diff options
Diffstat (limited to 'usr.sbin/config/mkoptions.cc')
| -rw-r--r-- | usr.sbin/config/mkoptions.cc | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/usr.sbin/config/mkoptions.cc b/usr.sbin/config/mkoptions.cc new file mode 100644 index 000000000000..3b5ed17e455c --- /dev/null +++ b/usr.sbin/config/mkoptions.cc @@ -0,0 +1,460 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1995 Peter Wemm + * Copyright (c) 1980, 1993 + * The Regents of the University of California. 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +/* + * Make all the .h files for the optional entries + */ + +#include <ctype.h> +#include <err.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/param.h> +#include "config.h" +#include "y.tab.h" + +static struct users { + int u_default; + int u_min; + int u_max; +} users = { 8, 2, 512 }; + +static char *lower(char *); +static void read_options(void); +static void do_option(char *); +static char *tooption(char *); + +void +options(void) +{ + char buf[40]; + struct cputype *cp; + struct opt_list *ol; + struct opt *op; + + /* Fake the cpu types as options. */ + SLIST_FOREACH(cp, &cputype, cpu_next) { + op = (struct opt *)calloc(1, sizeof(*op)); + if (op == NULL) + err(EXIT_FAILURE, "calloc"); + op->op_name = ns(cp->cpu_name); + SLIST_INSERT_HEAD(&opt, op, op_next); + } + + if (maxusers == 0) { + if (verbose) + fprintf(stderr, + "maxusers not specified; will auto-size\n"); + } else if (maxusers < users.u_min) { + fprintf(stderr, "minimum of %d maxusers assumed\n", + users.u_min); + maxusers = users.u_min; + } else if (maxusers > users.u_max) + fprintf(stderr, "warning: maxusers > %d (%d)\n", + users.u_max, maxusers); + + /* Fake MAXUSERS as an option. */ + op = (struct opt *)calloc(1, sizeof(*op)); + if (op == NULL) + err(EXIT_FAILURE, "calloc"); + op->op_name = ns("MAXUSERS"); + snprintf(buf, sizeof(buf), "%d", maxusers); + op->op_value = ns(buf); + SLIST_INSERT_HEAD(&opt, op, op_next); + + read_options(); + + /* Fake the value of MACHINE_ARCH as an option if necessary */ + SLIST_FOREACH(ol, &otab, o_next) { + if (strcasecmp(ol->o_name, machinearch) != 0) + continue; + + op = (struct opt *)calloc(1, sizeof(*op)); + if (op == NULL) + err(EXIT_FAILURE, "calloc"); + op->op_name = ns(ol->o_name); + SLIST_INSERT_HEAD(&opt, op, op_next); + break; + } + + SLIST_FOREACH(op, &opt, op_next) { + SLIST_FOREACH(ol, &otab, o_next) { + if (eq(op->op_name, ol->o_name) && + (ol->o_flags & OL_ALIAS)) { + fprintf(stderr, "Mapping option %s to %s.\n", + op->op_name, ol->o_file); + op->op_name = ol->o_file; + break; + } + } + } + SLIST_FOREACH(ol, &otab, o_next) + do_option(ol->o_name); + SLIST_FOREACH(op, &opt, op_next) { + if (!op->op_ownfile && strncmp(op->op_name, "DEV_", 4)) { + fprintf(stderr, "%s: unknown option \"%s\"\n", + PREFIX, op->op_name); + exit(1); + } + } +} + +/* + * Generate an <options>.h file + */ + +static void +do_option(char *name) +{ + char *file; + const char *basefile; + struct opt_list *ol; + struct opt *op; + struct opt_head op_head; + FILE *inf, *outf; + char *value; + char *oldvalue; + int seen; + int tidy; + + file = tooption(name); + /* + * Check to see if the option was specified.. + */ + value = NULL; + SLIST_FOREACH(op, &opt, op_next) { + if (eq(name, op->op_name)) { + oldvalue = value; + value = op->op_value; + if (value == NULL) + value = ns("1"); + if (oldvalue != NULL && !eq(value, oldvalue)) + fprintf(stderr, + "%s: option \"%s\" redefined from %s to %s\n", + PREFIX, op->op_name, oldvalue, + value); + op->op_ownfile++; + } + } + + remember(file); + inf = fopen(file, "r"); + if (inf == NULL) { + outf = fopen(file, "w"); + if (outf == NULL) + err(1, "%s", file); + + /* was the option in the config file? */ + if (value) { + fprintf(outf, "#define %s %s\n", name, value); + } /* else empty file */ + + (void)fclose(outf); + return; + } + basefile = ""; + SLIST_FOREACH(ol, &otab, o_next) + if (eq(name, ol->o_name)) { + basefile = ol->o_file; + break; + } + oldvalue = NULL; + SLIST_INIT(&op_head); + seen = 0; + tidy = 0; + for (;;) { + configword cp, inw; + char *invalue; + + /* get the #define */ + if ((inw = get_word(inf)).eol() || inw.eof()) + break; + /* get the option name */ + if ((inw = get_word(inf)).eol() || inw.eof()) + break; + /* get the option value */ + if ((cp = get_word(inf)).eol() || cp.eof()) + break; + /* option value */ + invalue = ns(cp); /* malloced */ + if (eq(inw, name)) { + oldvalue = invalue; + invalue = value; + seen++; + } + SLIST_FOREACH(ol, &otab, o_next) + if (eq(inw, ol->o_name)) + break; + if (!eq(inw, name) && !ol) { + fprintf(stderr, + "WARNING: unknown option `%s' removed from %s\n", + inw->c_str(), file); + tidy++; + } else if (ol != NULL && !eq(basefile, ol->o_file)) { + fprintf(stderr, + "WARNING: option `%s' moved from %s to %s\n", + inw->c_str(), basefile, ol->o_file); + tidy++; + } else { + op = (struct opt *) calloc(1, sizeof *op); + if (op == NULL) + err(EXIT_FAILURE, "calloc"); + op->op_name = ns(inw); + op->op_value = invalue; + SLIST_INSERT_HEAD(&op_head, op, op_next); + } + + /* EOL? */ + cp = get_word(inf); + if (cp.eof()) + break; + } + (void)fclose(inf); + if (!tidy && ((value == NULL && oldvalue == NULL) || + (value && oldvalue && eq(value, oldvalue)))) { + while (!SLIST_EMPTY(&op_head)) { + op = SLIST_FIRST(&op_head); + SLIST_REMOVE_HEAD(&op_head, op_next); + free(op->op_name); + free(op->op_value); + free(op); + } + return; + } + + if (value && !seen) { + /* New option appears */ + op = (struct opt *) calloc(1, sizeof *op); + if (op == NULL) + err(EXIT_FAILURE, "calloc"); + op->op_name = ns(name); + op->op_value = ns(value); + SLIST_INSERT_HEAD(&op_head, op, op_next); + } + + outf = fopen(file, "w"); + if (outf == NULL) + err(1, "%s", file); + while (!SLIST_EMPTY(&op_head)) { + op = SLIST_FIRST(&op_head); + /* was the option in the config file? */ + if (op->op_value) { + fprintf(outf, "#define %s %s\n", + op->op_name, op->op_value); + } + SLIST_REMOVE_HEAD(&op_head, op_next); + free(op->op_name); + free(op->op_value); + free(op); + } + (void)fclose(outf); +} + +/* + * Find the filename to store the option spec into. + */ +static char * +tooption(char *name) +{ + static char hbuf[MAXPATHLEN]; + char nbuf[MAXPATHLEN]; + struct opt_list *po; + char *fpath; + + /* "cannot happen"? the otab list should be complete.. */ + (void)strlcpy(nbuf, "options.h", sizeof(nbuf)); + + SLIST_FOREACH(po, &otab, o_next) { + if (eq(po->o_name, name)) { + strlcpy(nbuf, po->o_file, sizeof(nbuf)); + break; + } + } + + fpath = path(nbuf); + (void)strlcpy(hbuf, fpath, sizeof(hbuf)); + free(fpath); + return (hbuf); +} + + +static void +check_duplicate(const char *fname, const char *chkopt) +{ + struct opt_list *po; + + SLIST_FOREACH(po, &otab, o_next) { + if (eq(po->o_name, chkopt)) { + fprintf(stderr, "%s: Duplicate option %s.\n", + fname, chkopt); + exit(1); + } + } +} + +static void +insert_option(const char *fname, char *optname, char *val) +{ + struct opt_list *po; + + check_duplicate(fname, optname); + po = (struct opt_list *) calloc(1, sizeof *po); + if (po == NULL) + err(EXIT_FAILURE, "calloc"); + po->o_name = optname; + po->o_file = val; + po->o_flags = 0; + SLIST_INSERT_HEAD(&otab, po, o_next); +} + +static void +update_option(const char *optname, char *val, int flags) +{ + struct opt_list *po; + + SLIST_FOREACH(po, &otab, o_next) { + if (eq(po->o_name, optname)) { + free(po->o_file); + po->o_file = val; + po->o_flags = flags; + return; + } + } + /* + * Option not found, but that's OK, we just ignore it since it + * may be for another arch. + */ + return; +} + +static int +read_option_file(const char *fname, int flags) +{ + FILE *fp; + configword wd; + char *optname, *val; + char genopt[MAXPATHLEN]; + + fp = fopen(fname, "r"); + if (fp == NULL) { + if (verbose) { + getcwd(genopt, sizeof(genopt)); + fprintf(stderr, "Unable to open options file: %s\n", + fname); + fprintf(stderr, "CWD: %s\n", genopt); + } + return (0); + } + while (!(wd = get_word(fp)).eof()) { + if (wd.eol()) + continue; + if (wd[0] == '#') { + while (!(wd = get_word(fp)).eof() && !wd.eol()) + continue; + continue; + } + optname = ns(wd); + wd = get_word(fp); + if (wd.eof()) { + free(optname); + break; + } + if (wd.eol()) { + if (flags) { + fprintf(stderr, "%s: compat file requires two" + " words per line at %s\n", fname, optname); + exit(1); + } + char *s = ns(optname); + (void)snprintf(genopt, sizeof(genopt), "opt_%s.h", + lower(s)); + val = ns(genopt); + free(s); + } else { + val = ns(wd); + } + + if (flags == 0) { + /* + * insert_option takes possession of `optname` in the + * new option instead of making yet another copy. + */ + insert_option(fname, optname, val); + } else { + update_option(optname, val, flags); + free(optname); + optname = NULL; + } + } + (void)fclose(fp); + return (1); +} + +/* + * read the options and options.<machine> files + */ +static void +read_options(void) +{ + char fname[MAXPATHLEN]; + struct files_name *nl, *tnl; + + SLIST_INIT(&otab); + read_option_file("../../conf/options", 0); + (void)snprintf(fname, sizeof fname, "../../conf/options.%s", + machinename); + if (!read_option_file(fname, 0)) { + (void)snprintf(fname, sizeof fname, "options.%s", machinename); + read_option_file(fname, 0); + } + for (nl = STAILQ_FIRST(&optfntab); nl != NULL; nl = tnl) { + read_option_file(nl->f_name, 0); + tnl = STAILQ_NEXT(nl, f_next); + free(nl->f_name); + free(nl); + } + read_option_file("../../conf/options-compat", OL_ALIAS); +} + +static char * +lower(char *str) +{ + char *cp = str; + + while (*str) { + if (isupper(*str)) + *str = tolower(*str); + str++; + } + return (cp); +} |
