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