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