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