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 }
251