Home | History | Annotate | Line # | Download | only in config
files.c revision 1.14
      1 /*	$NetBSD: files.c,v 1.14 2014/10/09 10:29:36 uebayasi 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: @(#)files.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 <errno.h>
     49 #include <stdio.h>
     50 #include <stdlib.h>
     51 #include <string.h>
     52 #include <util.h>
     53 #include "defs.h"
     54 
     55 extern const char *yyfile;
     56 
     57 /*
     58  * We check that each full path name is unique.  File base names
     59  * should generally also be unique, e.g., having both a net/xx.c and
     60  * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably
     61  * wrong, but is permitted under some conditions.
     62  */
     63 static struct hashtab *basetab;		/* file base names */
     64 static struct hashtab *pathtab;		/* full path names */
     65 
     66 static struct files **unchecked;
     67 
     68 static void	addfiletoattr(const char *, struct files *);
     69 static int	checkaux(const char *, void *);
     70 static int	fixcount(const char *, void *);
     71 static int	fixfsel(const char *, void *);
     72 static int	fixsel(const char *, void *);
     73 
     74 void
     75 initfiles(void)
     76 {
     77 
     78 	basetab = ht_new();
     79 	pathtab = ht_new();
     80 	TAILQ_INIT(&allfiles);
     81 	unchecked = &TAILQ_FIRST(&allfiles);
     82 	TAILQ_INIT(&allobjects);
     83 }
     84 
     85 void
     86 addfile(const char *path, struct condexpr *optx, int flags, const char *rule)
     87 {
     88 	struct files *fi;
     89 	const char *dotp, *tail;
     90 	size_t baselen;
     91 	int needc, needf;
     92 	char base[200];
     93 
     94 	/* check various errors */
     95 	needc = flags & FI_NEEDSCOUNT;
     96 	needf = flags & FI_NEEDSFLAG;
     97 	if (needc && needf) {
     98 		cfgerror("cannot mix needs-count and needs-flag");
     99 		goto bad;
    100 	}
    101 	if (optx == NULL && (needc || needf)) {
    102 		cfgerror("nothing to %s for %s", needc ? "count" : "flag",
    103 		    path);
    104 		goto bad;
    105 	}
    106 
    107 	/* find last part of pathname, and same without trailing suffix */
    108 	tail = strrchr(path, '/');
    109 	if (tail == NULL)
    110 		tail = path;
    111 	else
    112 		tail++;
    113 	dotp = strrchr(tail, '.');
    114 	if (dotp == NULL || dotp[1] == 0 ||
    115 	    (baselen = dotp - tail) >= sizeof(base)) {
    116 		cfgerror("invalid pathname `%s'", path);
    117 		goto bad;
    118 	}
    119 
    120 	/*
    121 	 * Commit this file to memory.  We will decide later whether it
    122 	 * will be used after all.
    123 	 */
    124 	fi = ecalloc(1, sizeof *fi);
    125 	if (ht_insert(pathtab, path, fi)) {
    126 		free(fi);
    127 		if ((fi = ht_lookup(pathtab, path)) == NULL)
    128 			panic("addfile: ht_lookup(%s)", path);
    129 
    130 		/*
    131 		 * If it's a duplicate entry, it is must specify a make
    132 		 * rule, and only a make rule, and must come from
    133 		 * a different source file than the original entry.
    134 		 * If it does otherwise, it is disallowed.  This allows
    135 		 * machine-dependent files to override the compilation
    136 		 * options for specific files.
    137 		 */
    138 		if (rule != NULL && optx == NULL && flags == 0 &&
    139 		    yyfile != fi->fi_srcfile) {
    140 			fi->fi_mkrule = rule;
    141 			return;
    142 		}
    143 		cfgerror("duplicate file %s", path);
    144 		cfgxerror(fi->fi_srcfile, fi->fi_srcline,
    145 		    "here is the original definition");
    146 		goto bad;
    147 	}
    148 	memcpy(base, tail, baselen);
    149 	base[baselen] = 0;
    150 	fi->fi_srcfile = yyfile;
    151 	fi->fi_srcline = currentline();
    152 	fi->fi_flags = flags;
    153 	fi->fi_path = path;
    154 	fi->fi_tail = tail;
    155 	fi->fi_base = intern(base);
    156 	fi->fi_prefix = SLIST_EMPTY(&prefixes) ? NULL :
    157 			SLIST_FIRST(&prefixes)->pf_prefix;
    158 	fi->fi_optx = optx;
    159 	fi->fi_optf = NULL;
    160 	fi->fi_mkrule = rule;
    161 	fi->fi_attr = NULL;
    162 	TAILQ_INSERT_TAIL(&allfiles, fi, fi_next);
    163 	return;
    164  bad:
    165 	if (optx != NULL) {
    166 		condexpr_destroy(optx);
    167 	}
    168 }
    169 
    170 void
    171 addobject(const char *path, struct condexpr *optx, int flags)
    172 {
    173 	struct objects *oi;
    174 
    175 	/*
    176 	 * Commit this object to memory.  We will decide later whether it
    177 	 * will be used after all.
    178 	 */
    179 	oi = ecalloc(1, sizeof *oi);
    180 	if (ht_insert(pathtab, path, oi)) {
    181 		free(oi);
    182 		if ((oi = ht_lookup(pathtab, path)) == NULL)
    183 			panic("addfile: ht_lookup(%s)", path);
    184 		cfgerror("duplicate file %s", path);
    185 		cfgxerror(oi->oi_srcfile, oi->oi_srcline,
    186 		    "here is the original definition");
    187 	}
    188 	oi->oi_srcfile = yyfile;
    189 	oi->oi_srcline = currentline();
    190 	oi->oi_flags = flags;
    191 	oi->oi_path = path;
    192 	oi->oi_prefix = SLIST_EMPTY(&prefixes) ? NULL :
    193 			SLIST_FIRST(&prefixes)->pf_prefix;
    194 	oi->oi_optx = optx;
    195 	oi->oi_optf = NULL;
    196 	TAILQ_INSERT_TAIL(&allobjects, oi, oi_next);
    197 	return;
    198 }
    199 
    200 static void
    201 addfiletoattr(const char *name, struct files *fi)
    202 {
    203 	struct attr *a;
    204 
    205 	a = ht_lookup(attrtab, name);
    206 	if (a != NULL) {
    207 		TAILQ_INSERT_TAIL(&a->a_files, fi, fi_anext);
    208 		fi->fi_attr = a;
    209 	}
    210 }
    211 
    212 /*
    213  * We have finished reading some "files" file, either ../../conf/files
    214  * or ./files.$machine.  Make sure that everything that is flagged as
    215  * needing a count is reasonable.  (This prevents ../../conf/files from
    216  * depending on some machine-specific device.)
    217  */
    218 void
    219 checkfiles(void)
    220 {
    221 	struct files *fi, *last;
    222 
    223 	last = NULL;
    224 	for (fi = *unchecked; fi != NULL;
    225 	    last = fi, fi = TAILQ_NEXT(fi, fi_next)) {
    226 		if ((fi->fi_flags & FI_NEEDSCOUNT) != 0)
    227 			(void)expr_eval(fi->fi_optx, checkaux, fi);
    228 	}
    229 	if (last != NULL)
    230 		unchecked = &TAILQ_NEXT(last, fi_next);
    231 }
    232 
    233 /*
    234  * Auxiliary function for checkfiles, called from expr_eval.
    235  * We are not actually interested in the expression's value.
    236  */
    237 static int
    238 checkaux(const char *name, void *context)
    239 {
    240 	struct files *fi = context;
    241 
    242 	if (ht_lookup(devbasetab, name) == NULL) {
    243 		cfgxerror(fi->fi_srcfile, fi->fi_srcline,
    244 		    "`%s' is not a countable device",
    245 		    name);
    246 		/* keep fixfiles() from complaining again */
    247 		fi->fi_flags |= FI_HIDDEN;
    248 	}
    249 	return (0);
    250 }
    251 
    252 /*
    253  * We have finished reading everything.  Tack the files down: calculate
    254  * selection and counts as needed.  Check that the object files built
    255  * from the selected sources do not collide.
    256  */
    257 int
    258 fixfiles(void)
    259 {
    260 	struct files *fi, *ofi;
    261 	struct nvlist *flathead, **flatp;
    262 	int err, sel;
    263 
    264 	err = 0;
    265 	TAILQ_FOREACH(fi, &allfiles, fi_next) {
    266 
    267 		/* Skip files that generated counted-device complaints. */
    268 		if (fi->fi_flags & FI_HIDDEN)
    269 			continue;
    270 
    271 		/* Optional: see if it is to be included. */
    272 		if (fi->fi_flags & FIT_FORCESELECT)
    273 		{
    274 			/* include it */ ;
    275 		}
    276 		else if (fi->fi_optx != NULL) {
    277 			if (fi->fi_optx->cx_type == CX_ATOM) {
    278 				addfiletoattr(fi->fi_optx->cx_u.atom, fi);
    279 			}
    280 			flathead = NULL;
    281 			flatp = &flathead;
    282 			sel = expr_eval(fi->fi_optx,
    283 			    fi->fi_flags & FI_NEEDSCOUNT ? fixcount :
    284 			    fi->fi_flags & FI_NEEDSFLAG ? fixfsel :
    285 			    fixsel,
    286 			    &flatp);
    287 			fi->fi_optf = flathead;
    288 			if (!sel)
    289 				continue;
    290 		}
    291 
    292 		/* We like this file.  Make sure it generates a unique .o. */
    293 		if (ht_insert(basetab, fi->fi_base, fi)) {
    294 			if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL)
    295 				panic("fixfiles ht_lookup(%s)", fi->fi_base);
    296 			/*
    297 			 * If the new file comes from a different source,
    298 			 * allow the new one to override the old one.
    299 			 */
    300 			if (fi->fi_path != ofi->fi_path) {
    301 				if (ht_replace(basetab, fi->fi_base, fi) != 1)
    302 					panic("fixfiles ht_replace(%s)",
    303 					    fi->fi_base);
    304 				ofi->fi_flags &= ~FI_SEL;
    305 				ofi->fi_flags |= FI_HIDDEN;
    306 			} else {
    307 				cfgxerror(fi->fi_srcfile, fi->fi_srcline,
    308 				    "object file collision on %s.o, from %s",
    309 				    fi->fi_base, fi->fi_path);
    310 				cfgxerror(ofi->fi_srcfile, ofi->fi_srcline,
    311 				    "here is the previous file: %s",
    312 				    ofi->fi_path);
    313 				err = 1;
    314 			}
    315 		}
    316 		fi->fi_flags |= FI_SEL;
    317 		CFGDBG(3, "file slected `%s'", fi->fi_path);
    318 		if (fi->fi_attr != NULL)
    319 			CFGDBG(3, "file `%s' belongs to attr `%s'", fi->fi_path,
    320 			    fi->fi_attr->a_name);
    321 	}
    322 	return (err);
    323 }
    324 
    325 /*
    326  * We have finished reading everything.  Tack the objects down: calculate
    327  * selection.
    328  */
    329 int
    330 fixobjects(void)
    331 {
    332 	struct objects *oi;
    333 	struct nvlist *flathead, **flatp;
    334 	int err, sel;
    335 
    336 	err = 0;
    337 	TAILQ_FOREACH(oi, &allobjects, oi_next) {
    338 		/* Optional: see if it is to be included. */
    339 		if (oi->oi_optx != NULL) {
    340 			flathead = NULL;
    341 			flatp = &flathead;
    342 			sel = expr_eval(oi->oi_optx,
    343 			    oi->oi_flags & OI_NEEDSFLAG ? fixfsel :
    344 			    fixsel,
    345 			    &flatp);
    346 			oi->oi_optf = flathead;
    347 			if (!sel)
    348 				continue;
    349 		}
    350 
    351 		oi->oi_flags |= OI_SEL;
    352 	}
    353 	return (err);
    354 }
    355 
    356 /*
    357  * We have finished reading everything.  Tack the devsws down: calculate
    358  * selection.
    359  */
    360 int
    361 fixdevsw(void)
    362 {
    363 	int error;
    364 	struct devm *dm, *res;
    365 	struct hashtab *fixdevmtab;
    366 	char mstr[16];
    367 
    368 	error = 0;
    369 	fixdevmtab = ht_new();
    370 
    371 	TAILQ_FOREACH(dm, &alldevms, dm_next) {
    372 		res = ht_lookup(fixdevmtab, intern(dm->dm_name));
    373 		if (res != NULL) {
    374 			if (res->dm_cmajor != dm->dm_cmajor ||
    375 			    res->dm_bmajor != dm->dm_bmajor) {
    376 				cfgxerror(res->dm_srcfile, res->dm_srcline,
    377 					"device-major '%s' "
    378 					"block %d, char %d redefined"
    379 					" at %s:%d as block %d, char %d",
    380 					res->dm_name,
    381 					res->dm_bmajor, res->dm_cmajor,
    382 					dm->dm_srcfile, dm->dm_srcline,
    383 					dm->dm_bmajor, dm->dm_cmajor);
    384 			} else {
    385 				cfgxerror(res->dm_srcfile, res->dm_srcline,
    386 					"device-major '%s' "
    387 					"(block %d, char %d) duplicated"
    388 					" at %s:%d",
    389 					dm->dm_name, dm->dm_bmajor,
    390 					dm->dm_cmajor,
    391 					dm->dm_srcfile, dm->dm_srcline);
    392 			}
    393 			error = 1;
    394 			goto out;
    395 		}
    396 		if (ht_insert(fixdevmtab, intern(dm->dm_name), dm)) {
    397 			panic("fixdevsw: %s char %d block %d",
    398 			      dm->dm_name, dm->dm_cmajor, dm->dm_bmajor);
    399 		}
    400 
    401 		if (dm->dm_opts != NULL &&
    402 		    !expr_eval(dm->dm_opts, fixsel, NULL))
    403 			continue;
    404 
    405 		if (dm->dm_cmajor != NODEVMAJOR) {
    406 			if (ht_lookup(cdevmtab, intern(dm->dm_name)) != NULL) {
    407 				cfgxerror(dm->dm_srcfile, dm->dm_srcline,
    408 				       "device-major of character device '%s' "
    409 				       "is already defined", dm->dm_name);
    410 				error = 1;
    411 				goto out;
    412 			}
    413 			(void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_cmajor);
    414 			if (ht_lookup(cdevmtab, intern(mstr)) != NULL) {
    415 				cfgxerror(dm->dm_srcfile, dm->dm_srcline,
    416 				       "device-major of character major '%d' "
    417 				       "is already defined", dm->dm_cmajor);
    418 				error = 1;
    419 				goto out;
    420 			}
    421 			if (ht_insert(cdevmtab, intern(dm->dm_name), dm) ||
    422 			    ht_insert(cdevmtab, intern(mstr), dm)) {
    423 				panic("fixdevsw: %s character major %d",
    424 				      dm->dm_name, dm->dm_cmajor);
    425 			}
    426 		}
    427 		if (dm->dm_bmajor != NODEVMAJOR) {
    428 			if (ht_lookup(bdevmtab, intern(dm->dm_name)) != NULL) {
    429 				cfgxerror(dm->dm_srcfile, dm->dm_srcline,
    430 				       "device-major of block device '%s' "
    431 				       "is already defined", dm->dm_name);
    432 				error = 1;
    433 				goto out;
    434 			}
    435 			(void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_bmajor);
    436 			if (ht_lookup(bdevmtab, intern(mstr)) != NULL) {
    437 				cfgxerror(dm->dm_srcfile, dm->dm_srcline,
    438 				       "device-major of block major '%d' "
    439 				       "is already defined", dm->dm_bmajor);
    440 				error = 1;
    441 				goto out;
    442 			}
    443 			if (ht_insert(bdevmtab, intern(dm->dm_name), dm) ||
    444 			    ht_insert(bdevmtab, intern(mstr), dm)) {
    445 				panic("fixdevsw: %s block major %d",
    446 				      dm->dm_name, dm->dm_bmajor);
    447 			}
    448 		}
    449 	}
    450 
    451 out:
    452 	ht_free(fixdevmtab);
    453 	return (error);
    454 }
    455 
    456 /*
    457  * Called when evaluating a needs-count expression.  Make sure the
    458  * atom is a countable device.  The expression succeeds iff there
    459  * is at least one of them (note that while `xx*' will not always
    460  * set xx's d_umax > 0, you cannot mix '*' and needs-count).  The
    461  * mkheaders() routine wants a flattened, in-order list of the
    462  * atoms for `#define name value' lines, so we build that as we
    463  * are called to eval each atom.
    464  */
    465 static int
    466 fixcount(const char *name, void *context)
    467 {
    468 	struct nvlist ***p = context;
    469 	struct devbase *dev;
    470 	struct nvlist *nv;
    471 
    472 	dev = ht_lookup(devbasetab, name);
    473 	if (dev == NULL)	/* cannot occur here; we checked earlier */
    474 		panic("fixcount(%s)", name);
    475 	nv = newnv(name, NULL, NULL, dev->d_umax, NULL);
    476 	**p = nv;
    477 	*p = &nv->nv_next;
    478 	(void)ht_insert(needcnttab, name, nv);
    479 	return (dev->d_umax != 0);
    480 }
    481 
    482 /*
    483  * Called from fixfiles when eval'ing a selection expression for a
    484  * file that will generate a .h with flags.  We will need the flat list.
    485  */
    486 static int
    487 fixfsel(const char *name, void *context)
    488 {
    489 	struct nvlist ***p = context;
    490 	struct nvlist *nv;
    491 	int sel;
    492 
    493 	sel = ht_lookup(selecttab, name) != NULL;
    494 	nv = newnv(name, NULL, NULL, sel, NULL);
    495 	**p = nv;
    496 	*p = &nv->nv_next;
    497 	return (sel);
    498 }
    499 
    500 /*
    501  * As for fixfsel above, but we do not need the flat list.
    502  */
    503 static int
    504 /*ARGSUSED*/
    505 fixsel(const char *name, void *context)
    506 {
    507 
    508 	return (ht_lookup(selecttab, name) != NULL);
    509 }
    510 
    511 /*
    512  * Eval an expression tree.  Calls the given function on each node,
    513  * passing it the given context & the name; return value is &/|/! of
    514  * results of evaluating atoms.
    515  *
    516  * No short circuiting ever occurs.  fn must return 0 or 1 (otherwise
    517  * our mixing of C's bitwise & boolean here may give surprises).
    518  */
    519 int
    520 expr_eval(struct condexpr *expr, int (*fn)(const char *, void *), void *ctx)
    521 {
    522 	int lhs, rhs;
    523 
    524 	switch (expr->cx_type) {
    525 
    526 	case CX_ATOM:
    527 		return ((*fn)(expr->cx_atom, ctx));
    528 
    529 	case CX_NOT:
    530 		return (!expr_eval(expr->cx_not, fn, ctx));
    531 
    532 	case CX_AND:
    533 		lhs = expr_eval(expr->cx_and.left, fn, ctx);
    534 		rhs = expr_eval(expr->cx_and.right, fn, ctx);
    535 		return (lhs & rhs);
    536 
    537 	case CX_OR:
    538 		lhs = expr_eval(expr->cx_or.left, fn, ctx);
    539 		rhs = expr_eval(expr->cx_or.right, fn, ctx);
    540 		return (lhs | rhs);
    541 	}
    542 	panic("invalid condexpr type %d", (int)expr->cx_type);
    543 	/* NOTREACHED */
    544 	return (0);
    545 }
    546 
    547 #ifdef DEBUG
    548 /*
    549  * Print expression tree.
    550  */
    551 void
    552 prexpr(struct nvlist *expr)
    553 {
    554 	static void pr0();
    555 
    556 	printf("expr =");
    557 	pr0(expr);
    558 	printf("\n");
    559 	(void)fflush(stdout);
    560 }
    561 
    562 static void
    563 pr0(struct nvlist *e)
    564 {
    565 
    566 	switch (e->nv_num) {
    567 	case FX_ATOM:
    568 		printf(" %s", e->nv_name);
    569 		return;
    570 	case FX_NOT:
    571 		printf(" (!");
    572 		break;
    573 	case FX_AND:
    574 		printf(" (&");
    575 		break;
    576 	case FX_OR:
    577 		printf(" (|");
    578 		break;
    579 	default:
    580 		printf(" (?%lld?", e->nv_num);
    581 		break;
    582 	}
    583 	if (e->nv_ptr)
    584 		pr0(e->nv_ptr);
    585 	pr0(e->nv_next);
    586 	printf(")");
    587 }
    588 #endif
    589