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 * 3. 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 /* 34 * Make all the .h files for the optional entries 35 */ 36 37 #include <ctype.h> 38 #include <err.h> 39 #include <stdio.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include <sys/param.h> 43 #include "config.h" 44 #include "y.tab.h" 45 46 static struct users { 47 int u_default; 48 int u_min; 49 int u_max; 50 } users = { 8, 2, 512 }; 51 52 static char *lower(char *); 53 static void read_options(void); 54 static void do_option(char *); 55 static char *tooption(char *); 56 57 void 58 options(void) 59 { 60 char buf[40]; 61 struct cputype *cp; 62 struct opt_list *ol; 63 struct opt *op; 64 65 /* Fake the cpu types as options. */ 66 SLIST_FOREACH(cp, &cputype, cpu_next) { 67 op = (struct opt *)calloc(1, sizeof(*op)); 68 if (op == NULL) 69 err(EXIT_FAILURE, "calloc"); 70 op->op_name = ns(cp->cpu_name); 71 SLIST_INSERT_HEAD(&opt, op, op_next); 72 } 73 74 if (maxusers == 0) { 75 if (verbose) 76 fprintf(stderr, 77 "maxusers not specified; will auto-size\n"); 78 } else if (maxusers < users.u_min) { 79 fprintf(stderr, "minimum of %d maxusers assumed\n", 80 users.u_min); 81 maxusers = users.u_min; 82 } else if (maxusers > users.u_max) 83 fprintf(stderr, "warning: maxusers > %d (%d)\n", 84 users.u_max, maxusers); 85 86 /* Fake MAXUSERS as an option. */ 87 op = (struct opt *)calloc(1, sizeof(*op)); 88 if (op == NULL) 89 err(EXIT_FAILURE, "calloc"); 90 op->op_name = ns("MAXUSERS"); 91 snprintf(buf, sizeof(buf), "%d", maxusers); 92 op->op_value = ns(buf); 93 SLIST_INSERT_HEAD(&opt, op, op_next); 94 95 read_options(); 96 97 /* Fake the value of MACHINE_ARCH as an option if necessary */ 98 SLIST_FOREACH(ol, &otab, o_next) { 99 if (strcasecmp(ol->o_name, machinearch) != 0) 100 continue; 101 102 op = (struct opt *)calloc(1, sizeof(*op)); 103 if (op == NULL) 104 err(EXIT_FAILURE, "calloc"); 105 op->op_name = ns(ol->o_name); 106 SLIST_INSERT_HEAD(&opt, op, op_next); 107 break; 108 } 109 110 SLIST_FOREACH(op, &opt, op_next) { 111 SLIST_FOREACH(ol, &otab, o_next) { 112 if (eq(op->op_name, ol->o_name) && 113 (ol->o_flags & OL_ALIAS)) { 114 fprintf(stderr, "Mapping option %s to %s.\n", 115 op->op_name, ol->o_file); 116 op->op_name = ol->o_file; 117 break; 118 } 119 } 120 } 121 SLIST_FOREACH(ol, &otab, o_next) 122 do_option(ol->o_name); 123 SLIST_FOREACH(op, &opt, op_next) { 124 if (!op->op_ownfile && strncmp(op->op_name, "DEV_", 4)) { 125 fprintf(stderr, "%s: unknown option \"%s\"\n", 126 PREFIX, op->op_name); 127 exit(1); 128 } 129 } 130 } 131 132 /* 133 * Generate an <options>.h file 134 */ 135 136 static void 137 do_option(char *name) 138 { 139 char *file; 140 const char *basefile; 141 struct opt_list *ol; 142 struct opt *op; 143 struct opt_head op_head; 144 FILE *inf, *outf; 145 char *value; 146 char *oldvalue; 147 int seen; 148 int tidy; 149 150 file = tooption(name); 151 /* 152 * Check to see if the option was specified.. 153 */ 154 value = NULL; 155 SLIST_FOREACH(op, &opt, op_next) { 156 if (eq(name, op->op_name)) { 157 oldvalue = value; 158 value = op->op_value; 159 if (value == NULL) 160 value = ns("1"); 161 if (oldvalue != NULL && !eq(value, oldvalue)) 162 fprintf(stderr, 163 "%s: option \"%s\" redefined from %s to %s\n", 164 PREFIX, op->op_name, oldvalue, 165 value); 166 op->op_ownfile++; 167 } 168 } 169 170 remember(file); 171 inf = fopen(file, "r"); 172 if (inf == NULL) { 173 outf = fopen(file, "w"); 174 if (outf == NULL) 175 err(1, "%s", file); 176 177 /* was the option in the config file? */ 178 if (value) { 179 fprintf(outf, "#define %s %s\n", name, value); 180 } /* else empty file */ 181 182 (void)fclose(outf); 183 return; 184 } 185 basefile = ""; 186 SLIST_FOREACH(ol, &otab, o_next) 187 if (eq(name, ol->o_name)) { 188 basefile = ol->o_file; 189 break; 190 } 191 oldvalue = NULL; 192 SLIST_INIT(&op_head); 193 seen = 0; 194 tidy = 0; 195 for (;;) { 196 configword cp, inw; 197 char *invalue; 198 199 /* get the #define */ 200 if ((inw = get_word(inf)).eol() || inw.eof()) 201 break; 202 /* get the option name */ 203 if ((inw = get_word(inf)).eol() || inw.eof()) 204 break; 205 /* get the option value */ 206 if ((cp = get_word(inf)).eol() || cp.eof()) 207 break; 208 /* option value */ 209 invalue = ns(cp); /* malloced */ 210 if (eq(inw, name)) { 211 oldvalue = invalue; 212 invalue = value; 213 seen++; 214 } 215 SLIST_FOREACH(ol, &otab, o_next) 216 if (eq(inw, ol->o_name)) 217 break; 218 if (!eq(inw, name) && !ol) { 219 fprintf(stderr, 220 "WARNING: unknown option `%s' removed from %s\n", 221 inw->c_str(), file); 222 tidy++; 223 } else if (ol != NULL && !eq(basefile, ol->o_file)) { 224 fprintf(stderr, 225 "WARNING: option `%s' moved from %s to %s\n", 226 inw->c_str(), basefile, ol->o_file); 227 tidy++; 228 } else { 229 op = (struct opt *) calloc(1, sizeof *op); 230 if (op == NULL) 231 err(EXIT_FAILURE, "calloc"); 232 op->op_name = ns(inw); 233 op->op_value = invalue; 234 SLIST_INSERT_HEAD(&op_head, op, op_next); 235 } 236 237 /* EOL? */ 238 cp = get_word(inf); 239 if (cp.eof()) 240 break; 241 } 242 (void)fclose(inf); 243 if (!tidy && ((value == NULL && oldvalue == NULL) || 244 (value && oldvalue && eq(value, oldvalue)))) { 245 while (!SLIST_EMPTY(&op_head)) { 246 op = SLIST_FIRST(&op_head); 247 SLIST_REMOVE_HEAD(&op_head, op_next); 248 free(op->op_name); 249 free(op->op_value); 250 free(op); 251 } 252 return; 253 } 254 255 if (value && !seen) { 256 /* New option appears */ 257 op = (struct opt *) calloc(1, sizeof *op); 258 if (op == NULL) 259 err(EXIT_FAILURE, "calloc"); 260 op->op_name = ns(name); 261 op->op_value = ns(value); 262 SLIST_INSERT_HEAD(&op_head, op, op_next); 263 } 264 265 outf = fopen(file, "w"); 266 if (outf == NULL) 267 err(1, "%s", file); 268 while (!SLIST_EMPTY(&op_head)) { 269 op = SLIST_FIRST(&op_head); 270 /* was the option in the config file? */ 271 if (op->op_value) { 272 fprintf(outf, "#define %s %s\n", 273 op->op_name, op->op_value); 274 } 275 SLIST_REMOVE_HEAD(&op_head, op_next); 276 free(op->op_name); 277 free(op->op_value); 278 free(op); 279 } 280 (void)fclose(outf); 281 } 282 283 /* 284 * Find the filename to store the option spec into. 285 */ 286 static char * 287 tooption(char *name) 288 { 289 static char hbuf[MAXPATHLEN]; 290 char nbuf[MAXPATHLEN]; 291 struct opt_list *po; 292 char *fpath; 293 294 /* "cannot happen"? the otab list should be complete.. */ 295 (void)strlcpy(nbuf, "options.h", sizeof(nbuf)); 296 297 SLIST_FOREACH(po, &otab, o_next) { 298 if (eq(po->o_name, name)) { 299 strlcpy(nbuf, po->o_file, sizeof(nbuf)); 300 break; 301 } 302 } 303 304 fpath = path(nbuf); 305 (void)strlcpy(hbuf, fpath, sizeof(hbuf)); 306 free(fpath); 307 return (hbuf); 308 } 309 310 311 static void 312 check_duplicate(const char *fname, const char *chkopt) 313 { 314 struct opt_list *po; 315 316 SLIST_FOREACH(po, &otab, o_next) { 317 if (eq(po->o_name, chkopt)) { 318 fprintf(stderr, "%s: Duplicate option %s.\n", 319 fname, chkopt); 320 exit(1); 321 } 322 } 323 } 324 325 static void 326 insert_option(const char *fname, char *optname, char *val) 327 { 328 struct opt_list *po; 329 330 check_duplicate(fname, optname); 331 po = (struct opt_list *) calloc(1, sizeof *po); 332 if (po == NULL) 333 err(EXIT_FAILURE, "calloc"); 334 po->o_name = optname; 335 po->o_file = val; 336 po->o_flags = 0; 337 SLIST_INSERT_HEAD(&otab, po, o_next); 338 } 339 340 static void 341 update_option(const char *optname, char *val, int flags) 342 { 343 struct opt_list *po; 344 345 SLIST_FOREACH(po, &otab, o_next) { 346 if (eq(po->o_name, optname)) { 347 free(po->o_file); 348 po->o_file = val; 349 po->o_flags = flags; 350 return; 351 } 352 } 353 /* 354 * Option not found, but that's OK, we just ignore it since it 355 * may be for another arch. 356 */ 357 return; 358 } 359 360 static int 361 read_option_file(const char *fname, int flags) 362 { 363 FILE *fp; 364 configword wd; 365 char *optname, *val; 366 char genopt[MAXPATHLEN]; 367 368 fp = fopen(fname, "r"); 369 if (fp == NULL) { 370 if (verbose) { 371 getcwd(genopt, sizeof(genopt)); 372 fprintf(stderr, "Unable to open options file: %s\n", 373 fname); 374 fprintf(stderr, "CWD: %s\n", genopt); 375 } 376 return (0); 377 } 378 while (!(wd = get_word(fp)).eof()) { 379 if (wd.eol()) 380 continue; 381 if (wd[0] == '#') { 382 while (!(wd = get_word(fp)).eof() && !wd.eol()) 383 continue; 384 continue; 385 } 386 optname = ns(wd); 387 wd = get_word(fp); 388 if (wd.eof()) { 389 free(optname); 390 break; 391 } 392 if (wd.eol()) { 393 if (flags) { 394 fprintf(stderr, "%s: compat file requires two" 395 " words per line at %s\n", fname, optname); 396 exit(1); 397 } 398 char *s = ns(optname); 399 (void)snprintf(genopt, sizeof(genopt), "opt_%s.h", 400 lower(s)); 401 val = ns(genopt); 402 free(s); 403 } else { 404 val = ns(wd); 405 } 406 407 if (flags == 0) { 408 /* 409 * insert_option takes possession of `optname` in the 410 * new option instead of making yet another copy. 411 */ 412 insert_option(fname, optname, val); 413 } else { 414 update_option(optname, val, flags); 415 free(optname); 416 optname = NULL; 417 } 418 } 419 (void)fclose(fp); 420 return (1); 421 } 422 423 /* 424 * read the options and options.<machine> files 425 */ 426 static void 427 read_options(void) 428 { 429 char fname[MAXPATHLEN]; 430 struct files_name *nl, *tnl; 431 432 SLIST_INIT(&otab); 433 read_option_file("../../conf/options", 0); 434 (void)snprintf(fname, sizeof fname, "../../conf/options.%s", 435 machinename); 436 if (!read_option_file(fname, 0)) { 437 (void)snprintf(fname, sizeof fname, "options.%s", machinename); 438 read_option_file(fname, 0); 439 } 440 for (nl = STAILQ_FIRST(&optfntab); nl != NULL; nl = tnl) { 441 read_option_file(nl->f_name, 0); 442 tnl = STAILQ_NEXT(nl, f_next); 443 free(nl->f_name); 444 free(nl); 445 } 446 read_option_file("../../conf/options-compat", OL_ALIAS); 447 } 448 449 static char * 450 lower(char *str) 451 { 452 char *cp = str; 453 454 while (*str) { 455 if (isupper(*str)) 456 *str = tolower(*str); 457 str++; 458 } 459 return (cp); 460 } 461