1/* $NetBSD$ */ 2 3/* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This software was developed by the Computer Systems Engineering group 8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 * contributed to Berkeley. 10 * 11 * All advertising materials mentioning features or use of this software 12 * must display the following acknowledgement: 13 * This product includes software developed by the University of 14 * California, Lawrence Berkeley Laboratories. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * from: @(#)mkheaders.c 8.1 (Berkeley) 6/6/93 41 */ 42 43#if HAVE_NBTOOL_CONFIG_H 44#include "nbtool_config.h" 45#endif 46 47#include <sys/cdefs.h> 48__RCSID("$NetBSD$"); 49 50#include <sys/param.h> 51#include <ctype.h> 52#include <errno.h> 53#include <stdio.h> 54#include <stdlib.h> 55#include <string.h> 56#include <time.h> 57#include <util.h> 58#include <err.h> 59#include "defs.h" 60 61#include <crc_extern.h> 62 63static int emitcnt(struct nvlist *); 64static int emitopts(void); 65static int emittime(void); 66static int herr(const char *, const char *, FILE *); 67static int defopts_print(const char *, struct defoptlist *, void *); 68static char *cntname(const char *); 69 70/* 71 * We define a global symbol with the name of each option and its value. 72 * This should stop code compiled with different options being linked together. 73 */ 74 75/* Unlikely constant for undefined options */ 76#define UNDEFINED ('n' << 24 | 0 << 20 | 't' << 12 | 0xdefU) 77/* Value for defined options with value UNDEFINED */ 78#define DEFINED (0xdef1U << 16 | 'n' << 8 | 0xed) 79 80/* 81 * Make the various config-generated header files. 82 */ 83int 84mkheaders(void) 85{ 86 struct files *fi; 87 88 /* 89 * Make headers containing counts, as needed. 90 */ 91 TAILQ_FOREACH(fi, &allfiles, fi_next) { 92 if (fi->fi_flags & FI_HIDDEN) 93 continue; 94 if (fi->fi_flags & (FI_NEEDSCOUNT | FI_NEEDSFLAG) && 95 emitcnt(fi->fi_optf)) 96 return (1); 97 } 98 99 if (emitopts() || emitlocs() || emitioconfh()) 100 return (1); 101 102 /* 103 * If the minimum required version is ever bumped beyond 20090513, 104 * emittime() can be removed. 105 */ 106 if (version <= 20090513 && emittime()) 107 return (1); 108 109 return (0); 110} 111 112static void 113fprint_global(FILE *fp, const char *name, long long value) 114{ 115 /* 116 * We have to doubt the founding fathers here. 117 * The gas syntax for hppa is 'var .equ value', for all? other 118 * instruction sets it is ' .equ var,value'. both have been used in 119 * various assemblers, but supporting a common syntax would be good. 120 * Fortunately we can use .equiv since it has a consistent syntax, 121 * but requires us to detect multiple assignments - event with the 122 * same value. 123 */ 124 fprintf(fp, "#ifdef _LOCORE\n" 125 " .ifndef _KERNEL_OPT_%s\n" 126 " .global _KERNEL_OPT_%s\n" 127 " .equiv _KERNEL_OPT_%s,0x%llx\n" 128 " .endif\n" 129 "#else\n" 130 "__asm(\" .ifndef _KERNEL_OPT_%s\\n" 131 " .global _KERNEL_OPT_%s\\n" 132 " .equiv _KERNEL_OPT_%s,0x%llx\\n" 133 " .endif\");\n" 134 "#endif\n", 135 name, name, name, value, 136 name, name, name, value); 137} 138 139/* Convert the option argument to a 32bit numder */ 140static unsigned int 141global_hash(const char *str) 142{ 143 unsigned long h; 144 char *ep; 145 146 /* 147 * If the value is a valid numeric, just use it 148 * We don't care about negative values here, we 149 * just use the value as a hash. 150 */ 151 h = strtoul(str, &ep, 0); 152 if (*ep != 0) 153 /* Otherwise shove through a 32bit CRC function */ 154 h = crc_buf(0, str, strlen(str)); 155 156 /* Avoid colliding with the value used for undefined options. */ 157 /* At least until I stop any options being set to zero */ 158 return (unsigned int)(h != UNDEFINED ? h : DEFINED); 159} 160 161static void 162fprintcnt(FILE *fp, struct nvlist *nv) 163{ 164 const char *name = cntname(nv->nv_name); 165 166 fprintf(fp, "#define\t%s\t%lld\n", name, nv->nv_num); 167 fprint_global(fp, name, nv->nv_num); 168} 169 170static int 171emitcnt(struct nvlist *head) 172{ 173 char nfname[BUFSIZ], tfname[BUFSIZ]; 174 struct nvlist *nv; 175 FILE *fp; 176 177 (void)snprintf(nfname, sizeof(nfname), "%s.h", head->nv_name); 178 (void)snprintf(tfname, sizeof(tfname), "tmp_%s", nfname); 179 180 if ((fp = fopen(tfname, "w")) == NULL) 181 return (herr("open", tfname, NULL)); 182 183 for (nv = head; nv != NULL; nv = nv->nv_next) 184 fprintcnt(fp, nv); 185 186 fflush(fp); 187 if (ferror(fp)) 188 return herr("writ", tfname, fp); 189 190 if (fclose(fp) == EOF) 191 return (herr("clos", tfname, NULL)); 192 193 return (moveifchanged(tfname, nfname)); 194} 195 196/* 197 * Output a string, preceded by a tab and possibly unescaping any quotes. 198 * The argument will be output as is if it doesn't start with \". 199 * Otherwise the first backslash in a \? sequence will be dropped. 200 */ 201static void 202fprintstr(FILE *fp, const char *str) 203{ 204 205 if (strncmp(str, "\\\"", 2) != 0) { 206 (void)fprintf(fp, "\t%s", str); 207 return; 208 } 209 210 (void)fputc('\t', fp); 211 212 for (; *str; str++) { 213 switch (*str) { 214 case '\\': 215 if (!*++str) /* XXX */ 216 str--; 217 /*FALLTHROUGH*/ 218 default: 219 (void)fputc(*str, fp); 220 break; 221 } 222 } 223} 224 225/* 226 * Callback function for walking the option file hash table. We write out 227 * the options defined for this file. 228 */ 229static int 230/*ARGSUSED*/ 231defopts_print(const char *name, struct defoptlist *value, void *arg) 232{ 233 char tfname[BUFSIZ]; 234 struct nvlist *option; 235 struct defoptlist *dl; 236 const char *opt_value; 237 int isfsoption; 238 FILE *fp; 239 240 (void)snprintf(tfname, sizeof(tfname), "tmp_%s", name); 241 if ((fp = fopen(tfname, "w")) == NULL) 242 return (herr("open", tfname, NULL)); 243 244 for (dl = value; dl != NULL; dl = dl->dl_next) { 245 isfsoption = OPT_FSOPT(dl->dl_name); 246 247 if (dl->dl_obsolete) { 248 fprintf(fp, "/* %s `%s' is obsolete */\n", 249 isfsoption ? "file system" : "option", 250 dl->dl_name); 251 fprint_global(fp, dl->dl_name, 0xdeadbeef); 252 continue; 253 } 254 255 if (((option = ht_lookup(opttab, dl->dl_name)) == NULL && 256 (option = ht_lookup(fsopttab, dl->dl_name)) == NULL) && 257 (dl->dl_value == NULL)) { 258 fprintf(fp, "/* %s `%s' not defined */\n", 259 isfsoption ? "file system" : "option", 260 dl->dl_name); 261 fprint_global(fp, dl->dl_name, UNDEFINED); 262 continue; 263 } 264 265 opt_value = option != NULL ? option->nv_str : dl->dl_value; 266 if (isfsoption == 1) 267 /* For filesysteme we'd output the lower case name */ 268 opt_value = NULL; 269 270 fprintf(fp, "#define\t%s", dl->dl_name); 271 if (opt_value != NULL) 272 fprintstr(fp, opt_value); 273 else if (!isfsoption) 274 fprintstr(fp, "1"); 275 fputc('\n', fp); 276 fprint_global(fp, dl->dl_name, 277 opt_value == NULL ? 1 : global_hash(opt_value)); 278 } 279 280 fflush(fp); 281 if (ferror(fp)) 282 return herr("writ", tfname, fp); 283 284 if (fclose(fp) == EOF) 285 return (herr("clos", tfname, NULL)); 286 287 return (moveifchanged(tfname, name)); 288} 289 290/* 291 * Emit the option header files. 292 */ 293static int 294emitopts(void) 295{ 296 297 return (dlhash_enumerate(optfiletab, defopts_print, NULL)); 298} 299 300/* 301 * A callback function for walking the attribute hash table. 302 * Emit CPP definitions of manifest constants for the locators on the 303 * "name" attribute node (passed as the "value" parameter). 304 */ 305static int 306locators_print(const char *name, void *value, void *arg) 307{ 308 struct attr *a; 309 struct loclist *ll; 310 int i; 311 char *locdup, *namedup; 312 char *cp; 313 FILE *fp = arg; 314 315 a = value; 316 if (a->a_locs) { 317 if (strchr(name, ' ') != NULL || strchr(name, '\t') != NULL) 318 /* 319 * name contains a space; we can't generate 320 * usable defines, so ignore it. 321 */ 322 return 0; 323 locdup = estrdup(name); 324 for (cp = locdup; *cp; cp++) 325 if (islower((unsigned char)*cp)) 326 *cp = (char)toupper((unsigned char)*cp); 327 for (i = 0, ll = a->a_locs; ll; ll = ll->ll_next, i++) { 328 if (strchr(ll->ll_name, ' ') != NULL || 329 strchr(ll->ll_name, '\t') != NULL) 330 /* 331 * name contains a space; we can't generate 332 * usable defines, so ignore it. 333 */ 334 continue; 335 namedup = estrdup(ll->ll_name); 336 for (cp = namedup; *cp; cp++) 337 if (islower((unsigned char)*cp)) 338 *cp = (char)toupper((unsigned char)*cp); 339 else if (*cp == ARRCHR) 340 *cp = '_'; 341 fprintf(fp, "#define %sCF_%s %d\n", locdup, namedup, i); 342 if (ll->ll_string != NULL) 343 fprintf(fp, "#define %sCF_%s_DEFAULT %s\n", 344 locdup, namedup, ll->ll_string); 345 free(namedup); 346 } 347 /* assert(i == a->a_loclen) */ 348 fprintf(fp, "#define %sCF_NLOCS %d\n", locdup, a->a_loclen); 349 free(locdup); 350 } 351 return 0; 352} 353 354/* 355 * Build the "locators.h" file with manifest constants for all potential 356 * locators in the configuration. Do this by enumerating the attribute 357 * hash table and emitting all the locators for each attribute. 358 */ 359int 360emitlocs(void) 361{ 362 const char *tfname; 363 int rval; 364 FILE *tfp; 365 366 tfname = "tmp_locators.h"; 367 if ((tfp = fopen(tfname, "w")) == NULL) 368 return (herr("open", tfname, NULL)); 369 370 rval = ht_enumerate(attrtab, locators_print, tfp); 371 372 fflush(tfp); 373 if (ferror(tfp)) 374 return (herr("writ", tfname, NULL)); 375 if (fclose(tfp) == EOF) 376 return (herr("clos", tfname, NULL)); 377 if (rval) 378 return (rval); 379 return (moveifchanged(tfname, "locators.h")); 380} 381 382/* 383 * Build the "ioconf.h" file with extern declarations for all configured 384 * cfdrivers. 385 */ 386int 387emitioconfh(void) 388{ 389 const char *tfname; 390 FILE *tfp; 391 struct devbase *d; 392 struct devi *i; 393 394 tfname = "tmp_ioconf.h"; 395 if ((tfp = fopen(tfname, "w")) == NULL) 396 return (herr("open", tfname, NULL)); 397 398 fputs("\n/* pseudo-devices */\n", tfp); 399 TAILQ_FOREACH(i, &allpseudo, i_next) { 400 fprintf(tfp, "void %sattach(int);\n", 401 i->i_base->d_name); 402 } 403 404 fputs("\n/* driver structs */\n", tfp); 405 TAILQ_FOREACH(d, &allbases, d_next) { 406 if (!devbase_has_instances(d, WILD)) 407 continue; 408 fprintf(tfp, "extern struct cfdriver %s_cd;\n", d->d_name); 409 } 410 411 fflush(tfp); 412 if (ferror(tfp)) 413 return herr("writ", tfname, tfp); 414 415 if (fclose(tfp) == EOF) 416 return (herr("clos", tfname, NULL)); 417 418 return (moveifchanged(tfname, "ioconf.h")); 419} 420 421/* 422 * Make a file that config_time.h can use as a source, if required. 423 */ 424static int 425emittime(void) 426{ 427 FILE *fp; 428 time_t t; 429 struct tm *tm; 430 char buf[128]; 431 432 t = time(NULL); 433 tm = gmtime(&t); 434 435 if ((fp = fopen("config_time.src", "w")) == NULL) 436 return (herr("open", "config_time.src", NULL)); 437 438 if (strftime(buf, sizeof(buf), "%c %Z", tm) == 0) 439 return (herr("strftime", "config_time.src", fp)); 440 441 fprintf(fp, "/* %s */\n" 442 "#define CONFIG_TIME\t%2lld\n" 443 "#define CONFIG_YEAR\t%2d\n" 444 "#define CONFIG_MONTH\t%2d\n" 445 "#define CONFIG_DATE\t%2d\n" 446 "#define CONFIG_HOUR\t%2d\n" 447 "#define CONFIG_MINS\t%2d\n" 448 "#define CONFIG_SECS\t%2d\n", 449 buf, (long long)t, 450 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 451 tm->tm_hour, tm->tm_min, tm->tm_sec); 452 453 fflush(fp); 454 if (ferror(fp)) 455 return (herr("fprintf", "config_time.src", fp)); 456 457 if (fclose(fp) != 0) 458 return (herr("clos", "config_time.src", NULL)); 459 460 /* 461 * *Don't* moveifchanged this file. Makefile.kern.inc will 462 * handle that if it determines such a move is necessary. 463 */ 464 return (0); 465} 466 467/* 468 * Compare two files. If nfname doesn't exist, or is different from 469 * tfname, move tfname to nfname. Otherwise, delete tfname. 470 */ 471int 472moveifchanged(const char *tfname, const char *nfname) 473{ 474 char tbuf[BUFSIZ], nbuf[BUFSIZ]; 475 FILE *tfp, *nfp; 476 477 if ((tfp = fopen(tfname, "r")) == NULL) 478 return (herr("open", tfname, NULL)); 479 480 if ((nfp = fopen(nfname, "r")) == NULL) 481 goto moveit; 482 483 while (fgets(tbuf, sizeof(tbuf), tfp) != NULL) { 484 if (fgets(nbuf, sizeof(nbuf), nfp) == NULL) { 485 /* 486 * Old file has fewer lines. 487 */ 488 goto moveit; 489 } 490 if (strcmp(tbuf, nbuf) != 0) 491 goto moveit; 492 } 493 494 /* 495 * We've reached the end of the new file. Check to see if new file 496 * has fewer lines than old. 497 */ 498 if (fgets(nbuf, sizeof(nbuf), nfp) != NULL) { 499 /* 500 * New file has fewer lines. 501 */ 502 goto moveit; 503 } 504 505 (void) fclose(nfp); 506 (void) fclose(tfp); 507 if (remove(tfname) == -1) 508 return(herr("remov", tfname, NULL)); 509 return (0); 510 511 moveit: 512 /* 513 * They're different, or the file doesn't exist. 514 */ 515 if (nfp) 516 (void) fclose(nfp); 517 if (tfp) 518 (void) fclose(tfp); 519 if (rename(tfname, nfname) == -1) 520 return (herr("renam", tfname, NULL)); 521 return (0); 522} 523 524static int 525herr(const char *what, const char *fname, FILE *fp) 526{ 527 528 warn("error %sing %s", what, fname); 529 if (fp) 530 (void)fclose(fp); 531 return (1); 532} 533 534static char * 535cntname(const char *src) 536{ 537 char *dst; 538 char c; 539 static char buf[100]; 540 541 dst = buf; 542 *dst++ = 'N'; 543 while ((c = *src++) != 0) 544 *dst++ = (char)(islower((u_char)c) ? toupper((u_char)c) : c); 545 *dst = 0; 546 return (buf); 547} 548