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