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