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 = value ? ns(value) : NULL; 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 298 /* "cannot happen"? the otab list should be complete.. */ 299 (void)strlcpy(nbuf, "options.h", sizeof(nbuf)); 300 301 SLIST_FOREACH(po, &otab, o_next) { 302 if (eq(po->o_name, name)) { 303 strlcpy(nbuf, po->o_file, sizeof(nbuf)); 304 break; 305 } 306 } 307 308 (void)strlcpy(hbuf, path(nbuf), sizeof(hbuf)); 309 return (hbuf); 310 } 311 312 313 static void 314 check_duplicate(const char *fname, const char *chkopt) 315 { 316 struct opt_list *po; 317 318 SLIST_FOREACH(po, &otab, o_next) { 319 if (eq(po->o_name, chkopt)) { 320 fprintf(stderr, "%s: Duplicate option %s.\n", 321 fname, chkopt); 322 exit(1); 323 } 324 } 325 } 326 327 static void 328 insert_option(const char *fname, char *optname, char *val) 329 { 330 struct opt_list *po; 331 332 check_duplicate(fname, optname); 333 po = (struct opt_list *) calloc(1, sizeof *po); 334 if (po == NULL) 335 err(EXIT_FAILURE, "calloc"); 336 po->o_name = optname; 337 po->o_file = val; 338 po->o_flags = 0; 339 SLIST_INSERT_HEAD(&otab, po, o_next); 340 } 341 342 static void 343 update_option(const char *optname, char *val, int flags) 344 { 345 struct opt_list *po; 346 347 SLIST_FOREACH(po, &otab, o_next) { 348 if (eq(po->o_name, optname)) { 349 free(po->o_file); 350 po->o_file = val; 351 po->o_flags = flags; 352 return; 353 } 354 } 355 /* 356 * Option not found, but that's OK, we just ignore it since it 357 * may be for another arch. 358 */ 359 return; 360 } 361 362 static int 363 read_option_file(const char *fname, int flags) 364 { 365 FILE *fp; 366 configword wd; 367 char *optname, *val; 368 char genopt[MAXPATHLEN]; 369 370 fp = fopen(fname, "r"); 371 if (fp == NULL) 372 return (0); 373 while (!(wd = get_word(fp)).eof()) { 374 if (wd.eol()) 375 continue; 376 if (wd[0] == '#') { 377 while (!(wd = get_word(fp)).eof() && !wd.eol()) 378 continue; 379 continue; 380 } 381 optname = ns(wd); 382 wd = get_word(fp); 383 if (wd.eof()) 384 return (1); 385 if (wd.eol()) { 386 if (flags) { 387 fprintf(stderr, "%s: compat file requires two" 388 " words per line at %s\n", fname, optname); 389 exit(1); 390 } 391 char *s = ns(optname); 392 (void)snprintf(genopt, sizeof(genopt), "opt_%s.h", 393 lower(s)); 394 val = ns(genopt); 395 free(s); 396 } else { 397 val = ns(wd); 398 } 399 if (flags == 0) 400 insert_option(fname, optname, val); 401 else 402 update_option(optname, val, flags); 403 } 404 (void)fclose(fp); 405 return (1); 406 } 407 408 /* 409 * read the options and options.<machine> files 410 */ 411 static void 412 read_options(void) 413 { 414 char fname[MAXPATHLEN]; 415 416 SLIST_INIT(&otab); 417 read_option_file("../../conf/options", 0); 418 (void)snprintf(fname, sizeof fname, "../../conf/options.%s", 419 machinename); 420 if (!read_option_file(fname, 0)) { 421 (void)snprintf(fname, sizeof fname, "options.%s", machinename); 422 read_option_file(fname, 0); 423 } 424 read_option_file("../../conf/options-compat", OL_ALIAS); 425 } 426 427 static char * 428 lower(char *str) 429 { 430 char *cp = str; 431 432 while (*str) { 433 if (isupper(*str)) 434 *str = tolower(*str); 435 str++; 436 } 437 return (cp); 438 } 439