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