152379d36SWarner Losh /*- 252379d36SWarner Losh * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 352379d36SWarner Losh * 452379d36SWarner Losh * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 552379d36SWarner Losh * All Rights Reserved. 652379d36SWarner Losh * Copyright (c) 1998 Robert Nordier 752379d36SWarner Losh * All Rights Reserved. 852379d36SWarner Losh * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 952379d36SWarner Losh * All rights reserved. 1052379d36SWarner Losh * Copyright (c) 2014 Roger Pau Monné <roger.pau@citrix.com> 1152379d36SWarner Losh * All Rights Reserved. 1252379d36SWarner Losh * Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org> 1352467047SWarner Losh * Copyright (c) 2018 Netflix, Inc. 1452379d36SWarner Losh * 1552379d36SWarner Losh * Redistribution and use in source and binary forms, with or without 1652379d36SWarner Losh * modification, are permitted provided that the following conditions 1752379d36SWarner Losh * are met: 1852379d36SWarner Losh * 1. Redistributions of source code must retain the above copyright 1952379d36SWarner Losh * notice, this list of conditions and the following disclaimer 2052379d36SWarner Losh * in this position and unchanged. 2152379d36SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 2252379d36SWarner Losh * notice, this list of conditions and the following disclaimer in the 2352379d36SWarner Losh * documentation and/or other materials provided with the distribution. 2452379d36SWarner Losh * 2552379d36SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2652379d36SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2752379d36SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2852379d36SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2952379d36SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3052379d36SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3152379d36SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3252379d36SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3352379d36SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3452379d36SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3552379d36SWarner Losh * SUCH DAMAGE. 3652379d36SWarner Losh */ 3752379d36SWarner Losh 3852379d36SWarner Losh #include <sys/cdefs.h> 3952379d36SWarner Losh __FBSDID("$FreeBSD$"); 4052379d36SWarner Losh 4152379d36SWarner Losh /* Note: This is compiled in both the kernel and boot loader contexts */ 4252379d36SWarner Losh 4352379d36SWarner Losh #include <sys/param.h> 4452379d36SWarner Losh #ifdef _KERNEL 4552379d36SWarner Losh #include <sys/systm.h> 4652379d36SWarner Losh #else 4752379d36SWarner Losh #include <stand.h> 4852379d36SWarner Losh #endif 4952379d36SWarner Losh #include <sys/reboot.h> 5052379d36SWarner Losh #include <sys/boot.h> 5152379d36SWarner Losh 5252379d36SWarner Losh #ifdef _KERNEL 5352379d36SWarner Losh #define SETENV(k, v) kern_setenv(k, v) 5452379d36SWarner Losh #define GETENV(k) kern_getenv(k) 5552379d36SWarner Losh #define FREE(v) freeenv(v) 5652379d36SWarner Losh #else /* Boot loader */ 5752379d36SWarner Losh #define SETENV(k, v) setenv(k, v, 1) 5852379d36SWarner Losh #define GETENV(k) getenv(k) 5952379d36SWarner Losh #define FREE(v) 6052379d36SWarner Losh #endif 6152379d36SWarner Losh 6252379d36SWarner Losh static struct 6352379d36SWarner Losh { 6452379d36SWarner Losh const char *ev; 6552379d36SWarner Losh int mask; 6652379d36SWarner Losh } howto_names[] = { 6752379d36SWarner Losh { "boot_askname", RB_ASKNAME}, 6852379d36SWarner Losh { "boot_cdrom", RB_CDROM}, 6952379d36SWarner Losh { "boot_ddb", RB_KDB}, 7052379d36SWarner Losh { "boot_dfltroot", RB_DFLTROOT}, 7152379d36SWarner Losh { "boot_gdb", RB_GDB}, 7252379d36SWarner Losh { "boot_multicons", RB_MULTIPLE}, 7352379d36SWarner Losh { "boot_mute", RB_MUTE}, 7452379d36SWarner Losh { "boot_pause", RB_PAUSE}, 7552379d36SWarner Losh { "boot_serial", RB_SERIAL}, 7652379d36SWarner Losh { "boot_single", RB_SINGLE}, 7752379d36SWarner Losh { "boot_verbose", RB_VERBOSE}, 7852379d36SWarner Losh { NULL, 0} 7952379d36SWarner Losh }; 8052379d36SWarner Losh 8152379d36SWarner Losh /* 8252379d36SWarner Losh * In the boot environment, we often parse a command line and have to throw away 8352379d36SWarner Losh * its contents. As we do so, we set environment variables that correspond to 8452379d36SWarner Losh * the flags we encounter. Later, to get a howto mask, we grovel through these 8552379d36SWarner Losh * to reconstruct it. This also allows users in their loader.conf to set them 8652379d36SWarner Losh * and have the kernel see them. 8752379d36SWarner Losh */ 8852379d36SWarner Losh 8952379d36SWarner Losh /** 9052379d36SWarner Losh * @brief convert the env vars in howto_names into a howto mask 9152379d36SWarner Losh */ 9252379d36SWarner Losh int 9352379d36SWarner Losh boot_env_to_howto(void) 9452379d36SWarner Losh { 9552379d36SWarner Losh int i, howto; 9652379d36SWarner Losh char *val; 9752379d36SWarner Losh 9852379d36SWarner Losh for (howto = 0, i = 0; howto_names[i].ev != NULL; i++) { 9952379d36SWarner Losh val = GETENV(howto_names[i].ev); 10052379d36SWarner Losh if (val != NULL && strcasecmp(val, "no") != 0) 10152379d36SWarner Losh howto |= howto_names[i].mask; 10252379d36SWarner Losh FREE(val); 10352379d36SWarner Losh } 10452379d36SWarner Losh return (howto); 10552379d36SWarner Losh } 10652379d36SWarner Losh 10752379d36SWarner Losh /** 10852379d36SWarner Losh * @brief Set env vars from howto_names based on howto passed in 10952379d36SWarner Losh */ 11052379d36SWarner Losh void 11152379d36SWarner Losh boot_howto_to_env(int howto) 11252379d36SWarner Losh { 11352379d36SWarner Losh int i; 11452379d36SWarner Losh 11552379d36SWarner Losh for (i = 0; howto_names[i].ev != NULL; i++) 11652379d36SWarner Losh if (howto & howto_names[i].mask) 11752379d36SWarner Losh SETENV(howto_names[i].ev, "YES"); 11852379d36SWarner Losh } 11952379d36SWarner Losh 12052379d36SWarner Losh /** 12152379d36SWarner Losh * @brief Helper routine to parse a single arg and return its mask 12252379d36SWarner Losh * 12352379d36SWarner Losh * Parse all the - options to create a mask (or a serial speed in the 12452379d36SWarner Losh * case of -S). If the arg doesn't start with '-' assume it's an env 12552379d36SWarner Losh * variable and set that instead. 12652379d36SWarner Losh */ 12752379d36SWarner Losh int 12852379d36SWarner Losh boot_parse_arg(char *v) 12952379d36SWarner Losh { 13052379d36SWarner Losh char *n; 13152379d36SWarner Losh int howto; 13252379d36SWarner Losh 13352379d36SWarner Losh #if 0 13452379d36SWarner Losh /* Need to see if this is better or worse than the meat of the #else */ 13552379d36SWarner Losh static const char howto_switches[] = "aCdrgDmphsv"; 13652379d36SWarner Losh static int howto_masks[] = { 13752379d36SWarner Losh RB_ASKNAME, RB_CDROM, RB_KDB, RB_DFLTROOT, RB_GDB, RB_MULTIPLE, 13852379d36SWarner Losh RB_MUTE, RB_PAUSE, RB_SERIAL, RB_SINGLE, RB_VERBOSE 13952379d36SWarner Losh }; 14052379d36SWarner Losh 14152379d36SWarner Losh opts = strchr(kargs, '-'); 14252379d36SWarner Losh while (opts != NULL) { 14352379d36SWarner Losh while (*(++opts) != '\0') { 14452379d36SWarner Losh sw = strchr(howto_switches, *opts); 14552379d36SWarner Losh if (sw == NULL) 14652379d36SWarner Losh break; 14752379d36SWarner Losh howto |= howto_masks[sw - howto_switches]; 14852379d36SWarner Losh } 14952379d36SWarner Losh opts = strchr(opts, '-'); 15052379d36SWarner Losh } 15152379d36SWarner Losh #else 15252379d36SWarner Losh howto = 0; 15352379d36SWarner Losh if (*v == '-') { 15452379d36SWarner Losh while (*v != '\0') { 15552379d36SWarner Losh v++; 15652379d36SWarner Losh switch (*v) { 15752379d36SWarner Losh case 'a': howto |= RB_ASKNAME; break; 15852379d36SWarner Losh case 'C': howto |= RB_CDROM; break; 15952379d36SWarner Losh case 'd': howto |= RB_KDB; break; 16052379d36SWarner Losh case 'D': howto |= RB_MULTIPLE; break; 16152379d36SWarner Losh case 'm': howto |= RB_MUTE; break; 16252379d36SWarner Losh case 'g': howto |= RB_GDB; break; 16352379d36SWarner Losh case 'h': howto |= RB_SERIAL; break; 16452379d36SWarner Losh case 'p': howto |= RB_PAUSE; break; 16552379d36SWarner Losh case 'P': howto |= RB_PROBE; break; 16652379d36SWarner Losh case 'r': howto |= RB_DFLTROOT; break; 16752379d36SWarner Losh case 's': howto |= RB_SINGLE; break; 16852379d36SWarner Losh case 'S': SETENV("comconsole_speed", v + 1); v += strlen(v); break; 16952379d36SWarner Losh case 'v': howto |= RB_VERBOSE; break; 17052379d36SWarner Losh } 17152379d36SWarner Losh } 17252379d36SWarner Losh } else { 17352379d36SWarner Losh n = strsep(&v, "="); 17452379d36SWarner Losh if (v == NULL) 17552379d36SWarner Losh SETENV(n, "1"); 17652379d36SWarner Losh else 17752379d36SWarner Losh SETENV(n, v); 17852379d36SWarner Losh } 17952379d36SWarner Losh #endif 18052379d36SWarner Losh return (howto); 18152379d36SWarner Losh } 18252379d36SWarner Losh 18352379d36SWarner Losh /** 18452379d36SWarner Losh * @brief breakup the command line into args, and pass to boot_parse_arg 18552379d36SWarner Losh */ 18652379d36SWarner Losh int 18752379d36SWarner Losh boot_parse_cmdline_delim(char *cmdline, const char *delim) 18852379d36SWarner Losh { 18952379d36SWarner Losh char *v; 19052379d36SWarner Losh int howto; 19152379d36SWarner Losh 19252379d36SWarner Losh howto = 0; 19352379d36SWarner Losh while ((v = strsep(&cmdline, delim)) != NULL) { 19452379d36SWarner Losh if (*v == '\0') 19552379d36SWarner Losh continue; 19652379d36SWarner Losh howto |= boot_parse_arg(v); 19752379d36SWarner Losh } 19852379d36SWarner Losh return (howto); 19952379d36SWarner Losh } 20052379d36SWarner Losh 20152379d36SWarner Losh /** 202*2834e42cSWarner Losh * @brief Simplified interface for common 'space or tab separated' args 20352379d36SWarner Losh */ 20452379d36SWarner Losh int 20552379d36SWarner Losh boot_parse_cmdline(char *cmdline) 20652379d36SWarner Losh { 20752379d36SWarner Losh 208*2834e42cSWarner Losh return (boot_parse_cmdline_delim(cmdline, " \t\n")); 20952379d36SWarner Losh } 21052379d36SWarner Losh 21152379d36SWarner Losh /** 21252379d36SWarner Losh * @brief Pass a vector of strings to boot_parse_arg 21352379d36SWarner Losh */ 21452379d36SWarner Losh int 21552379d36SWarner Losh boot_parse_args(int argc, char *argv[]) 21652379d36SWarner Losh { 21752379d36SWarner Losh int i, howto; 21852379d36SWarner Losh 21952379d36SWarner Losh howto = 0; 22052379d36SWarner Losh for (i = 1; i < argc; i++) 22152379d36SWarner Losh howto |= boot_parse_arg(argv[i]); 22252379d36SWarner Losh return (howto); 22352379d36SWarner Losh } 224