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
39char *kobj_kmdb_argv[11];	/* 10 arguments and trailing NULL */
40
41/*
42 * Parse the boot line to determine boot flags.
43 */
44void
45bootflags(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 legacy wanboot argument meant for 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}
248