1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 #include <sys/types.h>
  28 #include <sys/reboot.h>
  29 #include <sys/cmn_err.h>
  30 #include <sys/bootconf.h>
  31 #include <sys/promif.h>
  32 #include <sys/obpdefs.h>
  33 #include <sys/sunddi.h>
  34 #include <sys/systm.h>
  35 #include <sys/kobj.h>
  36 #include <sys/kobj_impl.h>
  37 #include <util/getoptstr.h>
  38 
  39 char *kobj_kmdb_argv[11];       /* 10 arguments and trailing NULL */
  40 
  41 /*
  42  * Parse the boot line to determine boot flags.
  43  */
  44 void
  45 bootflags(struct bootops *ops)
  46 {
  47         struct gos_params params;
  48         uchar_t num_O_opt = 0;
  49         char *cp;
  50         int c;
  51         char scratch[BOOTARGS_MAX];
  52 
  53         if (BOP_GETPROP(ops, "bootargs", kern_bootargs) == -1) {
  54                 boothowto |= RB_ASKNAME;
  55                 return;
  56         }
  57 
  58         (void) BOP_GETPROP(ops, "boot-file", kern_bootfile);
  59 
  60         cp = kern_bootargs;
  61 
  62 #if defined(_OBP)
  63         /*
  64          * x86: The boot scripts (i.e., /etc/bootrc) don't prepend the kernel
  65          * name to the boot arguments.  (And beware making it do so: if the
  66          * run-kernel command returns, it will loop, and you will end up with
  67          * multiple copies of the kernel name.)
  68          */
  69         if (cp[0] != '-') {
  70                 /* if user booted kadb or kmdb, load kmdb */
  71                 if (cp[0] == 'k' && (cp[1] == 'a' || cp[1] == 'm') &&
  72                     cp[2] == 'd' && cp[3] == 'b' &&
  73                     (cp[4] == ' ' || cp[4] == ' ' || cp[4] == 0))
  74                         boothowto |= RB_KMDB;
  75                 SKIP_WORD(cp);          /* Skip the kernel's filename. */
  76         }
  77 #endif
  78         SKIP_SPC(cp);
  79 
  80 #if defined(_OBP)
  81         /* skip bootblk args */
  82         params.gos_opts = "abcdDf:F:gGHhi:km:o:O:rsvVwxZ:";
  83 #else
  84         params.gos_opts = "abcdgGhi:km:O:rsvwx";
  85 #endif
  86         params.gos_strp = cp;
  87         getoptstr_init(&params);
  88         while ((c = getoptstr(&params)) != -1) {
  89 
  90                 switch (c) {
  91                 case 'a':
  92                         boothowto |= RB_ASKNAME;
  93                         break;
  94                 case 'b':
  95                         boothowto |= RB_NOBOOTRC;
  96                         break;
  97                 case 'c':
  98                         boothowto |= RB_CONFIG;
  99                         break;
 100                 case 'd':
 101                         boothowto |= RB_DEBUGENTER;
 102                         break;
 103 #if defined(_OBP)
 104                 case 'D':
 105                 case 'F':
 106                         break;
 107                 case 'f':
 108                         (void)prom_setprop(prom_optionsnode(), "diag-level",
 109                             (char *)params.gos_optargp,
 110                             params.gos_optarglen + 1);
 111                         break;
 112 #endif
 113                 case 'g':
 114                         boothowto |= RB_FORTHDEBUG;
 115                         break;
 116                 case 'G':
 117                         boothowto |= RB_FORTHDEBUGDBP;
 118                         break;
 119                 case 'h':
 120                         boothowto |= RB_HALT;
 121                         break;
 122 #if defined(_OBP)
 123                 case 'H':
 124                         break;
 125 #endif
 126                 case 'i':
 127                         if (params.gos_optarglen + 1 > sizeof (initname)) {
 128                                 _kobj_printf(ops, "krtld: initname too long.  "
 129                                     "Ignoring.\n");
 130                         } else {
 131                                 (void) strncpy(initname, params.gos_optargp,
 132                                     params.gos_optarglen);
 133                                 initname[params.gos_optarglen] = '\0';
 134                         }
 135                         break;
 136                 case 'k':
 137                         boothowto |= RB_KMDB;
 138                         break;
 139                 case 'm':
 140                         if (strlen(initargs) + 3 + params.gos_optarglen + 1 >
 141                             sizeof (initargs)) {
 142                                 _kobj_printf(ops,
 143                                     "unix: init options too long.  "
 144                                     "Ignoring -m.\n");
 145                                 break;
 146                         }
 147                         /* gos_optargp is not null terminated */
 148                         (void) strncpy(scratch, params.gos_optargp,
 149                             params.gos_optarglen);
 150                         scratch[params.gos_optarglen] = '\0';
 151                         (void) strlcat(initargs, "-m ", sizeof (initargs));
 152                         (void) strlcat(initargs, scratch,
 153                             sizeof (initargs));
 154                         (void) strlcat(initargs, " ", sizeof (initargs));
 155                         break;
 156 #if defined(_OBP)
 157                 /* Ignore argument meant for wanboot standalone */
 158                 case 'o':
 159                         break;
 160 #endif
 161                 case 'O': {
 162                         char **str = &kobj_kmdb_argv[num_O_opt];
 163 
 164                         if (++num_O_opt > (sizeof (kobj_kmdb_argv) /
 165                             sizeof (char *)) - 1) {
 166                                 _kobj_printf(ops, "krtld: too many kmdb "
 167                                     "options - ignoring option #%d.\n",
 168                                     num_O_opt);
 169                                 continue;
 170                         }
 171 
 172                         *str = kobj_alloc(params.gos_optarglen + 1, KM_TMP);
 173                         (void) strncpy(*str, params.gos_optargp,
 174                             params.gos_optarglen);
 175                         (*str)[params.gos_optarglen] = '\0';
 176                         break;
 177                 }
 178                 case 'r':
 179                         if (strlen(initargs) + 3 + 1 > sizeof (initargs)) {
 180                                 _kobj_printf(ops, "unix: init options too "
 181                                     "long.  Ignoring -r.\n");
 182                                 break;
 183                         }
 184                         boothowto |= RB_RECONFIG;
 185                         (void) strlcat(initargs, "-r ", sizeof (initargs));
 186                         break;
 187                 case 's':
 188                         if (strlen(initargs) + 3 + 1 > sizeof (initargs)) {
 189                                 _kobj_printf(ops, "unix: init options too "
 190                                     "long.  Ignoring -s.\n");
 191                                 break;
 192                         }
 193                         boothowto |= RB_SINGLE;
 194                         (void) strlcat(initargs, "-s ", sizeof (initargs));
 195                         break;
 196                 case 'v':
 197                         if (strlen(initargs) + 3 + 1 > sizeof (initargs)) {
 198                                 _kobj_printf(ops, "unix: init options too "
 199                                     "long.  Ignoring -v.\n");
 200                                 break;
 201                         }
 202                         boothowto |= RB_VERBOSE;
 203                         (void) strlcat(initargs, "-v ", sizeof (initargs));
 204                         break;
 205 #if defined(_OBP)
 206                 case 'V':
 207                         break;
 208                 case 'Z':
 209                         break;
 210 #endif
 211                 case 'w':
 212                         boothowto |= RB_WRITABLE;
 213                         break;
 214                 case 'x':
 215                         boothowto |= RB_NOBOOTCLUSTER;
 216                         break;
 217                 case '?':
 218                         switch (params.gos_last_opt) {
 219                         case 'i':
 220                                 _kobj_printf(ops, "krtld: Required argument "
 221                                     "for -i flag missing.  Ignoring.\n");
 222                                 break;
 223                         default:
 224                                 _kobj_printf(ops, "krtld: Ignoring invalid "
 225                                     "kernel option -%c.\n",
 226                                     params.gos_last_opt);
 227                         }
 228                         break;
 229                 default:
 230                         _kobj_printf(ops, "krtld: Ignoring unimplemented "
 231                             "option -%c.\n", c);
 232                 }
 233         }
 234 
 235         if ((boothowto & (RB_DEBUGENTER | RB_KMDB)) == RB_DEBUGENTER) {
 236                 _kobj_printf(ops, "krtld: -d is not valid without -k.\n");
 237                 boothowto &= ~RB_DEBUGENTER;
 238         }
 239 
 240         if (*params.gos_strp) {
 241                 /* Unused arguments. */
 242                 if (params.gos_strp[0] == '-' && ISSPACE(params.gos_strp[1])) {
 243                         /*EMPTY*/
 244                         /* Lousy install arguments.  Silently ignore. */
 245                 } else {
 246                         _kobj_printf(ops, "krtld: Unused kernel arguments: "
 247                             "`%s'.\n", params.gos_strp);
 248                 }
 249         }
 250 }