1 /* $NetBSD: mkheaders.c,v 1.18 2010/03/22 14:40:54 pooka 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 *, void *, 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, void *value, void *arg) 225 { 226 char tfname[BUFSIZ]; 227 struct nvlist *nv, *option; 228 const char *opt_value; 229 int isfsoption; 230 FILE *fp; 231 232 (void)snprintf(tfname, sizeof(tfname), "tmp_%s", name); 233 if ((fp = fopen(tfname, "w")) == NULL) 234 return (herr("open", tfname, NULL)); 235 236 for (nv = value; nv != NULL; nv = nv->nv_next) { 237 isfsoption = OPT_FSOPT(nv->nv_name); 238 239 if (nv->nv_flags & NV_OBSOLETE) { 240 fprintf(fp, "/* %s `%s' is obsolete */\n", 241 isfsoption ? "file system" : "option", 242 nv->nv_name); 243 fprint_global(fp, nv->nv_name, 0xdeadbeef); 244 continue; 245 } 246 247 if (((option = ht_lookup(opttab, nv->nv_name)) == NULL && 248 (option = ht_lookup(fsopttab, nv->nv_name)) == NULL) && 249 (nv->nv_str == NULL)) { 250 fprintf(fp, "/* %s `%s' not defined */\n", 251 isfsoption ? "file system" : "option", 252 nv->nv_name); 253 fprint_global(fp, nv->nv_name, UNDEFINED); 254 continue; 255 } 256 257 opt_value = option != NULL ? option->nv_str : nv->nv_str; 258 if (isfsoption == 1) 259 /* For filesysteme we'd output the lower case name */ 260 opt_value = NULL; 261 262 fprintf(fp, "#define\t%s", nv->nv_name); 263 if (opt_value != NULL) 264 fprintstr(fp, opt_value); 265 else if (!isfsoption) 266 fprintstr(fp, "1"); 267 fputc('\n', fp); 268 fprint_global(fp, nv->nv_name, 269 opt_value == NULL ? 1 : global_hash(opt_value)); 270 } 271 272 fflush(fp); 273 if (ferror(fp)) 274 return herr("writ", tfname, fp); 275 276 if (fclose(fp) == EOF) 277 return (herr("clos", tfname, NULL)); 278 279 return (moveifchanged(tfname, name)); 280 } 281 282 /* 283 * Emit the option header files. 284 */ 285 static int 286 emitopts(void) 287 { 288 289 return (ht_enumerate(optfiletab, defopts_print, NULL)); 290 } 291 292 /* 293 * A callback function for walking the attribute hash table. 294 * Emit CPP definitions of manifest constants for the locators on the 295 * "name" attribute node (passed as the "value" parameter). 296 */ 297 static int 298 locators_print(const char *name, void *value, void *arg) 299 { 300 struct attr *a; 301 struct nvlist *nv; 302 int i; 303 char *locdup, *namedup; 304 char *cp; 305 FILE *fp = arg; 306 307 a = value; 308 if (a->a_locs) { 309 if (strchr(name, ' ') != NULL || strchr(name, '\t') != NULL) 310 /* 311 * name contains a space; we can't generate 312 * usable defines, so ignore it. 313 */ 314 return 0; 315 locdup = estrdup(name); 316 for (cp = locdup; *cp; cp++) 317 if (islower((unsigned char)*cp)) 318 *cp = toupper((unsigned char)*cp); 319 for (i = 0, nv = a->a_locs; nv; nv = nv->nv_next, i++) { 320 if (strchr(nv->nv_name, ' ') != NULL || 321 strchr(nv->nv_name, '\t') != NULL) 322 /* 323 * name contains a space; we can't generate 324 * usable defines, so ignore it. 325 */ 326 continue; 327 namedup = estrdup(nv->nv_name); 328 for (cp = namedup; *cp; cp++) 329 if (islower((unsigned char)*cp)) 330 *cp = toupper((unsigned char)*cp); 331 else if (*cp == ARRCHR) 332 *cp = '_'; 333 fprintf(fp, "#define %sCF_%s %d\n", locdup, namedup, i); 334 if (nv->nv_str != NULL) 335 fprintf(fp, "#define %sCF_%s_DEFAULT %s\n", 336 locdup, namedup, nv->nv_str); 337 free(namedup); 338 } 339 /* assert(i == a->a_loclen) */ 340 fprintf(fp, "#define %sCF_NLOCS %d\n", locdup, a->a_loclen); 341 free(locdup); 342 } 343 return 0; 344 } 345 346 /* 347 * Build the "locators.h" file with manifest constants for all potential 348 * locators in the configuration. Do this by enumerating the attribute 349 * hash table and emitting all the locators for each attribute. 350 */ 351 int 352 emitlocs(void) 353 { 354 const char *tfname; 355 int rval; 356 FILE *tfp; 357 358 tfname = "tmp_locators.h"; 359 if ((tfp = fopen(tfname, "w")) == NULL) 360 return (herr("open", tfname, NULL)); 361 362 rval = ht_enumerate(attrtab, locators_print, tfp); 363 364 fflush(tfp); 365 if (ferror(tfp)) 366 return (herr("writ", tfname, NULL)); 367 if (fclose(tfp) == EOF) 368 return (herr("clos", tfname, NULL)); 369 if (rval) 370 return (rval); 371 return (moveifchanged(tfname, "locators.h")); 372 } 373 374 /* 375 * Build the "ioconf.h" file with extern declarations for all configured 376 * cfdrivers. 377 */ 378 int 379 emitioconfh(void) 380 { 381 const char *tfname; 382 FILE *tfp; 383 struct devbase *d; 384 385 tfname = "tmp_ioconf.h"; 386 if ((tfp = fopen(tfname, "w")) == NULL) 387 return (herr("open", tfname, NULL)); 388 389 TAILQ_FOREACH(d, &allbases, d_next) { 390 if (!devbase_has_instances(d, WILD)) 391 continue; 392 fprintf(tfp, "extern struct cfdriver %s_cd;\n", d->d_name); 393 } 394 395 fflush(tfp); 396 if (ferror(tfp)) 397 return herr("writ", tfname, tfp); 398 399 if (fclose(tfp) == EOF) 400 return (herr("clos", tfname, NULL)); 401 402 return (moveifchanged(tfname, "ioconf.h")); 403 } 404 405 /* 406 * Make a file that config_time.h can use as a source, if required. 407 */ 408 static int 409 emittime(void) 410 { 411 FILE *fp; 412 time_t t; 413 struct tm *tm; 414 char buf[128]; 415 416 t = time(NULL); 417 tm = gmtime(&t); 418 419 if ((fp = fopen("config_time.src", "w")) == NULL) 420 return (herr("open", "config_time.src", NULL)); 421 422 if (strftime(buf, sizeof(buf), "%c %Z", tm) == 0) 423 return (herr("strftime", "config_time.src", fp)); 424 425 fprintf(fp, "/* %s */\n" 426 "#define CONFIG_TIME\t%2lld\n" 427 "#define CONFIG_YEAR\t%2d\n" 428 "#define CONFIG_MONTH\t%2d\n" 429 "#define CONFIG_DATE\t%2d\n" 430 "#define CONFIG_HOUR\t%2d\n" 431 "#define CONFIG_MINS\t%2d\n" 432 "#define CONFIG_SECS\t%2d\n", 433 buf, (long long)t, 434 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 435 tm->tm_hour, tm->tm_min, tm->tm_sec); 436 437 fflush(fp); 438 if (ferror(fp)) 439 return (herr("fprintf", "config_time.src", fp)); 440 441 if (fclose(fp) != 0) 442 return (herr("clos", "config_time.src", NULL)); 443 444 /* 445 * *Don't* moveifchanged this file. Makefile.kern.inc will 446 * handle that if it determines such a move is necessary. 447 */ 448 return (0); 449 } 450 451 /* 452 * Compare two files. If nfname doesn't exist, or is different from 453 * tfname, move tfname to nfname. Otherwise, delete tfname. 454 */ 455 int 456 moveifchanged(const char *tfname, const char *nfname) 457 { 458 char tbuf[BUFSIZ], nbuf[BUFSIZ]; 459 FILE *tfp, *nfp; 460 461 if ((tfp = fopen(tfname, "r")) == NULL) 462 return (herr("open", tfname, NULL)); 463 464 if ((nfp = fopen(nfname, "r")) == NULL) 465 goto moveit; 466 467 while (fgets(tbuf, sizeof(tbuf), tfp) != NULL) { 468 if (fgets(nbuf, sizeof(nbuf), nfp) == NULL) { 469 /* 470 * Old file has fewer lines. 471 */ 472 goto moveit; 473 } 474 if (strcmp(tbuf, nbuf) != 0) 475 goto moveit; 476 } 477 478 /* 479 * We've reached the end of the new file. Check to see if new file 480 * has fewer lines than old. 481 */ 482 if (fgets(nbuf, sizeof(nbuf), nfp) != NULL) { 483 /* 484 * New file has fewer lines. 485 */ 486 goto moveit; 487 } 488 489 (void) fclose(nfp); 490 (void) fclose(tfp); 491 if (remove(tfname) == -1) 492 return(herr("remov", tfname, NULL)); 493 return (0); 494 495 moveit: 496 /* 497 * They're different, or the file doesn't exist. 498 */ 499 if (nfp) 500 (void) fclose(nfp); 501 if (tfp) 502 (void) fclose(tfp); 503 if (rename(tfname, nfname) == -1) 504 return (herr("renam", tfname, NULL)); 505 return (0); 506 } 507 508 static int 509 herr(const char *what, const char *fname, FILE *fp) 510 { 511 512 warn("error %sing %s", what, fname); 513 if (fp) 514 (void)fclose(fp); 515 return (1); 516 } 517 518 static char * 519 cntname(const char *src) 520 { 521 char *dst; 522 unsigned char c; 523 static char buf[100]; 524 525 dst = buf; 526 *dst++ = 'N'; 527 while ((c = *src++) != 0) 528 *dst++ = islower(c) ? toupper(c) : c; 529 *dst = 0; 530 return (buf); 531 } 532