Home | History | Annotate | Line # | Download | only in config
files.c revision 1.9
      1  1.9  drochner /*	$NetBSD: files.c,v 1.9 2009/01/20 18:20:48 drochner Exp $	*/
      2  1.1   thorpej 
      3  1.1   thorpej /*
      4  1.1   thorpej  * Copyright (c) 1992, 1993
      5  1.1   thorpej  *	The Regents of the University of California.  All rights reserved.
      6  1.1   thorpej  *
      7  1.1   thorpej  * This software was developed by the Computer Systems Engineering group
      8  1.1   thorpej  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
      9  1.1   thorpej  * contributed to Berkeley.
     10  1.1   thorpej  *
     11  1.1   thorpej  * All advertising materials mentioning features or use of this software
     12  1.1   thorpej  * must display the following acknowledgement:
     13  1.1   thorpej  *	This product includes software developed by the University of
     14  1.1   thorpej  *	California, Lawrence Berkeley Laboratories.
     15  1.1   thorpej  *
     16  1.1   thorpej  * Redistribution and use in source and binary forms, with or without
     17  1.1   thorpej  * modification, are permitted provided that the following conditions
     18  1.1   thorpej  * are met:
     19  1.1   thorpej  * 1. Redistributions of source code must retain the above copyright
     20  1.1   thorpej  *    notice, this list of conditions and the following disclaimer.
     21  1.1   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     22  1.1   thorpej  *    notice, this list of conditions and the following disclaimer in the
     23  1.1   thorpej  *    documentation and/or other materials provided with the distribution.
     24  1.1   thorpej  * 3. Neither the name of the University nor the names of its contributors
     25  1.1   thorpej  *    may be used to endorse or promote products derived from this software
     26  1.1   thorpej  *    without specific prior written permission.
     27  1.1   thorpej  *
     28  1.1   thorpej  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     29  1.1   thorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     30  1.1   thorpej  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     31  1.1   thorpej  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     32  1.1   thorpej  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     33  1.1   thorpej  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     34  1.1   thorpej  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     35  1.1   thorpej  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     36  1.1   thorpej  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     37  1.1   thorpej  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     38  1.1   thorpej  * SUCH DAMAGE.
     39  1.1   thorpej  *
     40  1.1   thorpej  *	from: @(#)files.c	8.1 (Berkeley) 6/6/93
     41  1.1   thorpej  */
     42  1.1   thorpej 
     43  1.1   thorpej #if HAVE_NBTOOL_CONFIG_H
     44  1.1   thorpej #include "nbtool_config.h"
     45  1.1   thorpej #endif
     46  1.1   thorpej 
     47  1.1   thorpej #include <sys/param.h>
     48  1.1   thorpej #include <errno.h>
     49  1.1   thorpej #include <stdio.h>
     50  1.1   thorpej #include <stdlib.h>
     51  1.1   thorpej #include <string.h>
     52  1.3  christos #include <util.h>
     53  1.1   thorpej #include "defs.h"
     54  1.1   thorpej 
     55  1.1   thorpej extern const char *yyfile;
     56  1.1   thorpej 
     57  1.1   thorpej /*
     58  1.1   thorpej  * We check that each full path name is unique.  File base names
     59  1.1   thorpej  * should generally also be unique, e.g., having both a net/xx.c and
     60  1.1   thorpej  * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably
     61  1.1   thorpej  * wrong, but is permitted under some conditions.
     62  1.1   thorpej  */
     63  1.1   thorpej static struct hashtab *basetab;		/* file base names */
     64  1.1   thorpej static struct hashtab *pathtab;		/* full path names */
     65  1.1   thorpej 
     66  1.1   thorpej static struct files **unchecked;
     67  1.1   thorpej 
     68  1.1   thorpej static int	checkaux(const char *, void *);
     69  1.1   thorpej static int	fixcount(const char *, void *);
     70  1.1   thorpej static int	fixfsel(const char *, void *);
     71  1.1   thorpej static int	fixsel(const char *, void *);
     72  1.1   thorpej static int	expr_eval(struct nvlist *,
     73  1.1   thorpej 		    int (*)(const char *, void *), void *);
     74  1.1   thorpej static void	expr_free(struct nvlist *);
     75  1.1   thorpej 
     76  1.1   thorpej void
     77  1.1   thorpej initfiles(void)
     78  1.1   thorpej {
     79  1.1   thorpej 
     80  1.1   thorpej 	basetab = ht_new();
     81  1.1   thorpej 	pathtab = ht_new();
     82  1.1   thorpej 	TAILQ_INIT(&allfiles);
     83  1.1   thorpej 	unchecked = &TAILQ_FIRST(&allfiles);
     84  1.1   thorpej 	TAILQ_INIT(&allobjects);
     85  1.1   thorpej }
     86  1.1   thorpej 
     87  1.1   thorpej void
     88  1.1   thorpej addfile(const char *path, struct nvlist *optx, int flags, const char *rule)
     89  1.1   thorpej {
     90  1.1   thorpej 	struct files *fi;
     91  1.1   thorpej 	const char *dotp, *tail;
     92  1.1   thorpej 	size_t baselen;
     93  1.1   thorpej 	int needc, needf;
     94  1.1   thorpej 	char base[200];
     95  1.1   thorpej 
     96  1.1   thorpej 	/* check various errors */
     97  1.1   thorpej 	needc = flags & FI_NEEDSCOUNT;
     98  1.1   thorpej 	needf = flags & FI_NEEDSFLAG;
     99  1.1   thorpej 	if (needc && needf) {
    100  1.6  christos 		cfgerror("cannot mix needs-count and needs-flag");
    101  1.1   thorpej 		goto bad;
    102  1.1   thorpej 	}
    103  1.1   thorpej 	if (optx == NULL && (needc || needf)) {
    104  1.6  christos 		cfgerror("nothing to %s for %s", needc ? "count" : "flag",
    105  1.6  christos 		    path);
    106  1.1   thorpej 		goto bad;
    107  1.1   thorpej 	}
    108  1.1   thorpej 
    109  1.1   thorpej 	/* find last part of pathname, and same without trailing suffix */
    110  1.1   thorpej 	tail = strrchr(path, '/');
    111  1.1   thorpej 	if (tail == NULL)
    112  1.1   thorpej 		tail = path;
    113  1.1   thorpej 	else
    114  1.1   thorpej 		tail++;
    115  1.1   thorpej 	dotp = strrchr(tail, '.');
    116  1.1   thorpej 	if (dotp == NULL || dotp[1] == 0 ||
    117  1.1   thorpej 	    (baselen = dotp - tail) >= sizeof(base)) {
    118  1.6  christos 		cfgerror("invalid pathname `%s'", path);
    119  1.1   thorpej 		goto bad;
    120  1.1   thorpej 	}
    121  1.1   thorpej 
    122  1.1   thorpej 	/*
    123  1.1   thorpej 	 * Commit this file to memory.  We will decide later whether it
    124  1.1   thorpej 	 * will be used after all.
    125  1.1   thorpej 	 */
    126  1.1   thorpej 	fi = ecalloc(1, sizeof *fi);
    127  1.1   thorpej 	if (ht_insert(pathtab, path, fi)) {
    128  1.1   thorpej 		free(fi);
    129  1.1   thorpej 		if ((fi = ht_lookup(pathtab, path)) == NULL)
    130  1.1   thorpej 			panic("addfile: ht_lookup(%s)", path);
    131  1.1   thorpej 
    132  1.1   thorpej 		/*
    133  1.1   thorpej 		 * If it's a duplicate entry, it is must specify a make
    134  1.1   thorpej 		 * rule, and only a make rule, and must come from
    135  1.1   thorpej 		 * a different source file than the original entry.
    136  1.1   thorpej 		 * If it does otherwise, it is disallowed.  This allows
    137  1.1   thorpej 		 * machine-dependent files to override the compilation
    138  1.1   thorpej 		 * options for specific files.
    139  1.1   thorpej 		 */
    140  1.1   thorpej 		if (rule != NULL && optx == NULL && flags == 0 &&
    141  1.1   thorpej 		    yyfile != fi->fi_srcfile) {
    142  1.1   thorpej 			fi->fi_mkrule = rule;
    143  1.1   thorpej 			return;
    144  1.1   thorpej 		}
    145  1.6  christos 		cfgerror("duplicate file %s", path);
    146  1.6  christos 		cfgxerror(fi->fi_srcfile, fi->fi_srcline,
    147  1.1   thorpej 		    "here is the original definition");
    148  1.1   thorpej 		goto bad;
    149  1.1   thorpej 	}
    150  1.1   thorpej 	memcpy(base, tail, baselen);
    151  1.1   thorpej 	base[baselen] = 0;
    152  1.1   thorpej 	fi->fi_srcfile = yyfile;
    153  1.1   thorpej 	fi->fi_srcline = currentline();
    154  1.1   thorpej 	fi->fi_flags = flags;
    155  1.1   thorpej 	fi->fi_path = path;
    156  1.1   thorpej 	fi->fi_tail = tail;
    157  1.1   thorpej 	fi->fi_base = intern(base);
    158  1.1   thorpej 	fi->fi_prefix = SLIST_EMPTY(&prefixes) ? NULL :
    159  1.1   thorpej 			SLIST_FIRST(&prefixes)->pf_prefix;
    160  1.1   thorpej 	fi->fi_optx = optx;
    161  1.1   thorpej 	fi->fi_optf = NULL;
    162  1.1   thorpej 	fi->fi_mkrule = rule;
    163  1.1   thorpej 	TAILQ_INSERT_TAIL(&allfiles, fi, fi_next);
    164  1.1   thorpej 	return;
    165  1.1   thorpej  bad:
    166  1.1   thorpej 	expr_free(optx);
    167  1.1   thorpej }
    168  1.1   thorpej 
    169  1.1   thorpej void
    170  1.1   thorpej addobject(const char *path, struct nvlist *optx, int flags)
    171  1.1   thorpej {
    172  1.1   thorpej 	struct objects *oi;
    173  1.1   thorpej 
    174  1.1   thorpej 	/*
    175  1.1   thorpej 	 * Commit this object to memory.  We will decide later whether it
    176  1.1   thorpej 	 * will be used after all.
    177  1.1   thorpej 	 */
    178  1.1   thorpej 	oi = ecalloc(1, sizeof *oi);
    179  1.1   thorpej 	if (ht_insert(pathtab, path, oi)) {
    180  1.1   thorpej 		free(oi);
    181  1.1   thorpej 		if ((oi = ht_lookup(pathtab, path)) == NULL)
    182  1.1   thorpej 			panic("addfile: ht_lookup(%s)", path);
    183  1.6  christos 		cfgerror("duplicate file %s", path);
    184  1.6  christos 		cfgxerror(oi->oi_srcfile, oi->oi_srcline,
    185  1.1   thorpej 		    "here is the original definition");
    186  1.1   thorpej 	}
    187  1.1   thorpej 	oi->oi_srcfile = yyfile;
    188  1.1   thorpej 	oi->oi_srcline = currentline();
    189  1.1   thorpej 	oi->oi_flags = flags;
    190  1.1   thorpej 	oi->oi_path = path;
    191  1.1   thorpej 	oi->oi_prefix = SLIST_EMPTY(&prefixes) ? NULL :
    192  1.1   thorpej 			SLIST_FIRST(&prefixes)->pf_prefix;
    193  1.1   thorpej 	oi->oi_optx = optx;
    194  1.1   thorpej 	oi->oi_optf = NULL;
    195  1.1   thorpej 	TAILQ_INSERT_TAIL(&allobjects, oi, oi_next);
    196  1.1   thorpej 	return;
    197  1.1   thorpej }
    198  1.1   thorpej 
    199  1.1   thorpej /*
    200  1.1   thorpej  * We have finished reading some "files" file, either ../../conf/files
    201  1.1   thorpej  * or ./files.$machine.  Make sure that everything that is flagged as
    202  1.1   thorpej  * needing a count is reasonable.  (This prevents ../../conf/files from
    203  1.1   thorpej  * depending on some machine-specific device.)
    204  1.1   thorpej  */
    205  1.1   thorpej void
    206  1.1   thorpej checkfiles(void)
    207  1.1   thorpej {
    208  1.1   thorpej 	struct files *fi, *last;
    209  1.1   thorpej 
    210  1.1   thorpej 	last = NULL;
    211  1.1   thorpej 	for (fi = *unchecked; fi != NULL;
    212  1.1   thorpej 	    last = fi, fi = TAILQ_NEXT(fi, fi_next)) {
    213  1.1   thorpej 		if ((fi->fi_flags & FI_NEEDSCOUNT) != 0)
    214  1.1   thorpej 			(void)expr_eval(fi->fi_optx, checkaux, fi);
    215  1.1   thorpej 	}
    216  1.1   thorpej 	if (last != NULL)
    217  1.1   thorpej 		unchecked = &TAILQ_NEXT(last, fi_next);
    218  1.1   thorpej }
    219  1.1   thorpej 
    220  1.1   thorpej /*
    221  1.1   thorpej  * Auxiliary function for checkfiles, called from expr_eval.
    222  1.1   thorpej  * We are not actually interested in the expression's value.
    223  1.1   thorpej  */
    224  1.1   thorpej static int
    225  1.1   thorpej checkaux(const char *name, void *context)
    226  1.1   thorpej {
    227  1.1   thorpej 	struct files *fi = context;
    228  1.1   thorpej 
    229  1.1   thorpej 	if (ht_lookup(devbasetab, name) == NULL) {
    230  1.6  christos 		cfgxerror(fi->fi_srcfile, fi->fi_srcline,
    231  1.1   thorpej 		    "`%s' is not a countable device",
    232  1.1   thorpej 		    name);
    233  1.1   thorpej 		/* keep fixfiles() from complaining again */
    234  1.1   thorpej 		fi->fi_flags |= FI_HIDDEN;
    235  1.1   thorpej 	}
    236  1.1   thorpej 	return (0);
    237  1.1   thorpej }
    238  1.1   thorpej 
    239  1.1   thorpej /*
    240  1.1   thorpej  * We have finished reading everything.  Tack the files down: calculate
    241  1.1   thorpej  * selection and counts as needed.  Check that the object files built
    242  1.1   thorpej  * from the selected sources do not collide.
    243  1.1   thorpej  */
    244  1.1   thorpej int
    245  1.1   thorpej fixfiles(void)
    246  1.1   thorpej {
    247  1.1   thorpej 	struct files *fi, *ofi;
    248  1.1   thorpej 	struct nvlist *flathead, **flatp;
    249  1.1   thorpej 	int err, sel;
    250  1.1   thorpej 
    251  1.1   thorpej 	err = 0;
    252  1.1   thorpej 	TAILQ_FOREACH(fi, &allfiles, fi_next) {
    253  1.2       erh 
    254  1.1   thorpej 		/* Skip files that generated counted-device complaints. */
    255  1.1   thorpej 		if (fi->fi_flags & FI_HIDDEN)
    256  1.1   thorpej 			continue;
    257  1.1   thorpej 
    258  1.1   thorpej 		/* Optional: see if it is to be included. */
    259  1.2       erh 		if (fi->fi_flags & FIT_FORCESELECT)
    260  1.2       erh 		{
    261  1.2       erh 			/* include it */ ;
    262  1.2       erh 		}
    263  1.2       erh 		else if (fi->fi_optx != NULL) {
    264  1.1   thorpej 			flathead = NULL;
    265  1.1   thorpej 			flatp = &flathead;
    266  1.1   thorpej 			sel = expr_eval(fi->fi_optx,
    267  1.1   thorpej 			    fi->fi_flags & FI_NEEDSCOUNT ? fixcount :
    268  1.1   thorpej 			    fi->fi_flags & FI_NEEDSFLAG ? fixfsel :
    269  1.1   thorpej 			    fixsel,
    270  1.1   thorpej 			    &flatp);
    271  1.1   thorpej 			fi->fi_optf = flathead;
    272  1.1   thorpej 			if (!sel)
    273  1.1   thorpej 				continue;
    274  1.1   thorpej 		}
    275  1.1   thorpej 
    276  1.1   thorpej 		/* We like this file.  Make sure it generates a unique .o. */
    277  1.1   thorpej 		if (ht_insert(basetab, fi->fi_base, fi)) {
    278  1.1   thorpej 			if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL)
    279  1.1   thorpej 				panic("fixfiles ht_lookup(%s)", fi->fi_base);
    280  1.1   thorpej 			/*
    281  1.1   thorpej 			 * If the new file comes from a different source,
    282  1.1   thorpej 			 * allow the new one to override the old one.
    283  1.1   thorpej 			 */
    284  1.1   thorpej 			if (fi->fi_path != ofi->fi_path) {
    285  1.1   thorpej 				if (ht_replace(basetab, fi->fi_base, fi) != 1)
    286  1.1   thorpej 					panic("fixfiles ht_replace(%s)",
    287  1.1   thorpej 					    fi->fi_base);
    288  1.1   thorpej 				ofi->fi_flags &= ~FI_SEL;
    289  1.1   thorpej 				ofi->fi_flags |= FI_HIDDEN;
    290  1.1   thorpej 			} else {
    291  1.6  christos 				cfgxerror(fi->fi_srcfile, fi->fi_srcline,
    292  1.1   thorpej 				    "object file collision on %s.o, from %s",
    293  1.1   thorpej 				    fi->fi_base, fi->fi_path);
    294  1.6  christos 				cfgxerror(ofi->fi_srcfile, ofi->fi_srcline,
    295  1.1   thorpej 				    "here is the previous file: %s",
    296  1.1   thorpej 				    ofi->fi_path);
    297  1.1   thorpej 				err = 1;
    298  1.1   thorpej 			}
    299  1.1   thorpej 		}
    300  1.1   thorpej 		fi->fi_flags |= FI_SEL;
    301  1.1   thorpej 	}
    302  1.1   thorpej 	return (err);
    303  1.1   thorpej }
    304  1.1   thorpej 
    305  1.1   thorpej /*
    306  1.1   thorpej  * We have finished reading everything.  Tack the objects down: calculate
    307  1.1   thorpej  * selection.
    308  1.1   thorpej  */
    309  1.1   thorpej int
    310  1.1   thorpej fixobjects(void)
    311  1.1   thorpej {
    312  1.1   thorpej 	struct objects *oi;
    313  1.1   thorpej 	struct nvlist *flathead, **flatp;
    314  1.1   thorpej 	int err, sel;
    315  1.1   thorpej 
    316  1.1   thorpej 	err = 0;
    317  1.1   thorpej 	TAILQ_FOREACH(oi, &allobjects, oi_next) {
    318  1.1   thorpej 		/* Optional: see if it is to be included. */
    319  1.1   thorpej 		if (oi->oi_optx != NULL) {
    320  1.1   thorpej 			flathead = NULL;
    321  1.1   thorpej 			flatp = &flathead;
    322  1.1   thorpej 			sel = expr_eval(oi->oi_optx,
    323  1.1   thorpej 			    oi->oi_flags & OI_NEEDSFLAG ? fixfsel :
    324  1.1   thorpej 			    fixsel,
    325  1.1   thorpej 			    &flatp);
    326  1.1   thorpej 			oi->oi_optf = flathead;
    327  1.1   thorpej 			if (!sel)
    328  1.1   thorpej 				continue;
    329  1.1   thorpej 		}
    330  1.1   thorpej 
    331  1.1   thorpej 		oi->oi_flags |= OI_SEL;
    332  1.1   thorpej 	}
    333  1.1   thorpej 	return (err);
    334  1.1   thorpej }
    335  1.1   thorpej 
    336  1.1   thorpej /*
    337  1.1   thorpej  * We have finished reading everything.  Tack the devsws down: calculate
    338  1.1   thorpej  * selection.
    339  1.1   thorpej  */
    340  1.1   thorpej int
    341  1.1   thorpej fixdevsw(void)
    342  1.1   thorpej {
    343  1.5       alc 	int error;
    344  1.1   thorpej 	struct devm *dm, *res;
    345  1.1   thorpej 	struct hashtab *fixdevmtab;
    346  1.1   thorpej 	char mstr[16];
    347  1.1   thorpej 
    348  1.5       alc 	error = 0;
    349  1.1   thorpej 	fixdevmtab = ht_new();
    350  1.1   thorpej 
    351  1.1   thorpej 	TAILQ_FOREACH(dm, &alldevms, dm_next) {
    352  1.1   thorpej 		res = ht_lookup(fixdevmtab, intern(dm->dm_name));
    353  1.1   thorpej 		if (res != NULL) {
    354  1.1   thorpej 			if (res->dm_cmajor != dm->dm_cmajor ||
    355  1.1   thorpej 			    res->dm_bmajor != dm->dm_bmajor) {
    356  1.6  christos 				cfgxerror(res->dm_srcfile, res->dm_srcline,
    357  1.7       dsl 					"device-major '%s' "
    358  1.7       dsl 					"block %d, char %d redefined"
    359  1.7       dsl 					" at %s:%d as block %d, char %d",
    360  1.7       dsl 					res->dm_name,
    361  1.7       dsl 					res->dm_bmajor, res->dm_cmajor,
    362  1.7       dsl 					dm->dm_srcfile, dm->dm_srcline,
    363  1.7       dsl 					dm->dm_bmajor, dm->dm_cmajor);
    364  1.1   thorpej 			} else {
    365  1.7       dsl 				cfgxerror(res->dm_srcfile, res->dm_srcline,
    366  1.7       dsl 					"device-major '%s' "
    367  1.7       dsl 					"(block %d, char %d) duplicated"
    368  1.7       dsl 					" at %s:%d",
    369  1.7       dsl 					dm->dm_name, dm->dm_bmajor,
    370  1.7       dsl 					dm->dm_cmajor,
    371  1.7       dsl 					dm->dm_srcfile, dm->dm_srcline);
    372  1.1   thorpej 			}
    373  1.7       dsl 			error = 1;
    374  1.7       dsl 			goto out;
    375  1.1   thorpej 		}
    376  1.1   thorpej 		if (ht_insert(fixdevmtab, intern(dm->dm_name), dm)) {
    377  1.1   thorpej 			panic("fixdevsw: %s char %d block %d",
    378  1.1   thorpej 			      dm->dm_name, dm->dm_cmajor, dm->dm_bmajor);
    379  1.1   thorpej 		}
    380  1.1   thorpej 
    381  1.1   thorpej 		if (dm->dm_opts != NULL &&
    382  1.1   thorpej 		    !expr_eval(dm->dm_opts, fixsel, NULL))
    383  1.1   thorpej 			continue;
    384  1.1   thorpej 
    385  1.9  drochner 		if (dm->dm_cmajor != NODEVMAJOR) {
    386  1.1   thorpej 			if (ht_lookup(cdevmtab, intern(dm->dm_name)) != NULL) {
    387  1.6  christos 				cfgxerror(dm->dm_srcfile, dm->dm_srcline,
    388  1.1   thorpej 				       "device-major of character device '%s' "
    389  1.1   thorpej 				       "is already defined", dm->dm_name);
    390  1.5       alc 				error = 1;
    391  1.4  christos 				goto out;
    392  1.1   thorpej 			}
    393  1.1   thorpej 			(void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_cmajor);
    394  1.1   thorpej 			if (ht_lookup(cdevmtab, intern(mstr)) != NULL) {
    395  1.6  christos 				cfgxerror(dm->dm_srcfile, dm->dm_srcline,
    396  1.1   thorpej 				       "device-major of character major '%d' "
    397  1.1   thorpej 				       "is already defined", dm->dm_cmajor);
    398  1.5       alc 				error = 1;
    399  1.4  christos 				goto out;
    400  1.1   thorpej 			}
    401  1.1   thorpej 			if (ht_insert(cdevmtab, intern(dm->dm_name), dm) ||
    402  1.1   thorpej 			    ht_insert(cdevmtab, intern(mstr), dm)) {
    403  1.1   thorpej 				panic("fixdevsw: %s character major %d",
    404  1.1   thorpej 				      dm->dm_name, dm->dm_cmajor);
    405  1.1   thorpej 			}
    406  1.1   thorpej 		}
    407  1.9  drochner 		if (dm->dm_bmajor != NODEVMAJOR) {
    408  1.1   thorpej 			if (ht_lookup(bdevmtab, intern(dm->dm_name)) != NULL) {
    409  1.6  christos 				cfgxerror(dm->dm_srcfile, dm->dm_srcline,
    410  1.1   thorpej 				       "device-major of block device '%s' "
    411  1.1   thorpej 				       "is already defined", dm->dm_name);
    412  1.5       alc 				error = 1;
    413  1.4  christos 				goto out;
    414  1.1   thorpej 			}
    415  1.1   thorpej 			(void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_bmajor);
    416  1.1   thorpej 			if (ht_lookup(bdevmtab, intern(mstr)) != NULL) {
    417  1.6  christos 				cfgxerror(dm->dm_srcfile, dm->dm_srcline,
    418  1.1   thorpej 				       "device-major of block major '%d' "
    419  1.1   thorpej 				       "is already defined", dm->dm_bmajor);
    420  1.5       alc 				error = 1;
    421  1.4  christos 				goto out;
    422  1.1   thorpej 			}
    423  1.1   thorpej 			if (ht_insert(bdevmtab, intern(dm->dm_name), dm) ||
    424  1.1   thorpej 			    ht_insert(bdevmtab, intern(mstr), dm)) {
    425  1.1   thorpej 				panic("fixdevsw: %s block major %d",
    426  1.1   thorpej 				      dm->dm_name, dm->dm_bmajor);
    427  1.1   thorpej 			}
    428  1.1   thorpej 		}
    429  1.1   thorpej 	}
    430  1.1   thorpej 
    431  1.4  christos out:
    432  1.4  christos 	ht_free(fixdevmtab);
    433  1.5       alc 	return (error);
    434  1.1   thorpej }
    435  1.1   thorpej 
    436  1.1   thorpej /*
    437  1.1   thorpej  * Called when evaluating a needs-count expression.  Make sure the
    438  1.1   thorpej  * atom is a countable device.  The expression succeeds iff there
    439  1.1   thorpej  * is at least one of them (note that while `xx*' will not always
    440  1.1   thorpej  * set xx's d_umax > 0, you cannot mix '*' and needs-count).  The
    441  1.1   thorpej  * mkheaders() routine wants a flattened, in-order list of the
    442  1.1   thorpej  * atoms for `#define name value' lines, so we build that as we
    443  1.1   thorpej  * are called to eval each atom.
    444  1.1   thorpej  */
    445  1.1   thorpej static int
    446  1.1   thorpej fixcount(const char *name, void *context)
    447  1.1   thorpej {
    448  1.1   thorpej 	struct nvlist ***p = context;
    449  1.1   thorpej 	struct devbase *dev;
    450  1.1   thorpej 	struct nvlist *nv;
    451  1.1   thorpej 
    452  1.1   thorpej 	dev = ht_lookup(devbasetab, name);
    453  1.1   thorpej 	if (dev == NULL)	/* cannot occur here; we checked earlier */
    454  1.1   thorpej 		panic("fixcount(%s)", name);
    455  1.1   thorpej 	nv = newnv(name, NULL, NULL, dev->d_umax, NULL);
    456  1.1   thorpej 	**p = nv;
    457  1.1   thorpej 	*p = &nv->nv_next;
    458  1.1   thorpej 	(void)ht_insert(needcnttab, name, nv);
    459  1.1   thorpej 	return (dev->d_umax != 0);
    460  1.1   thorpej }
    461  1.1   thorpej 
    462  1.1   thorpej /*
    463  1.1   thorpej  * Called from fixfiles when eval'ing a selection expression for a
    464  1.1   thorpej  * file that will generate a .h with flags.  We will need the flat list.
    465  1.1   thorpej  */
    466  1.1   thorpej static int
    467  1.1   thorpej fixfsel(const char *name, void *context)
    468  1.1   thorpej {
    469  1.1   thorpej 	struct nvlist ***p = context;
    470  1.1   thorpej 	struct nvlist *nv;
    471  1.1   thorpej 	int sel;
    472  1.1   thorpej 
    473  1.1   thorpej 	sel = ht_lookup(selecttab, name) != NULL;
    474  1.1   thorpej 	nv = newnv(name, NULL, NULL, sel, NULL);
    475  1.1   thorpej 	**p = nv;
    476  1.1   thorpej 	*p = &nv->nv_next;
    477  1.1   thorpej 	return (sel);
    478  1.1   thorpej }
    479  1.1   thorpej 
    480  1.1   thorpej /*
    481  1.1   thorpej  * As for fixfsel above, but we do not need the flat list.
    482  1.1   thorpej  */
    483  1.1   thorpej static int
    484  1.6  christos /*ARGSUSED*/
    485  1.1   thorpej fixsel(const char *name, void *context)
    486  1.1   thorpej {
    487  1.1   thorpej 
    488  1.1   thorpej 	return (ht_lookup(selecttab, name) != NULL);
    489  1.1   thorpej }
    490  1.1   thorpej 
    491  1.1   thorpej /*
    492  1.1   thorpej  * Eval an expression tree.  Calls the given function on each node,
    493  1.1   thorpej  * passing it the given context & the name; return value is &/|/! of
    494  1.1   thorpej  * results of evaluating atoms.
    495  1.1   thorpej  *
    496  1.1   thorpej  * No short circuiting ever occurs.  fn must return 0 or 1 (otherwise
    497  1.1   thorpej  * our mixing of C's bitwise & boolean here may give surprises).
    498  1.1   thorpej  */
    499  1.1   thorpej static int
    500  1.1   thorpej expr_eval(struct nvlist *expr, int (*fn)(const char *, void *), void *context)
    501  1.1   thorpej {
    502  1.1   thorpej 	int lhs, rhs;
    503  1.1   thorpej 
    504  1.8  christos 	switch (expr->nv_num) {
    505  1.1   thorpej 
    506  1.1   thorpej 	case FX_ATOM:
    507  1.1   thorpej 		return ((*fn)(expr->nv_name, context));
    508  1.1   thorpej 
    509  1.1   thorpej 	case FX_NOT:
    510  1.1   thorpej 		return (!expr_eval(expr->nv_next, fn, context));
    511  1.1   thorpej 
    512  1.1   thorpej 	case FX_AND:
    513  1.1   thorpej 		lhs = expr_eval(expr->nv_ptr, fn, context);
    514  1.1   thorpej 		rhs = expr_eval(expr->nv_next, fn, context);
    515  1.1   thorpej 		return (lhs & rhs);
    516  1.1   thorpej 
    517  1.1   thorpej 	case FX_OR:
    518  1.1   thorpej 		lhs = expr_eval(expr->nv_ptr, fn, context);
    519  1.1   thorpej 		rhs = expr_eval(expr->nv_next, fn, context);
    520  1.1   thorpej 		return (lhs | rhs);
    521  1.1   thorpej 	}
    522  1.8  christos 	panic("expr_eval %lld", expr->nv_num);
    523  1.1   thorpej 	/* NOTREACHED */
    524  1.1   thorpej 	return (0);
    525  1.1   thorpej }
    526  1.1   thorpej 
    527  1.1   thorpej /*
    528  1.1   thorpej  * Free an expression tree.
    529  1.1   thorpej  */
    530  1.1   thorpej static void
    531  1.1   thorpej expr_free(struct nvlist *expr)
    532  1.1   thorpej {
    533  1.1   thorpej 	struct nvlist *rhs;
    534  1.1   thorpej 
    535  1.1   thorpej 	/* This loop traverses down the RHS of each subexpression. */
    536  1.1   thorpej 	for (; expr != NULL; expr = rhs) {
    537  1.8  christos 		switch (expr->nv_num) {
    538  1.1   thorpej 
    539  1.1   thorpej 		/* Atoms and !-exprs have no left hand side. */
    540  1.1   thorpej 		case FX_ATOM:
    541  1.1   thorpej 		case FX_NOT:
    542  1.1   thorpej 			break;
    543  1.1   thorpej 
    544  1.1   thorpej 		/* For AND and OR nodes, free the LHS. */
    545  1.1   thorpej 		case FX_AND:
    546  1.1   thorpej 		case FX_OR:
    547  1.1   thorpej 			expr_free(expr->nv_ptr);
    548  1.1   thorpej 			break;
    549  1.1   thorpej 
    550  1.1   thorpej 		default:
    551  1.8  christos 			panic("expr_free %lld", expr->nv_num);
    552  1.1   thorpej 		}
    553  1.1   thorpej 		rhs = expr->nv_next;
    554  1.1   thorpej 		nvfree(expr);
    555  1.1   thorpej 	}
    556  1.1   thorpej }
    557  1.1   thorpej 
    558  1.1   thorpej #ifdef DEBUG
    559  1.1   thorpej /*
    560  1.1   thorpej  * Print expression tree.
    561  1.1   thorpej  */
    562  1.1   thorpej void
    563  1.1   thorpej prexpr(struct nvlist *expr)
    564  1.1   thorpej {
    565  1.1   thorpej 	static void pr0();
    566  1.1   thorpej 
    567  1.1   thorpej 	printf("expr =");
    568  1.1   thorpej 	pr0(expr);
    569  1.1   thorpej 	printf("\n");
    570  1.1   thorpej 	(void)fflush(stdout);
    571  1.1   thorpej }
    572  1.1   thorpej 
    573  1.1   thorpej static void
    574  1.1   thorpej pr0(struct nvlist *e)
    575  1.1   thorpej {
    576  1.1   thorpej 
    577  1.8  christos 	switch (e->nv_num) {
    578  1.1   thorpej 	case FX_ATOM:
    579  1.1   thorpej 		printf(" %s", e->nv_name);
    580  1.1   thorpej 		return;
    581  1.1   thorpej 	case FX_NOT:
    582  1.1   thorpej 		printf(" (!");
    583  1.1   thorpej 		break;
    584  1.1   thorpej 	case FX_AND:
    585  1.1   thorpej 		printf(" (&");
    586  1.1   thorpej 		break;
    587  1.1   thorpej 	case FX_OR:
    588  1.1   thorpej 		printf(" (|");
    589  1.1   thorpej 		break;
    590  1.1   thorpej 	default:
    591  1.8  christos 		printf(" (?%lld?", e->nv_num);
    592  1.1   thorpej 		break;
    593  1.1   thorpej 	}
    594  1.1   thorpej 	if (e->nv_ptr)
    595  1.1   thorpej 		pr0(e->nv_ptr);
    596  1.1   thorpej 	pr0(e->nv_next);
    597  1.1   thorpej 	printf(")");
    598  1.1   thorpej }
    599  1.1   thorpej #endif
    600