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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/bootconf.h>
31 #include <sys/reboot.h>
32 #include <sys/param.h>
33 #include <sys/salib.h>
34 #include <sys/debug.h>
35 #include <sys/promif.h>
36 #include <sys/boot.h>
37 #include <sys/sysmacros.h>
38 #include <util/getoptstr.h>
39 #include "boot_plat.h"
40 
41 static char impl_arch_buf[MAXNAMELEN];
42 static char default_path_buf[MAXPATHLEN];
43 
44 char	wanboot_arguments[OBP_MAXPATHLEN];	/* args following "-o" */
45 
46 /*
47  * Parse the boot arguments, adding the options found to the existing boothowto
48  * value (if any) or other state.  Then rewrite the buffer with arguments for
49  * the standalone.
50  *
51  * We assume that the buffer contains only the arguments (no preceeding
52  * filename or whitespace).  We start interpreting flags, ignoring those used
53  * by the boot block (-H, -X, and -F filename) and acting on those intended
54  * for us (those documented in boot(1M) as well as some undocumented), and
55  * stop at unknown flags.  Finally we reconstitute flags to be passed on to
56  * the standalone and the remaining arguments, excluding the first "--", to
57  * the beginning of the buffer, and return an integer representing our flags.
58  *
59  * NOTE: boothowto may already have bits set when this function is called
60  */
61 void
62 bootflags(char *args, size_t argsz)
63 {
64 	static char newargs[OBP_MAXPATHLEN];
65 	struct gos_params params;
66 	const char *cp;
67 	char *np;
68 	size_t npres;
69 	int c;
70 
71 	impl_arch_name = NULL;
72 	cmd_line_default_path = NULL;
73 
74 	params.gos_opts = "HXF:VnI:D:advhko:";
75 	params.gos_strp = args;
76 	getoptstr_init(&params);
77 	while ((c = getoptstr(&params)) != -1) {
78 		switch (c) {
79 		/*
80 		 * Bootblock flags: ignore.
81 		 */
82 		case 'H':
83 		case 'X':
84 		case 'F':
85 			break;
86 
87 		/*
88 		 * Boot flags.
89 		 */
90 		case 'V':
91 			verbosemode = 1;
92 			break;
93 		case 'n':
94 			cache_state = 0;
95 			printf("Warning: boot will not enable cache\n");
96 			break;
97 
98 		case 'I':
99 			if (params.gos_optarglen >= sizeof (impl_arch_buf)) {
100 				printf("boot: -I argument too long.  "
101 				    "Ignoring.\n");
102 				break;
103 			}
104 			(void) strncpy(impl_arch_buf, params.gos_optargp,
105 			    params.gos_optarglen);
106 			impl_arch_buf[params.gos_optarglen] = '\0';
107 			impl_arch_name = impl_arch_buf;
108 			break;
109 
110 		case 'D':
111 			if (params.gos_optarglen >= sizeof (default_path_buf)) {
112 				printf("boot: -D argument too long.  "
113 				    "Ignoring.\n");
114 				break;
115 			}
116 			(void) strncpy(default_path_buf, params.gos_optargp,
117 			    params.gos_optarglen);
118 			default_path_buf[params.gos_optarglen] = '\0';
119 			cmd_line_default_path = default_path_buf;
120 			break;
121 
122 		case 'o':
123 			if (params.gos_optarglen >=
124 			    sizeof (wanboot_arguments)) {
125 				printf("boot: -o argument too long.  "
126 				    "Ignoring.\n");
127 				break;
128 			}
129 			(void) strncpy(wanboot_arguments, params.gos_optargp,
130 			    params.gos_optarglen);
131 			wanboot_arguments[params.gos_optarglen] = '\0';
132 			break;
133 
134 		case 'a':
135 			boothowto |= RB_ASKNAME;
136 			break;
137 
138 		case 'd':
139 			boothowto |= RB_DEBUGENTER;
140 			break;
141 		case 'v':
142 			boothowto |= RB_VERBOSE;
143 			break;
144 		case 'h':
145 			boothowto |= RB_HALT;
146 			break;
147 
148 		/* Consumed by the kernel */
149 		case 'k':
150 			boothowto |= RB_KMDB;
151 			break;
152 
153 		/*
154 		 * Unrecognized flags: stop.
155 		 */
156 		case '?':
157 			/*
158 			 * Error.  Either an unrecognized option, or an option
159 			 * without an argument.  Check for the latter.
160 			 */
161 			switch (params.gos_last_opt) {
162 			case 'F':
163 				/* -F is a bootblock flag, so ignore. */
164 				break;
165 			case 'I':
166 			case 'D':
167 			case 'o':
168 				printf("boot: -%c flag missing required "
169 				    "argument.  Ignoring.\n",
170 				    params.gos_last_opt);
171 				break;
172 			default:
173 				/* Unrecognized option.  Stop. */
174 				goto done;
175 			}
176 			break;
177 
178 		default:
179 			printf("boot: Ignoring unimplemented option -%c.\n", c);
180 		}
181 	}
182 done:
183 
184 	/*
185 	 * Construct the arguments for the standalone.
186 	 */
187 
188 	*newargs = '\0';
189 	np = newargs;
190 
191 	/*
192 	 * We need a dash if we encountered an unrecognized option or if we
193 	 * need to pass flags on.
194 	 */
195 	if (c == '?' || (boothowto &
196 	    /* These flags are to be passed to the standalone. */
197 	    (RB_ASKNAME | RB_DEBUGENTER | RB_VERBOSE | RB_HALT | RB_KMDB))) {
198 		*np++ = '-';
199 
200 		/*
201 		 * boot(1M) says to pass these on.
202 		 */
203 		if (boothowto & RB_ASKNAME)
204 			*np++ = 'a';
205 
206 		/*
207 		 * boot isn't documented as consuming these flags, so pass
208 		 * them on.
209 		 */
210 		if (boothowto & RB_DEBUGENTER)
211 			*np++ = 'd';
212 		if (boothowto & RB_KMDB)
213 			*np++ = 'k';
214 		if (boothowto & RB_VERBOSE)
215 			*np++ = 'v';
216 		if (boothowto & RB_HALT)
217 			*np++ = 'h';
218 
219 		/*
220 		 * If we didn't encounter an unrecognized flag and there's
221 		 * more to copy, add a space to separate these flags.
222 		 * (Otherwise, unrecognized flags can be appended since we
223 		 * started this word with a dash.)
224 		 */
225 		if (c == -1 && params.gos_strp[0] != '\0')
226 			*np++ = ' ';
227 	}
228 
229 	npres = sizeof (newargs) - (size_t)(np - newargs);
230 
231 	if (c == '?') {
232 		/*
233 		 * Unrecognized flag: Copy gos_errp to end of line or a "--"
234 		 * word.
235 		 */
236 		cp = params.gos_errp;
237 		while (*cp && npres > 0) {
238 			if (cp[0] == '-' && cp[1] == '-' &&
239 			    (cp[2] == '\0' || ISSPACE(cp[2]))) {
240 				cp += 2;
241 				SKIP_SPC(cp);
242 				break;
243 			} else {
244 				const char *sp = cp;
245 				size_t sz;
246 
247 				/* Copy until the next word. */
248 				while (*cp && !ISSPACE(*cp))
249 					cp++;
250 				while (ISSPACE(*cp))
251 					cp++;
252 
253 				sz = MIN(npres, (size_t)(cp - sp));
254 				npres -= sz;
255 				bcopy(sp, np, sz);
256 				np += sz;
257 			}
258 		}
259 	} else {
260 		cp = params.gos_strp;
261 	}
262 
263 	while (npres > 0 && (*np++ = *cp++) != '\0')
264 		npres--;
265 
266 	newargs[sizeof (newargs) - 1] = '\0';
267 	(void) strlcpy(args, newargs, argsz);
268 
269 	/*
270 	 * If a default filename was specified in the args, set it.
271 	 */
272 	if (cmd_line_default_path)
273 		set_default_filename(cmd_line_default_path);
274 }
275