diff options
Diffstat (limited to 'sys/lib/libsa')
| -rw-r--r-- | sys/lib/libsa/Makefile | 4 | ||||
| -rw-r--r-- | sys/lib/libsa/bootcfg.c | 292 | ||||
| -rw-r--r-- | sys/lib/libsa/bootcfg.h | 56 |
3 files changed, 351 insertions, 1 deletions
diff --git a/sys/lib/libsa/Makefile b/sys/lib/libsa/Makefile index 90e20823e18..16dacf6d960 100644 --- a/sys/lib/libsa/Makefile +++ b/sys/lib/libsa/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.82 2014/06/14 20:49:37 mrg Exp $ +# $NetBSD: Makefile,v 1.83 2014/06/28 09:16:18 rtr Exp $ LIB= sa LIBISPRIVATE?= yes @@ -28,6 +28,8 @@ SRCS+= alloc.c errno.c exit.c files.c \ panic.c printf.c qsort.c snprintf.c strerror.c \ subr_prf.c twiddle.c checkpasswd.c +SRCS+= bootcfg.c + # string routines .if ${MACHINE_ARCH} != "i386" && ${MACHINE_ARCH} != "x86_64" SRCS+= memcmp.c memcpy.c memmove.c memset.c strchr.c diff --git a/sys/lib/libsa/bootcfg.c b/sys/lib/libsa/bootcfg.c new file mode 100644 index 00000000000..d5a1d226526 --- /dev/null +++ b/sys/lib/libsa/bootcfg.c @@ -0,0 +1,292 @@ +/* $NetBSD: bootcfg.c,v 1.1 2014/06/28 09:16:18 rtr Exp $ */ + +/*- + * Copyright (c) 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/reboot.h> + +#include <lib/libsa/stand.h> +#include <lib/libsa/bootcfg.h> +#include <lib/libkern/libkern.h> + +static int atoi(const char *); + +#define isnum(c) ((c) >= '0' && (c) <= '9') + +#define MENUFORMAT_AUTO 0 +#define MENUFORMAT_NUMBER 1 +#define MENUFORMAT_LETTER 2 + +#define DEFAULT_FORMAT MENUFORMAT_AUTO +#define DEFAULT_TIMEOUT 10 + +struct bootcfg_def bootcfg_info; + +int +atoi(const char *in) +{ + char *c; + int ret; + + ret = 0; + c = (char *)in; + if (*c == '-') + c++; + for (; isnum(*c); c++) + ret = (ret * 10) + (*c - '0'); + + return (*in == '-') ? -ret : ret; +} + +void +bootcfg_do_noop(const char *cmd, char *arg) +{ + /* noop, do nothing */ +} + +/* + * This function parses a boot.cfg file in the root of the filesystem + * (if present) and populates the global boot configuration. + * + * The file consists of a number of lines each terminated by \n + * The lines are in the format keyword=value. There should not be spaces + * around the = sign. + * + * perform_bootcfg(conf, command, maxsz) + * + * conf Path to boot.cfg to be passed verbatim to open() + * + * command Pointer to a function that will be called when + * perform_bootcfg() encounters a key (command) it does not + * recognize. + * The command function is provided both the keyword and + * value parsed as arguments to the function. + * + * maxsz Limit the size of the boot.cfg perform_bootcfg() will parse. + * - If maxsz is < 0 boot.cfg will not be processed. + * - If maxsz is = 0 no limit will be imposed but parsing may + * fail due to platform or other constraints e.g. maximum + * segment size. + * - If 0 < maxsz and boot.cfg exceeds maxsz it will not be + * parsed, otherwise it will be parsed. + * + * The recognised keywords are: + * banner: text displayed instead of the normal welcome text + * menu: Descriptive text:command to use + * timeout: Timeout in seconds (overrides that set by installboot) + * default: the default menu option to use if Return is pressed + * consdev: the console device to use + * format: how menu choices are displayed: (a)utomatic, (n)umbers or (l)etters + * clear: whether to clear the screen or not + * + * Example boot.cfg file: + * banner=Welcome to NetBSD + * banner=Please choose the boot type from the following menu + * menu=Boot NetBSD:boot netbsd + * menu=Boot into single user mode:boot netbsd -s + * menu=:boot hd1a:netbsd -cs + * menu=Goto boot comand line:prompt + * timeout=10 + * consdev=com0 + * default=1 +*/ +void +perform_bootcfg(const char *conf, bootcfg_command command, const off_t maxsz) +{ + char *bc, *c; + int cmenu, cbanner, len; + int fd, err, off; + struct stat st; + char *next, *key, *value, *v2; + + /* clear bootcfg structure */ + memset(&bootcfg_info, 0, sizeof(bootcfg_info)); + + /* set default timeout */ + bootcfg_info.timeout = DEFAULT_TIMEOUT; + + /* automatically switch between letter and numbers on menu */ + bootcfg_info.menuformat = DEFAULT_FORMAT; + + fd = open(conf, 0); + if (fd < 0) + return; + + err = fstat(fd, &st); + if (err == -1) { + close(fd); + return; + } + + /* if a maximum size is being requested for the boot.cfg enforce it. */ + if (0 < maxsz && st.st_size > maxsz) { + close(fd); + return; + } + + bc = alloc(st.st_size + 1); + if (bc == NULL) { + printf("Could not allocate memory for boot configuration\n"); + close(fd); + return; + } + + /* + * XXX original code, assumes error or eof return from read() + * results in the entire boot.cfg being buffered. + * - should bail out on read() failing. + * - assumption is made that the file size doesn't change between + * fstat() and read()ing. probably safe in this context + * arguably should check that reading the file won't overflow + * the storage anyway. + */ + off = 0; + do { + len = read(fd, bc + off, 1024); + if (len <= 0) + break; + off += len; + } while (len > 0); + bc[off] = '\0'; + + close(fd); + + /* bc is now assumed to contain the whole boot.cfg file (see above) */ + + cmenu = 0; + cbanner = 0; + for (c = bc; *c; c = next) { + key = c; + /* find end of line */ + for (; *c && *c != '\n'; c++) + /* zero terminate line on start of comment */ + if (*c == '#') + *c = 0; + /* zero terminate line */ + if (*(next = c)) + *next++ = 0; + /* Look for = separator between key and value */ + for (c = key; *c && *c != '='; c++) + continue; + /* Ignore lines with no key=value pair */ + if (*c == '\0') + continue; + + /* zero terminate key which points to keyword */ + *c++ = 0; + value = c; + /* Look for end of line (or file) and zero terminate value */ + for (; *c && *c != '\n'; c++) + continue; + *c = 0; + + if (!strncmp(key, "menu", 4)) { + /* + * Parse "menu=<description>:<command>". If the + * description is empty ("menu=:<command>)", + * then re-use the command as the description. + * Note that the command may contain embedded + * colons. + */ + if (cmenu >= BOOTCFG_MAXMENU) + continue; + bootcfg_info.desc[cmenu] = value; + for (v2 = value; *v2 && *v2 != ':'; v2++) + continue; + if (*v2) { + *v2++ = 0; + bootcfg_info.command[cmenu] = v2; + if (! *value) + bootcfg_info.desc[cmenu] = v2; + cmenu++; + } else { + /* No delimiter means invalid line */ + bootcfg_info.desc[cmenu] = NULL; + } + } else if (!strncmp(key, "banner", 6)) { + if (cbanner < BOOTCFG_MAXBANNER) + bootcfg_info.banner[cbanner++] = value; + } else if (!strncmp(key, "timeout", 7)) { + if (!isnum(*value)) + bootcfg_info.timeout = -1; + else + bootcfg_info.timeout = atoi(value); + } else if (!strncmp(key, "default", 7)) { + bootcfg_info.def = atoi(value) - 1; + } else if (!strncmp(key, "consdev", 7)) { + bootcfg_info.consdev = value; + } else if (!strncmp(key, BOOTCFG_CMD_LOAD, 4)) { + command(BOOTCFG_CMD_LOAD, value); + } else if (!strncmp(key, "format", 6)) { + printf("value:%c\n", *value); + switch (*value) { + case 'a': + case 'A': + bootcfg_info.menuformat = MENUFORMAT_AUTO; + break; + + case 'n': + case 'N': + case 'd': + case 'D': + bootcfg_info.menuformat = MENUFORMAT_NUMBER; + break; + + case 'l': + case 'L': + bootcfg_info.menuformat = MENUFORMAT_LETTER; + break; + } + } else if (!strncmp(key, "clear", 5)) { + bootcfg_info.clear = !!atoi(value); + } else if (!strncmp(key, BOOTCFG_CMD_USERCONF, 8)) { + command(BOOTCFG_CMD_USERCONF, value); + } else { + command(key, value); + } + } + + switch (bootcfg_info.menuformat) { + case MENUFORMAT_AUTO: + if (cmenu > 9 && bootcfg_info.timeout > 0) + bootcfg_info.menuformat = MENUFORMAT_LETTER; + else + bootcfg_info.menuformat = MENUFORMAT_NUMBER; + break; + + case MENUFORMAT_NUMBER: + if (cmenu > 9 && bootcfg_info.timeout > 0) + cmenu = 9; + break; + } + + bootcfg_info.nummenu = cmenu; + if (bootcfg_info.def < 0) + bootcfg_info.def = 0; + if (bootcfg_info.def >= cmenu) + bootcfg_info.def = cmenu - 1; +} diff --git a/sys/lib/libsa/bootcfg.h b/sys/lib/libsa/bootcfg.h new file mode 100644 index 00000000000..f072c33be17 --- /dev/null +++ b/sys/lib/libsa/bootcfg.h @@ -0,0 +1,56 @@ +/* $NetBSD: bootcfg.h,v 1.1 2014/06/28 09:16:18 rtr Exp $ */ + +/*- + * Copyright (c) 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _BOOTCFG_H +#define _BOOTCFG_H + +#define BOOTCFG_FILENAME "boot.cfg" +#define BOOTCFG_MAXMENU 20 +#define BOOTCFG_MAXBANNER 12 + +#define BOOTCFG_CMD_LOAD "load" +#define BOOTCFG_CMD_USERCONF "userconf" + +typedef void (*bootcfg_command)(const char *cmd, char *arg); + +struct bootcfg_def { + char *banner[BOOTCFG_MAXBANNER]; /* Banner text */ + char *command[BOOTCFG_MAXMENU]; /* Menu commands per entry*/ + char *consdev; /* Console device */ + int def; /* Default menu option */ + char *desc[BOOTCFG_MAXMENU]; /* Menu text per entry */ + int nummenu; /* Number of menu items */ + int timeout; /* Timeout in seconds */ + int menuformat; /* Letters instead of numbers */ + int clear; /* Clear the screen? */ +} extern bootcfg_info; + +void perform_bootcfg(const char *, bootcfg_command, const off_t); +void bootcfg_do_noop(const char *, char *); + +#endif /* !_BOOTCFG_H */ |
