xref: /freebsd/sys/kern/subr_boot.c (revision 52379d36a9bcfb7dbf73a581621b9ebb6d71f5c6)
1*52379d36SWarner Losh /*-
2*52379d36SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*52379d36SWarner Losh  *
4*52379d36SWarner Losh  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
5*52379d36SWarner Losh  * All Rights Reserved.
6*52379d36SWarner Losh  * Copyright (c) 1998 Robert Nordier
7*52379d36SWarner Losh  * All Rights Reserved.
8*52379d36SWarner Losh  * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
9*52379d36SWarner Losh  * All rights reserved.
10*52379d36SWarner Losh  * Copyright (c) 2014 Roger Pau Monné <roger.pau@citrix.com>
11*52379d36SWarner Losh  * All Rights Reserved.
12*52379d36SWarner Losh  * Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org>
13*52379d36SWarner Losh  * Copyright (c) 2018 Netflix
14*52379d36SWarner Losh  *
15*52379d36SWarner Losh  * Redistribution and use in source and binary forms, with or without
16*52379d36SWarner Losh  * modification, are permitted provided that the following conditions
17*52379d36SWarner Losh  * are met:
18*52379d36SWarner Losh  * 1. Redistributions of source code must retain the above copyright
19*52379d36SWarner Losh  *    notice, this list of conditions and the following disclaimer
20*52379d36SWarner Losh  *    in this position and unchanged.
21*52379d36SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
22*52379d36SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
23*52379d36SWarner Losh  *    documentation and/or other materials provided with the distribution.
24*52379d36SWarner Losh  *
25*52379d36SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
26*52379d36SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27*52379d36SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28*52379d36SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
29*52379d36SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30*52379d36SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31*52379d36SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32*52379d36SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33*52379d36SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34*52379d36SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35*52379d36SWarner Losh  * SUCH DAMAGE.
36*52379d36SWarner Losh  */
37*52379d36SWarner Losh 
38*52379d36SWarner Losh #include <sys/cdefs.h>
39*52379d36SWarner Losh __FBSDID("$FreeBSD$");
40*52379d36SWarner Losh 
41*52379d36SWarner Losh /* Note: This is compiled in both the kernel and boot loader contexts */
42*52379d36SWarner Losh 
43*52379d36SWarner Losh #include <sys/param.h>
44*52379d36SWarner Losh #ifdef _KERNEL
45*52379d36SWarner Losh #include <sys/systm.h>
46*52379d36SWarner Losh #else
47*52379d36SWarner Losh #include <stand.h>
48*52379d36SWarner Losh #endif
49*52379d36SWarner Losh #include <sys/reboot.h>
50*52379d36SWarner Losh #include <sys/boot.h>
51*52379d36SWarner Losh 
52*52379d36SWarner Losh #ifdef _KERNEL
53*52379d36SWarner Losh #define SETENV(k, v)	kern_setenv(k, v)
54*52379d36SWarner Losh #define GETENV(k)	kern_getenv(k)
55*52379d36SWarner Losh #define FREE(v)		freeenv(v)
56*52379d36SWarner Losh #else	/* Boot loader */
57*52379d36SWarner Losh #define SETENV(k, v)	setenv(k, v, 1)
58*52379d36SWarner Losh #define GETENV(k)	getenv(k)
59*52379d36SWarner Losh #define	FREE(v)
60*52379d36SWarner Losh #endif
61*52379d36SWarner Losh 
62*52379d36SWarner Losh static struct
63*52379d36SWarner Losh {
64*52379d36SWarner Losh 	const char	*ev;
65*52379d36SWarner Losh 	int		mask;
66*52379d36SWarner Losh } howto_names[] = {
67*52379d36SWarner Losh 	{ "boot_askname",	RB_ASKNAME},
68*52379d36SWarner Losh 	{ "boot_cdrom",		RB_CDROM},
69*52379d36SWarner Losh 	{ "boot_ddb",		RB_KDB},
70*52379d36SWarner Losh 	{ "boot_dfltroot",	RB_DFLTROOT},
71*52379d36SWarner Losh 	{ "boot_gdb",		RB_GDB},
72*52379d36SWarner Losh 	{ "boot_multicons",	RB_MULTIPLE},
73*52379d36SWarner Losh 	{ "boot_mute",		RB_MUTE},
74*52379d36SWarner Losh 	{ "boot_pause",		RB_PAUSE},
75*52379d36SWarner Losh 	{ "boot_serial",	RB_SERIAL},
76*52379d36SWarner Losh 	{ "boot_single",	RB_SINGLE},
77*52379d36SWarner Losh 	{ "boot_verbose",	RB_VERBOSE},
78*52379d36SWarner Losh 	{ NULL,	0}
79*52379d36SWarner Losh };
80*52379d36SWarner Losh 
81*52379d36SWarner Losh /*
82*52379d36SWarner Losh  * In the boot environment, we often parse a command line and have to throw away
83*52379d36SWarner Losh  * its contents. As we do so, we set environment variables that correspond to
84*52379d36SWarner Losh  * the flags we encounter. Later, to get a howto mask, we grovel through these
85*52379d36SWarner Losh  * to reconstruct it. This also allows users in their loader.conf to set them
86*52379d36SWarner Losh  * and have the kernel see them.
87*52379d36SWarner Losh  */
88*52379d36SWarner Losh 
89*52379d36SWarner Losh /**
90*52379d36SWarner Losh  * @brief convert the env vars in howto_names into a howto mask
91*52379d36SWarner Losh  */
92*52379d36SWarner Losh int
93*52379d36SWarner Losh boot_env_to_howto(void)
94*52379d36SWarner Losh {
95*52379d36SWarner Losh 	int i, howto;
96*52379d36SWarner Losh 	char *val;
97*52379d36SWarner Losh 
98*52379d36SWarner Losh 	for (howto = 0, i = 0; howto_names[i].ev != NULL; i++) {
99*52379d36SWarner Losh 		val = GETENV(howto_names[i].ev);
100*52379d36SWarner Losh 		if (val != NULL && strcasecmp(val, "no") != 0)
101*52379d36SWarner Losh 			howto |= howto_names[i].mask;
102*52379d36SWarner Losh 		FREE(val);
103*52379d36SWarner Losh 	}
104*52379d36SWarner Losh 	return (howto);
105*52379d36SWarner Losh }
106*52379d36SWarner Losh 
107*52379d36SWarner Losh /**
108*52379d36SWarner Losh  * @brief Set env vars from howto_names based on howto passed in
109*52379d36SWarner Losh  */
110*52379d36SWarner Losh void
111*52379d36SWarner Losh boot_howto_to_env(int howto)
112*52379d36SWarner Losh {
113*52379d36SWarner Losh 	int i;
114*52379d36SWarner Losh 
115*52379d36SWarner Losh 	for (i = 0; howto_names[i].ev != NULL; i++)
116*52379d36SWarner Losh 		if (howto & howto_names[i].mask)
117*52379d36SWarner Losh 			SETENV(howto_names[i].ev, "YES");
118*52379d36SWarner Losh }
119*52379d36SWarner Losh 
120*52379d36SWarner Losh /**
121*52379d36SWarner Losh  * @brief Helper routine to parse a single arg and return its mask
122*52379d36SWarner Losh  *
123*52379d36SWarner Losh  * Parse all the - options to create a mask (or a serial speed in the
124*52379d36SWarner Losh  * case of -S). If the arg doesn't start with '-' assume it's an env
125*52379d36SWarner Losh  * variable and set that instead.
126*52379d36SWarner Losh  */
127*52379d36SWarner Losh int
128*52379d36SWarner Losh boot_parse_arg(char *v)
129*52379d36SWarner Losh {
130*52379d36SWarner Losh 	char *n;
131*52379d36SWarner Losh 	int howto;
132*52379d36SWarner Losh 
133*52379d36SWarner Losh #if 0
134*52379d36SWarner Losh /* Need to see if this is better or worse than the meat of the #else */
135*52379d36SWarner Losh static const char howto_switches[] = "aCdrgDmphsv";
136*52379d36SWarner Losh static int howto_masks[] = {
137*52379d36SWarner Losh 	RB_ASKNAME, RB_CDROM, RB_KDB, RB_DFLTROOT, RB_GDB, RB_MULTIPLE,
138*52379d36SWarner Losh 	RB_MUTE, RB_PAUSE, RB_SERIAL, RB_SINGLE, RB_VERBOSE
139*52379d36SWarner Losh };
140*52379d36SWarner Losh 
141*52379d36SWarner Losh 	opts = strchr(kargs, '-');
142*52379d36SWarner Losh 	while (opts != NULL) {
143*52379d36SWarner Losh 		while (*(++opts) != '\0') {
144*52379d36SWarner Losh 			sw = strchr(howto_switches, *opts);
145*52379d36SWarner Losh 			if (sw == NULL)
146*52379d36SWarner Losh 				break;
147*52379d36SWarner Losh 			howto |= howto_masks[sw - howto_switches];
148*52379d36SWarner Losh 		}
149*52379d36SWarner Losh 		opts = strchr(opts, '-');
150*52379d36SWarner Losh 	}
151*52379d36SWarner Losh #else
152*52379d36SWarner Losh 	howto = 0;
153*52379d36SWarner Losh 	if (*v == '-') {
154*52379d36SWarner Losh 		while (*v != '\0') {
155*52379d36SWarner Losh 			v++;
156*52379d36SWarner Losh 			switch (*v) {
157*52379d36SWarner Losh 			case 'a': howto |= RB_ASKNAME; break;
158*52379d36SWarner Losh 			case 'C': howto |= RB_CDROM; break;
159*52379d36SWarner Losh 			case 'd': howto |= RB_KDB; break;
160*52379d36SWarner Losh 			case 'D': howto |= RB_MULTIPLE; break;
161*52379d36SWarner Losh 			case 'm': howto |= RB_MUTE; break;
162*52379d36SWarner Losh 			case 'g': howto |= RB_GDB; break;
163*52379d36SWarner Losh 			case 'h': howto |= RB_SERIAL; break;
164*52379d36SWarner Losh 			case 'p': howto |= RB_PAUSE; break;
165*52379d36SWarner Losh 			case 'P': howto |= RB_PROBE; break;
166*52379d36SWarner Losh 			case 'r': howto |= RB_DFLTROOT; break;
167*52379d36SWarner Losh 			case 's': howto |= RB_SINGLE; break;
168*52379d36SWarner Losh 			case 'S': SETENV("comconsole_speed", v + 1); v += strlen(v); break;
169*52379d36SWarner Losh 			case 'v': howto |= RB_VERBOSE; break;
170*52379d36SWarner Losh 			}
171*52379d36SWarner Losh 		}
172*52379d36SWarner Losh 	} else {
173*52379d36SWarner Losh 		n = strsep(&v, "=");
174*52379d36SWarner Losh 		if (v == NULL)
175*52379d36SWarner Losh 			SETENV(n, "1");
176*52379d36SWarner Losh 		else
177*52379d36SWarner Losh 			SETENV(n, v);
178*52379d36SWarner Losh 	}
179*52379d36SWarner Losh #endif
180*52379d36SWarner Losh 	return (howto);
181*52379d36SWarner Losh }
182*52379d36SWarner Losh 
183*52379d36SWarner Losh /**
184*52379d36SWarner Losh  * @brief breakup the command line into args, and pass to boot_parse_arg
185*52379d36SWarner Losh  */
186*52379d36SWarner Losh int
187*52379d36SWarner Losh boot_parse_cmdline_delim(char *cmdline, const char *delim)
188*52379d36SWarner Losh {
189*52379d36SWarner Losh 	char *v;
190*52379d36SWarner Losh 	int howto;
191*52379d36SWarner Losh 
192*52379d36SWarner Losh 	howto = 0;
193*52379d36SWarner Losh 	while ((v = strsep(&cmdline, delim)) != NULL) {
194*52379d36SWarner Losh 		if (*v == '\0')
195*52379d36SWarner Losh 			continue;
196*52379d36SWarner Losh 		howto |= boot_parse_arg(v);
197*52379d36SWarner Losh 	}
198*52379d36SWarner Losh 	return (howto);
199*52379d36SWarner Losh }
200*52379d36SWarner Losh 
201*52379d36SWarner Losh /**
202*52379d36SWarner Losh  * @brief Simplified interface for common 'space separated' args
203*52379d36SWarner Losh  */
204*52379d36SWarner Losh int
205*52379d36SWarner Losh boot_parse_cmdline(char *cmdline)
206*52379d36SWarner Losh {
207*52379d36SWarner Losh 
208*52379d36SWarner Losh 	return (boot_parse_cmdline_delim(cmdline, " \n"));
209*52379d36SWarner Losh }
210*52379d36SWarner Losh 
211*52379d36SWarner Losh /**
212*52379d36SWarner Losh  * @brief Pass a vector of strings to boot_parse_arg
213*52379d36SWarner Losh  */
214*52379d36SWarner Losh int
215*52379d36SWarner Losh boot_parse_args(int argc, char *argv[])
216*52379d36SWarner Losh {
217*52379d36SWarner Losh         int i, howto;
218*52379d36SWarner Losh 
219*52379d36SWarner Losh 	howto = 0;
220*52379d36SWarner Losh         for (i = 1; i < argc; i++)
221*52379d36SWarner Losh                 howto |= boot_parse_arg(argv[i]);
222*52379d36SWarner Losh 	return (howto);
223*52379d36SWarner Losh }
224