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