1/* 2 * Copyright (c) 1995 Peter Wemm 3 * Copyright (c) 1980, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 4. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#ifndef lint 32#if 0 33static char sccsid[] = "@(#)mkheaders.c 8.1 (Berkeley) 6/6/93"; 34#endif 35static const char rcsid[] = 36 "$FreeBSD$"; 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 51static struct users { 52 int u_default; 53 int u_min; 54 int u_max; 55} users = { 8, 2, 512 }; 56 57static char *lower(char *); 58static void read_options(void); 59static void do_option(char *); 60static char *tooption(char *); 61 62void 63options(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 139static void 140do_option(char *name) 141{ 142 char *file, *inw; 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 == 0) { 176 outf = fopen(file, "w"); 177 if (outf == 0) 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 char *cp; 200 char *invalue; 201 202 /* get the #define */ 203 if ((inw = get_word(inf)) == 0 || inw == (char *)EOF) 204 break; 205 /* get the option name */ 206 if ((inw = get_word(inf)) == 0 || inw == (char *)EOF) 207 break; 208 inw = ns(inw); 209 /* get the option value */ 210 if ((cp = get_word(inf)) == 0 || cp == (char *)EOF) 211 break; 212 /* option value */ 213 invalue = ns(cp); /* malloced */ 214 if (eq(inw, name)) { 215 oldvalue = invalue; 216 invalue = value; 217 seen++; 218 } 219 SLIST_FOREACH(ol, &otab, o_next) 220 if (eq(inw, ol->o_name)) 221 break; 222 if (!eq(inw, name) && !ol) { 223 fprintf(stderr, 224 "WARNING: unknown option `%s' removed from %s\n", 225 inw, file); 226 tidy++; 227 } else if (ol != NULL && !eq(basefile, ol->o_file)) { 228 fprintf(stderr, 229 "WARNING: option `%s' moved from %s to %s\n", 230 inw, basefile, ol->o_file); 231 tidy++; 232 } else { 233 op = (struct opt *) calloc(1, sizeof *op); 234 if (op == NULL) 235 err(EXIT_FAILURE, "calloc"); 236 op->op_name = inw; 237 op->op_value = invalue; 238 SLIST_INSERT_HEAD(&op_head, op, op_next); 239 } 240 241 /* EOL? */ 242 cp = get_word(inf); 243 if (cp == (char *)EOF) 244 break; 245 } 246 (void)fclose(inf); 247 if (!tidy && ((value == NULL && oldvalue == NULL) || 248 (value && oldvalue && eq(value, oldvalue)))) { 249 while (!SLIST_EMPTY(&op_head)) { 250 op = SLIST_FIRST(&op_head); 251 SLIST_REMOVE_HEAD(&op_head, op_next); 252 free(op->op_name); 253 free(op->op_value); 254 free(op); 255 } 256 return; 257 } 258 259 if (value && !seen) { 260 /* New option appears */ 261 op = (struct opt *) calloc(1, sizeof *op); 262 if (op == NULL) 263 err(EXIT_FAILURE, "calloc"); 264 op->op_name = ns(name); 265 op->op_value = value ? ns(value) : NULL; 266 SLIST_INSERT_HEAD(&op_head, op, op_next); 267 } 268 269 outf = fopen(file, "w"); 270 if (outf == 0) 271 err(1, "%s", file); 272 while (!SLIST_EMPTY(&op_head)) { 273 op = SLIST_FIRST(&op_head); 274 /* was the option in the config file? */ 275 if (op->op_value) { 276 fprintf(outf, "#define %s %s\n", 277 op->op_name, op->op_value); 278 } 279 SLIST_REMOVE_HEAD(&op_head, op_next); 280 free(op->op_name); 281 free(op->op_value); 282 free(op); 283 } 284 (void)fclose(outf); 285} 286 287/* 288 * Find the filename to store the option spec into. 289 */ 290static char * 291tooption(char *name) 292{ 293 static char hbuf[MAXPATHLEN]; 294 char nbuf[MAXPATHLEN]; 295 struct opt_list *po; 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 (void)strlcpy(hbuf, path(nbuf), sizeof(hbuf)); 308 return (hbuf); 309} 310 311 312static void 313check_duplicate(const char *fname, const char *this) 314{ 315 struct opt_list *po; 316 317 SLIST_FOREACH(po, &otab, o_next) { 318 if (eq(po->o_name, this)) { 319 fprintf(stderr, "%s: Duplicate option %s.\n", 320 fname, this); 321 exit(1); 322 } 323 } 324} 325 326static void 327insert_option(const char *fname, char *this, char *val) 328{ 329 struct opt_list *po; 330 331 check_duplicate(fname, this); 332 po = (struct opt_list *) calloc(1, sizeof *po); 333 if (po == NULL) 334 err(EXIT_FAILURE, "calloc"); 335 po->o_name = this; 336 po->o_file = val; 337 po->o_flags = 0; 338 SLIST_INSERT_HEAD(&otab, po, o_next); 339} 340 341static void 342update_option(const char *this, char *val, int flags) 343{ 344 struct opt_list *po; 345 346 SLIST_FOREACH(po, &otab, o_next) { 347 if (eq(po->o_name, this)) { 348 free(po->o_file); 349 po->o_file = val; 350 po->o_flags = flags; 351 return; 352 } 353 } 354 /* 355 * Option not found, but that's OK, we just ignore it since it 356 * may be for another arch. 357 */ 358 return; 359} 360 361static int 362read_option_file(const char *fname, int flags) 363{ 364 FILE *fp; 365 char *wd, *this, *val; 366 char genopt[MAXPATHLEN]; 367 368 fp = fopen(fname, "r"); 369 if (fp == 0) 370 return (0); 371 while ((wd = get_word(fp)) != (char *)EOF) { 372 if (wd == 0) 373 continue; 374 if (wd[0] == '#') { 375 while (((wd = get_word(fp)) != (char *)EOF) && wd) 376 continue; 377 continue; 378 } 379 this = ns(wd); 380 val = get_word(fp); 381 if (val == (char *)EOF) 382 return (1); 383 if (val == 0) { 384 if (flags) { 385 fprintf(stderr, "%s: compat file requires two" 386 " words per line at %s\n", fname, this); 387 exit(1); 388 } 389 char *s = ns(this); 390 (void)snprintf(genopt, sizeof(genopt), "opt_%s.h", 391 lower(s)); 392 val = genopt; 393 free(s); 394 } 395 val = ns(val); 396 if (flags == 0) 397 insert_option(fname, this, val); 398 else 399 update_option(this, val, flags); 400 } 401 (void)fclose(fp); 402 return (1); 403} 404 405/* 406 * read the options and options.<machine> files 407 */ 408static void 409read_options(void) 410{ 411 char fname[MAXPATHLEN]; 412 413 SLIST_INIT(&otab); 414 read_option_file("../../conf/options", 0); 415 (void)snprintf(fname, sizeof fname, "../../conf/options.%s", 416 machinename); 417 if (!read_option_file(fname, 0)) { 418 (void)snprintf(fname, sizeof fname, "options.%s", machinename); 419 read_option_file(fname, 0); 420 } 421 read_option_file("../../conf/options-compat", OL_ALIAS); 422} 423 424static char * 425lower(char *str) 426{ 427 char *cp = str; 428 429 while (*str) { 430 if (isupper(*str)) 431 *str = tolower(*str); 432 str++; 433 } 434 return (cp); 435} 436