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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/bootconf.h>
28 #include <sys/reboot.h>
29 #include <sys/param.h>
30 #include <sys/salib.h>
31 #include <sys/debug.h>
32 #include <sys/promif.h>
33 #include <sys/boot.h>
34 #include <sys/sysmacros.h>
35 #include <util/getoptstr.h>
36 #include "boot_plat.h"
37 
38 static char default_path_buf[MAXPATHLEN];
39 
40 char	cmd_line_boot_archive[MAXPATHLEN];
41 
42 boolean_t	halt;
43 
44 /*
45  * Parse the boot arguments, adding the options found to the existing boothowto
46  * value (if any) or other state.  Then rewrite the buffer with arguments for
47  * the standalone.
48  *
49  * NOTE: boothowto may already have bits set when this function is called
50  */
51 void
bootflags(char * args,size_t argsz)52 bootflags(char *args, size_t argsz)
53 {
54 	static char newargs[OBP_MAXPATHLEN];
55 	struct gos_params params;
56 	const char *cp;
57 	char *np;
58 	size_t npres;
59 	int c;
60 	char *cmd_line_default_path;
61 
62 	cmd_line_default_path = NULL;
63 
64 	params.gos_opts = "HXF:VnI:D:advhko:";
65 	params.gos_strp = args;
66 	getoptstr_init(&params);
67 	while ((c = getoptstr(&params)) != -1) {
68 		switch (c) {
69 		/*
70 		 * Bootblock flags.
71 		 */
72 		case 'H':
73 			halt = B_TRUE;
74 			/*FALLTHRU*/
75 		case 'X':
76 			break;
77 
78 		case 'F':
79 			if (params.gos_optarglen >=
80 			    sizeof (cmd_line_boot_archive)) {
81 				printf("boot: -F argument too long.  "
82 				    "Ignoring.\n");
83 				break;
84 			}
85 			(void) strncpy(cmd_line_boot_archive,
86 			    params.gos_optargp, params.gos_optarglen);
87 			cmd_line_boot_archive[params.gos_optarglen] = '\0';
88 			break;
89 
90 		/*
91 		 * Boot flags.
92 		 */
93 		case 'V':
94 			verbosemode = 1;
95 			break;
96 		case 'n':
97 			cache_state = 0;
98 			printf("Warning: boot will not enable cache\n");
99 			break;
100 
101 		case 'D':
102 			if (params.gos_optarglen >= sizeof (default_path_buf)) {
103 				printf("boot: -D argument too long.  "
104 				    "Ignoring.\n");
105 				break;
106 			}
107 			(void) strncpy(default_path_buf, params.gos_optargp,
108 			    params.gos_optarglen);
109 			default_path_buf[params.gos_optarglen] = '\0';
110 			cmd_line_default_path = default_path_buf;
111 			break;
112 
113 		case 'a':
114 			boothowto |= RB_ASKNAME;
115 			break;
116 
117 		case 'd':
118 			boothowto |= RB_DEBUGENTER;
119 			break;
120 		case 'v':
121 			boothowto |= RB_VERBOSE;
122 			break;
123 		case 'h':
124 			boothowto |= RB_HALT;
125 			break;
126 
127 		/* Consumed by the kernel */
128 		case 'k':
129 			boothowto |= RB_KMDB;
130 			break;
131 
132 		/*
133 		 * Unrecognized flags: stop.
134 		 */
135 		case '?':
136 			/*
137 			 * Error.  Either an unrecognized option, or an option
138 			 * without an argument.  Check for the latter.
139 			 */
140 			switch (params.gos_last_opt) {
141 			case 'F':
142 			case 'I':
143 			case 'D':
144 				printf("boot: -%c flag missing required "
145 				    "argument.  Ignoring.\n",
146 				    params.gos_last_opt);
147 				break;
148 			default:
149 				/* Unrecognized option.  Stop. */
150 				goto done;
151 			}
152 			break;
153 
154 		default:
155 			printf("boot: Ignoring unimplemented option -%c.\n", c);
156 		}
157 	}
158 done:
159 
160 	/*
161 	 * Construct the arguments for the standalone.
162 	 */
163 
164 	*newargs = '\0';
165 	np = newargs;
166 
167 	/*
168 	 * We need a dash if we encountered an unrecognized option or if we
169 	 * need to pass flags on.
170 	 */
171 	if (c == '?' || (boothowto &
172 	    /* These flags are to be passed to the standalone. */
173 	    (RB_ASKNAME | RB_DEBUGENTER | RB_VERBOSE | RB_HALT | RB_KMDB))) {
174 		*np++ = '-';
175 
176 		/*
177 		 * boot(8) says to pass these on.
178 		 */
179 		if (boothowto & RB_ASKNAME)
180 			*np++ = 'a';
181 
182 		/*
183 		 * boot isn't documented as consuming these flags, so pass
184 		 * them on.
185 		 */
186 		if (boothowto & RB_DEBUGENTER)
187 			*np++ = 'd';
188 		if (boothowto & RB_KMDB)
189 			*np++ = 'k';
190 		if (boothowto & RB_VERBOSE)
191 			*np++ = 'v';
192 		if (boothowto & RB_HALT)
193 			*np++ = 'h';
194 
195 		/*
196 		 * If we didn't encounter an unrecognized flag and there's
197 		 * more to copy, add a space to separate these flags.
198 		 * (Otherwise, unrecognized flags can be appended since we
199 		 * started this word with a dash.)
200 		 */
201 		if (c == -1 && params.gos_strp[0] != '\0')
202 			*np++ = ' ';
203 	}
204 
205 	npres = sizeof (newargs) - (size_t)(np - newargs);
206 
207 	if (c == '?') {
208 		/*
209 		 * Unrecognized flag: Copy gos_errp to end of line or a "--"
210 		 * word.
211 		 */
212 		cp = params.gos_errp;
213 		while (*cp && npres > 0) {
214 			if (cp[0] == '-' && cp[1] == '-' &&
215 			    (cp[2] == '\0' || ISSPACE(cp[2]))) {
216 				cp += 2;
217 				SKIP_SPC(cp);
218 				break;
219 			} else {
220 				const char *sp = cp;
221 				size_t sz;
222 
223 				/* Copy until the next word. */
224 				while (*cp && !ISSPACE(*cp))
225 					cp++;
226 				while (ISSPACE(*cp))
227 					cp++;
228 
229 				sz = MIN(npres, (size_t)(cp - sp));
230 				npres -= sz;
231 				bcopy(sp, np, sz);
232 				np += sz;
233 			}
234 		}
235 	} else {
236 		cp = params.gos_strp;
237 	}
238 
239 	while (npres > 0 && (*np++ = *cp++) != '\0')
240 		npres--;
241 
242 	newargs[sizeof (newargs) - 1] = '\0';
243 	(void) strlcpy(args, newargs, argsz);
244 
245 	/*
246 	 * If a default filename was specified in the args, set it.
247 	 */
248 	if (cmd_line_default_path)
249 		set_default_filename(cmd_line_default_path);
250 
251 	/*
252 	 * See if user wants to examine things
253 	 */
254 	if (halt == B_TRUE)
255 		prom_enter_mon();
256 }
257