mkoptions.c revision 330897
1/*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1995 Peter Wemm 5 * Copyright (c) 1980, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#ifndef lint 34#if 0 35static char sccsid[] = "@(#)mkheaders.c 8.1 (Berkeley) 6/6/93"; 36#endif 37static const char rcsid[] = 38 "$FreeBSD: stable/11/usr.sbin/config/mkoptions.c 330897 2018-03-14 03:19:51Z eadler $"; 39#endif /* not lint */ 40 41/* 42 * Make all the .h files for the optional entries 43 */ 44 45#include <ctype.h> 46#include <err.h> 47#include <stdio.h> 48#include <string.h> 49#include <sys/param.h> 50#include "config.h" 51#include "y.tab.h" 52 53static struct users { 54 int u_default; 55 int u_min; 56 int u_max; 57} users = { 8, 2, 512 }; 58 59static char *lower(char *); 60static void read_options(void); 61static void do_option(char *); 62static char *tooption(char *); 63 64void 65options(void) 66{ 67 char buf[40]; 68 struct cputype *cp; 69 struct opt_list *ol; 70 struct opt *op; 71 72 /* Fake the cpu types as options. */ 73 SLIST_FOREACH(cp, &cputype, cpu_next) { 74 op = (struct opt *)calloc(1, sizeof(*op)); 75 if (op == NULL) 76 err(EXIT_FAILURE, "calloc"); 77 op->op_name = ns(cp->cpu_name); 78 SLIST_INSERT_HEAD(&opt, op, op_next); 79 } 80 81 if (maxusers == 0) { 82 /* fprintf(stderr, "maxusers not specified; will auto-size\n"); */ 83 } else if (maxusers < users.u_min) { 84 fprintf(stderr, "minimum of %d maxusers assumed\n", 85 users.u_min); 86 maxusers = users.u_min; 87 } else if (maxusers > users.u_max) 88 fprintf(stderr, "warning: maxusers > %d (%d)\n", 89 users.u_max, maxusers); 90 91 /* Fake MAXUSERS as an option. */ 92 op = (struct opt *)calloc(1, sizeof(*op)); 93 if (op == NULL) 94 err(EXIT_FAILURE, "calloc"); 95 op->op_name = ns("MAXUSERS"); 96 snprintf(buf, sizeof(buf), "%d", maxusers); 97 op->op_value = ns(buf); 98 SLIST_INSERT_HEAD(&opt, op, op_next); 99 100 read_options(); 101 102 /* Fake the value of MACHINE_ARCH as an option if necessary */ 103 SLIST_FOREACH(ol, &otab, o_next) { 104 if (strcasecmp(ol->o_name, machinearch) != 0) 105 continue; 106 107 op = (struct opt *)calloc(1, sizeof(*op)); 108 if (op == NULL) 109 err(EXIT_FAILURE, "calloc"); 110 op->op_name = ns(ol->o_name); 111 SLIST_INSERT_HEAD(&opt, op, op_next); 112 break; 113 } 114 115 SLIST_FOREACH(op, &opt, op_next) { 116 SLIST_FOREACH(ol, &otab, o_next) { 117 if (eq(op->op_name, ol->o_name) && 118 (ol->o_flags & OL_ALIAS)) { 119 fprintf(stderr, "Mapping option %s to %s.\n", 120 op->op_name, ol->o_file); 121 op->op_name = ol->o_file; 122 break; 123 } 124 } 125 } 126 SLIST_FOREACH(ol, &otab, o_next) 127 do_option(ol->o_name); 128 SLIST_FOREACH(op, &opt, op_next) { 129 if (!op->op_ownfile && strncmp(op->op_name, "DEV_", 4)) { 130 fprintf(stderr, "%s: unknown option \"%s\"\n", 131 PREFIX, op->op_name); 132 exit(1); 133 } 134 } 135} 136 137/* 138 * Generate an <options>.h file 139 */ 140 141static void 142do_option(char *name) 143{ 144 char *file, *inw; 145 const char *basefile; 146 struct opt_list *ol; 147 struct opt *op; 148 struct opt_head op_head; 149 FILE *inf, *outf; 150 char *value; 151 char *oldvalue; 152 int seen; 153 int tidy; 154 155 file = tooption(name); 156 /* 157 * Check to see if the option was specified.. 158 */ 159 value = NULL; 160 SLIST_FOREACH(op, &opt, op_next) { 161 if (eq(name, op->op_name)) { 162 oldvalue = value; 163 value = op->op_value; 164 if (value == NULL) 165 value = ns("1"); 166 if (oldvalue != NULL && !eq(value, oldvalue)) 167 fprintf(stderr, 168 "%s: option \"%s\" redefined from %s to %s\n", 169 PREFIX, op->op_name, oldvalue, 170 value); 171 op->op_ownfile++; 172 } 173 } 174 175 remember(file); 176 inf = fopen(file, "r"); 177 if (inf == NULL) { 178 outf = fopen(file, "w"); 179 if (outf == NULL) 180 err(1, "%s", file); 181 182 /* was the option in the config file? */ 183 if (value) { 184 fprintf(outf, "#define %s %s\n", name, value); 185 } /* else empty file */ 186 187 (void)fclose(outf); 188 return; 189 } 190 basefile = ""; 191 SLIST_FOREACH(ol, &otab, o_next) 192 if (eq(name, ol->o_name)) { 193 basefile = ol->o_file; 194 break; 195 } 196 oldvalue = NULL; 197 SLIST_INIT(&op_head); 198 seen = 0; 199 tidy = 0; 200 for (;;) { 201 char *cp; 202 char *invalue; 203 204 /* get the #define */ 205 if ((inw = get_word(inf)) == NULL || inw == (char *)EOF) 206 break; 207 /* get the option name */ 208 if ((inw = get_word(inf)) == NULL || inw == (char *)EOF) 209 break; 210 inw = ns(inw); 211 /* get the option value */ 212 if ((cp = get_word(inf)) == NULL || cp == (char *)EOF) 213 break; 214 /* option value */ 215 invalue = ns(cp); /* malloced */ 216 if (eq(inw, name)) { 217 oldvalue = invalue; 218 invalue = value; 219 seen++; 220 } 221 SLIST_FOREACH(ol, &otab, o_next) 222 if (eq(inw, ol->o_name)) 223 break; 224 if (!eq(inw, name) && !ol) { 225 fprintf(stderr, 226 "WARNING: unknown option `%s' removed from %s\n", 227 inw, file); 228 tidy++; 229 } else if (ol != NULL && !eq(basefile, ol->o_file)) { 230 fprintf(stderr, 231 "WARNING: option `%s' moved from %s to %s\n", 232 inw, basefile, ol->o_file); 233 tidy++; 234 } else { 235 op = (struct opt *) calloc(1, sizeof *op); 236 if (op == NULL) 237 err(EXIT_FAILURE, "calloc"); 238 op->op_name = inw; 239 op->op_value = invalue; 240 SLIST_INSERT_HEAD(&op_head, op, op_next); 241 } 242 243 /* EOL? */ 244 cp = get_word(inf); 245 if (cp == (char *)EOF) 246 break; 247 } 248 (void)fclose(inf); 249 if (!tidy && ((value == NULL && oldvalue == NULL) || 250 (value && oldvalue && eq(value, oldvalue)))) { 251 while (!SLIST_EMPTY(&op_head)) { 252 op = SLIST_FIRST(&op_head); 253 SLIST_REMOVE_HEAD(&op_head, op_next); 254 free(op->op_name); 255 free(op->op_value); 256 free(op); 257 } 258 return; 259 } 260 261 if (value && !seen) { 262 /* New option appears */ 263 op = (struct opt *) calloc(1, sizeof *op); 264 if (op == NULL) 265 err(EXIT_FAILURE, "calloc"); 266 op->op_name = ns(name); 267 op->op_value = value ? ns(value) : NULL; 268 SLIST_INSERT_HEAD(&op_head, op, op_next); 269 } 270 271 outf = fopen(file, "w"); 272 if (outf == NULL) 273 err(1, "%s", file); 274 while (!SLIST_EMPTY(&op_head)) { 275 op = SLIST_FIRST(&op_head); 276 /* was the option in the config file? */ 277 if (op->op_value) { 278 fprintf(outf, "#define %s %s\n", 279 op->op_name, op->op_value); 280 } 281 SLIST_REMOVE_HEAD(&op_head, op_next); 282 free(op->op_name); 283 free(op->op_value); 284 free(op); 285 } 286 (void)fclose(outf); 287} 288 289/* 290 * Find the filename to store the option spec into. 291 */ 292static char * 293tooption(char *name) 294{ 295 static char hbuf[MAXPATHLEN]; 296 char nbuf[MAXPATHLEN]; 297 struct opt_list *po; 298 299 /* "cannot happen"? the otab list should be complete.. */ 300 (void)strlcpy(nbuf, "options.h", sizeof(nbuf)); 301 302 SLIST_FOREACH(po, &otab, o_next) { 303 if (eq(po->o_name, name)) { 304 strlcpy(nbuf, po->o_file, sizeof(nbuf)); 305 break; 306 } 307 } 308 309 (void)strlcpy(hbuf, path(nbuf), sizeof(hbuf)); 310 return (hbuf); 311} 312 313 314static void 315check_duplicate(const char *fname, const char *this) 316{ 317 struct opt_list *po; 318 319 SLIST_FOREACH(po, &otab, o_next) { 320 if (eq(po->o_name, this)) { 321 fprintf(stderr, "%s: Duplicate option %s.\n", 322 fname, this); 323 exit(1); 324 } 325 } 326} 327 328static void 329insert_option(const char *fname, char *this, char *val) 330{ 331 struct opt_list *po; 332 333 check_duplicate(fname, this); 334 po = (struct opt_list *) calloc(1, sizeof *po); 335 if (po == NULL) 336 err(EXIT_FAILURE, "calloc"); 337 po->o_name = this; 338 po->o_file = val; 339 po->o_flags = 0; 340 SLIST_INSERT_HEAD(&otab, po, o_next); 341} 342 343static void 344update_option(const char *this, char *val, int flags) 345{ 346 struct opt_list *po; 347 348 SLIST_FOREACH(po, &otab, o_next) { 349 if (eq(po->o_name, this)) { 350 free(po->o_file); 351 po->o_file = val; 352 po->o_flags = flags; 353 return; 354 } 355 } 356 /* 357 * Option not found, but that's OK, we just ignore it since it 358 * may be for another arch. 359 */ 360 return; 361} 362 363static int 364read_option_file(const char *fname, int flags) 365{ 366 FILE *fp; 367 char *wd, *this, *val; 368 char genopt[MAXPATHLEN]; 369 370 fp = fopen(fname, "r"); 371 if (fp == NULL) 372 return (0); 373 while ((wd = get_word(fp)) != (char *)EOF) { 374 if (wd == NULL) 375 continue; 376 if (wd[0] == '#') { 377 while (((wd = get_word(fp)) != (char *)EOF) && wd) 378 continue; 379 continue; 380 } 381 this = ns(wd); 382 val = get_word(fp); 383 if (val == (char *)EOF) 384 return (1); 385 if (val == NULL) { 386 if (flags) { 387 fprintf(stderr, "%s: compat file requires two" 388 " words per line at %s\n", fname, this); 389 exit(1); 390 } 391 char *s = ns(this); 392 (void)snprintf(genopt, sizeof(genopt), "opt_%s.h", 393 lower(s)); 394 val = genopt; 395 free(s); 396 } 397 val = ns(val); 398 if (flags == 0) 399 insert_option(fname, this, val); 400 else 401 update_option(this, val, flags); 402 } 403 (void)fclose(fp); 404 return (1); 405} 406 407/* 408 * read the options and options.<machine> files 409 */ 410static void 411read_options(void) 412{ 413 char fname[MAXPATHLEN]; 414 415 SLIST_INIT(&otab); 416 read_option_file("../../conf/options", 0); 417 (void)snprintf(fname, sizeof fname, "../../conf/options.%s", 418 machinename); 419 if (!read_option_file(fname, 0)) { 420 (void)snprintf(fname, sizeof fname, "options.%s", machinename); 421 read_option_file(fname, 0); 422 } 423 read_option_file("../../conf/options-compat", OL_ALIAS); 424} 425 426static char * 427lower(char *str) 428{ 429 char *cp = str; 430 431 while (*str) { 432 if (isupper(*str)) 433 *str = tolower(*str); 434 str++; 435 } 436 return (cp); 437} 438