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