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