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          * Sparc only, _OBP isn't defined on x86 any more.
  65          */
  66         if (cp[0] != '-') {
  67                 /* if user booted kadb or kmdb, load kmdb */
  68                 if (cp[0] == 'k' && (cp[1] == 'a' || cp[1] == 'm') &&
  69                     cp[2] == 'd' && cp[3] == 'b' &&
  70                     (cp[4] == ' ' || cp[4] == ' ' || cp[4] == 0))
  71                         boothowto |= RB_KMDB;
  72                 SKIP_WORD(cp);          /* Skip the kernel's filename. */
  73         }
  74 #endif
  75         SKIP_SPC(cp);
  76 
  77 #if defined(_OBP)
  78         /* skip bootblk args */
  79         params.gos_opts = "abcdDf:F:gGHhi:km:o:O:rsvVwxZ:";
  80 #else
  81         params.gos_opts = "abcdgGhi:km:O:rsvwx";
  82 #endif
  83         params.gos_strp = cp;
  84         getoptstr_init(&params);
  85         while ((c = getoptstr(&params)) != -1) {
  86 
  87                 switch (c) {
  88                 case 'a':
  89                         boothowto |= RB_ASKNAME;
  90                         break;
  91                 case 'b':
  92                         boothowto |= RB_NOBOOTRC;
  93                         break;
  94                 case 'c':
  95                         boothowto |= RB_CONFIG;
  96                         break;
  97                 case 'd':
  98                         boothowto |= RB_DEBUGENTER;
  99                         break;
 100 #if defined(_OBP)
 101                 case 'D':
 102                 case 'F':
 103                         break;
 104                 case 'f':
 105                         (void) prom_setprop(prom_optionsnode(), "diag-level",
 106                             (char *)params.gos_optargp,
 107                             params.gos_optarglen + 1);
 108                         break;
 109 #endif
 110                 case 'g':
 111                         boothowto |= RB_FORTHDEBUG;
 112                         break;
 113                 case 'G':
 114                         boothowto |= RB_FORTHDEBUGDBP;
 115                         break;
 116                 case 'h':
 117                         boothowto |= RB_HALT;
 118                         break;
 119 #if defined(_OBP)
 120                 case 'H':
 121                         break;
 122 #endif
 123                 case 'i':
 124                         if (params.gos_optarglen + 1 > sizeof (initname)) {
 125                                 _kobj_printf(ops, "krtld: initname too long.  "
 126                                     "Ignoring.\n");
 127                         } else {
 128                                 (void) strncpy(initname, params.gos_optargp,
 129                                     params.gos_optarglen);
 130                                 initname[params.gos_optarglen] = '\0';
 131                         }
 132                         break;
 133                 case 'k':
 134                         boothowto |= RB_KMDB;
 135                         break;
 136                 case 'm':
 137                         if (strlen(initargs) + 3 + params.gos_optarglen + 1 >
 138                             sizeof (initargs)) {
 139                                 _kobj_printf(ops,
 140                                     "unix: init options too long.  "
 141                                     "Ignoring -m.\n");
 142                                 break;
 143                         }
 144                         /* gos_optargp is not null terminated */
 145                         (void) strncpy(scratch, params.gos_optargp,
 146                             params.gos_optarglen);
 147                         scratch[params.gos_optarglen] = '\0';
 148                         (void) strlcat(initargs, "-m ", sizeof (initargs));
 149                         (void) strlcat(initargs, scratch,
 150                             sizeof (initargs));
 151                         (void) strlcat(initargs, " ", sizeof (initargs));
 152                         break;
 153 #if defined(_OBP)
 154                 /* Ignore argument meant for wanboot standalone */
 155                 case 'o':
 156                         break;
 157 #endif
 158                 case 'O': {
 159                         char **str = &kobj_kmdb_argv[num_O_opt];
 160 
 161                         if (++num_O_opt > (sizeof (kobj_kmdb_argv) /
 162                             sizeof (char *)) - 1) {
 163                                 _kobj_printf(ops, "krtld: too many kmdb "
 164                                     "options - ignoring option #%d.\n",
 165                                     num_O_opt);
 166                                 continue;
 167                         }
 168 
 169                         *str = kobj_alloc(params.gos_optarglen + 1, KM_TMP);
 170                         (void) strncpy(*str, params.gos_optargp,
 171                             params.gos_optarglen);
 172                         (*str)[params.gos_optarglen] = '\0';
 173                         break;
 174                 }
 175                 case 'r':
 176                         if (strlen(initargs) + 3 + 1 > sizeof (initargs)) {
 177                                 _kobj_printf(ops, "unix: init options too "
 178                                     "long.  Ignoring -r.\n");
 179                                 break;
 180                         }
 181                         boothowto |= RB_RECONFIG;
 182                         (void) strlcat(initargs, "-r ", sizeof (initargs));
 183                         break;
 184                 case 's':
 185                         if (strlen(initargs) + 3 + 1 > sizeof (initargs)) {
 186                                 _kobj_printf(ops, "unix: init options too "
 187                                     "long.  Ignoring -s.\n");
 188                                 break;
 189                         }
 190                         boothowto |= RB_SINGLE;
 191                         (void) strlcat(initargs, "-s ", sizeof (initargs));
 192                         break;
 193                 case 'v':
 194                         if (strlen(initargs) + 3 + 1 > sizeof (initargs)) {
 195                                 _kobj_printf(ops, "unix: init options too "
 196                                     "long.  Ignoring -v.\n");
 197                                 break;
 198                         }
 199                         boothowto |= RB_VERBOSE;
 200                         (void) strlcat(initargs, "-v ", sizeof (initargs));
 201                         break;
 202 #if defined(_OBP)
 203                 case 'V':
 204                         break;
 205                 case 'Z':
 206                         break;
 207 #endif
 208                 case 'w':
 209                         boothowto |= RB_WRITABLE;
 210                         break;
 211                 case 'x':
 212                         boothowto |= RB_NOBOOTCLUSTER;
 213                         break;
 214                 case '?':
 215                         switch (params.gos_last_opt) {
 216                         case 'i':
 217                                 _kobj_printf(ops, "krtld: Required argument "
 218                                     "for -i flag missing.  Ignoring.\n");
 219                                 break;
 220                         default:
 221                                 _kobj_printf(ops, "krtld: Ignoring invalid "
 222                                     "kernel option -%c.\n",
 223                                     params.gos_last_opt);
 224                         }
 225                         break;
 226                 default:
 227                         _kobj_printf(ops, "krtld: Ignoring unimplemented "
 228                             "option -%c.\n", c);
 229                 }
 230         }
 231 
 232         if ((boothowto & (RB_DEBUGENTER | RB_KMDB)) == RB_DEBUGENTER) {
 233                 _kobj_printf(ops, "krtld: -d is not valid without -k.\n");
 234                 boothowto &= ~RB_DEBUGENTER;
 235         }
 236 
 237         if (*params.gos_strp) {
 238                 /* Unused arguments. */
 239                 if (params.gos_strp[0] == '-' && ISSPACE(params.gos_strp[1])) {
 240                         /*EMPTY*/
 241                         /* Lousy install arguments.  Silently ignore. */
 242                 } else {
 243                         _kobj_printf(ops, "krtld: Unused kernel arguments: "
 244                             "`%s'.\n", params.gos_strp);
 245                 }
 246         }
 247 }