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 static const char rcsid[] = 38 "$FreeBSD$"; 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 53 static struct users { 54 int u_default; 55 int u_min; 56 int u_max; 57 } users = { 8, 2, 512 }; 58 59 static char *lower(char *); 60 static void read_options(void); 61 static void do_option(char *); 62 static char *tooption(char *); 63 64 void 65 options(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 141 static void 142 do_option(char *name) 143 { 144 char *file; 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 configword cp, inw; 202 char *invalue; 203 204 /* get the #define */ 205 if ((inw = get_word(inf)).eol() || inw.eof()) 206 break; 207 /* get the option name */ 208 if ((inw = get_word(inf)).eol() || inw.eof()) 209 break; 210 /* get the option value */ 211 if ((cp = get_word(inf)).eol() || cp.eof()) 212 break; 213 /* option value */ 214 invalue = ns(cp); /* malloced */ 215 if (eq(inw, name)) { 216 oldvalue = invalue; 217 invalue = value; 218 seen++; 219 } 220 SLIST_FOREACH(ol, &otab, o_next) 221 if (eq(inw, ol->o_name)) 222 break; 223 if (!eq(inw, name) && !ol) { 224 fprintf(stderr, 225 "WARNING: unknown option `%s' removed from %s\n", 226 inw->c_str(), file); 227 tidy++; 228 } else if (ol != NULL && !eq(basefile, ol->o_file)) { 229 fprintf(stderr, 230 "WARNING: option `%s' moved from %s to %s\n", 231 inw->c_str(), basefile, ol->o_file); 232 tidy++; 233 } else { 234 op = (struct opt *) calloc(1, sizeof *op); 235 if (op == NULL) 236 err(EXIT_FAILURE, "calloc"); 237 op->op_name = ns(inw); 238 op->op_value = invalue; 239 SLIST_INSERT_HEAD(&op_head, op, op_next); 240 } 241 242 /* EOL? */ 243 cp = get_word(inf); 244 if (cp.eof()) 245 break; 246 } 247 (void)fclose(inf); 248 if (!tidy && ((value == NULL && oldvalue == NULL) || 249 (value && oldvalue && eq(value, oldvalue)))) { 250 while (!SLIST_EMPTY(&op_head)) { 251 op = SLIST_FIRST(&op_head); 252 SLIST_REMOVE_HEAD(&op_head, op_next); 253 free(op->op_name); 254 free(op->op_value); 255 free(op); 256 } 257 return; 258 } 259 260 if (value && !seen) { 261 /* New option appears */ 262 op = (struct opt *) calloc(1, sizeof *op); 263 if (op == NULL) 264 err(EXIT_FAILURE, "calloc"); 265 op->op_name = ns(name); 266 op->op_value = ns(value); 267 SLIST_INSERT_HEAD(&op_head, op, op_next); 268 } 269 270 outf = fopen(file, "w"); 271 if (outf == NULL) 272 err(1, "%s", file); 273 while (!SLIST_EMPTY(&op_head)) { 274 op = SLIST_FIRST(&op_head); 275 /* was the option in the config file? */ 276 if (op->op_value) { 277 fprintf(outf, "#define %s %s\n", 278 op->op_name, op->op_value); 279 } 280 SLIST_REMOVE_HEAD(&op_head, op_next); 281 free(op->op_name); 282 free(op->op_value); 283 free(op); 284 } 285 (void)fclose(outf); 286 } 287 288 /* 289 * Find the filename to store the option spec into. 290 */ 291 static char * 292 tooption(char *name) 293 { 294 static char hbuf[MAXPATHLEN]; 295 char nbuf[MAXPATHLEN]; 296 struct opt_list *po; 297 char *fpath; 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 fpath = path(nbuf); 310 (void)strlcpy(hbuf, fpath, sizeof(hbuf)); 311 free(fpath); 312 return (hbuf); 313 } 314 315 316 static void 317 check_duplicate(const char *fname, const char *chkopt) 318 { 319 struct opt_list *po; 320 321 SLIST_FOREACH(po, &otab, o_next) { 322 if (eq(po->o_name, chkopt)) { 323 fprintf(stderr, "%s: Duplicate option %s.\n", 324 fname, chkopt); 325 exit(1); 326 } 327 } 328 } 329 330 static void 331 insert_option(const char *fname, char *optname, char *val) 332 { 333 struct opt_list *po; 334 335 check_duplicate(fname, optname); 336 po = (struct opt_list *) calloc(1, sizeof *po); 337 if (po == NULL) 338 err(EXIT_FAILURE, "calloc"); 339 po->o_name = optname; 340 po->o_file = val; 341 po->o_flags = 0; 342 SLIST_INSERT_HEAD(&otab, po, o_next); 343 } 344 345 static void 346 update_option(const char *optname, char *val, int flags) 347 { 348 struct opt_list *po; 349 350 SLIST_FOREACH(po, &otab, o_next) { 351 if (eq(po->o_name, optname)) { 352 free(po->o_file); 353 po->o_file = val; 354 po->o_flags = flags; 355 return; 356 } 357 } 358 /* 359 * Option not found, but that's OK, we just ignore it since it 360 * may be for another arch. 361 */ 362 return; 363 } 364 365 static int 366 read_option_file(const char *fname, int flags) 367 { 368 FILE *fp; 369 configword wd; 370 char *optname, *val; 371 char genopt[MAXPATHLEN]; 372 373 fp = fopen(fname, "r"); 374 if (fp == NULL) 375 return (0); 376 while (!(wd = get_word(fp)).eof()) { 377 if (wd.eol()) 378 continue; 379 if (wd[0] == '#') { 380 while (!(wd = get_word(fp)).eof() && !wd.eol()) 381 continue; 382 continue; 383 } 384 optname = ns(wd); 385 wd = get_word(fp); 386 if (wd.eof()) { 387 free(optname); 388 break; 389 } 390 if (wd.eol()) { 391 if (flags) { 392 fprintf(stderr, "%s: compat file requires two" 393 " words per line at %s\n", fname, optname); 394 exit(1); 395 } 396 char *s = ns(optname); 397 (void)snprintf(genopt, sizeof(genopt), "opt_%s.h", 398 lower(s)); 399 val = ns(genopt); 400 free(s); 401 } else { 402 val = ns(wd); 403 } 404 405 if (flags == 0) { 406 /* 407 * insert_option takes possession of `optname` in the 408 * new option instead of making yet another copy. 409 */ 410 insert_option(fname, optname, val); 411 } else { 412 update_option(optname, val, flags); 413 free(optname); 414 optname = NULL; 415 } 416 } 417 (void)fclose(fp); 418 return (1); 419 } 420 421 /* 422 * read the options and options.<machine> files 423 */ 424 static void 425 read_options(void) 426 { 427 char fname[MAXPATHLEN]; 428 429 SLIST_INIT(&otab); 430 read_option_file("../../conf/options", 0); 431 (void)snprintf(fname, sizeof fname, "../../conf/options.%s", 432 machinename); 433 if (!read_option_file(fname, 0)) { 434 (void)snprintf(fname, sizeof fname, "options.%s", machinename); 435 read_option_file(fname, 0); 436 } 437 read_option_file("../../conf/options-compat", OL_ALIAS); 438 } 439 440 static char * 441 lower(char *str) 442 { 443 char *cp = str; 444 445 while (*str) { 446 if (isupper(*str)) 447 *str = tolower(*str); 448 str++; 449 } 450 return (cp); 451 } 452