xref: /netbsd-src/usr.bin/config/files.c (revision 6dc5a3c0cc338ce0053da6509f56b11fc2b6ec89)
1*6dc5a3c0Sriastradh /*	$NetBSD: files.c,v 1.38 2024/04/05 00:43:42 riastradh Exp $	*/
25ecc953bSthorpej 
35ecc953bSthorpej /*
45ecc953bSthorpej  * Copyright (c) 1992, 1993
55ecc953bSthorpej  *	The Regents of the University of California.  All rights reserved.
65ecc953bSthorpej  *
75ecc953bSthorpej  * This software was developed by the Computer Systems Engineering group
85ecc953bSthorpej  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
95ecc953bSthorpej  * contributed to Berkeley.
105ecc953bSthorpej  *
115ecc953bSthorpej  * All advertising materials mentioning features or use of this software
125ecc953bSthorpej  * must display the following acknowledgement:
135ecc953bSthorpej  *	This product includes software developed by the University of
145ecc953bSthorpej  *	California, Lawrence Berkeley Laboratories.
155ecc953bSthorpej  *
165ecc953bSthorpej  * Redistribution and use in source and binary forms, with or without
175ecc953bSthorpej  * modification, are permitted provided that the following conditions
185ecc953bSthorpej  * are met:
195ecc953bSthorpej  * 1. Redistributions of source code must retain the above copyright
205ecc953bSthorpej  *    notice, this list of conditions and the following disclaimer.
215ecc953bSthorpej  * 2. Redistributions in binary form must reproduce the above copyright
225ecc953bSthorpej  *    notice, this list of conditions and the following disclaimer in the
235ecc953bSthorpej  *    documentation and/or other materials provided with the distribution.
245ecc953bSthorpej  * 3. Neither the name of the University nor the names of its contributors
255ecc953bSthorpej  *    may be used to endorse or promote products derived from this software
265ecc953bSthorpej  *    without specific prior written permission.
275ecc953bSthorpej  *
285ecc953bSthorpej  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
295ecc953bSthorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
305ecc953bSthorpej  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
315ecc953bSthorpej  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
325ecc953bSthorpej  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
335ecc953bSthorpej  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
345ecc953bSthorpej  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
355ecc953bSthorpej  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
365ecc953bSthorpej  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
375ecc953bSthorpej  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
385ecc953bSthorpej  * SUCH DAMAGE.
395ecc953bSthorpej  *
405ecc953bSthorpej  *	from: @(#)files.c	8.1 (Berkeley) 6/6/93
415ecc953bSthorpej  */
425ecc953bSthorpej 
435ecc953bSthorpej #if HAVE_NBTOOL_CONFIG_H
445ecc953bSthorpej #include "nbtool_config.h"
455ecc953bSthorpej #endif
465ecc953bSthorpej 
47d12b0036Schristos #include <sys/cdefs.h>
48*6dc5a3c0Sriastradh __RCSID("$NetBSD: files.c,v 1.38 2024/04/05 00:43:42 riastradh Exp $");
49d12b0036Schristos 
505ecc953bSthorpej #include <sys/param.h>
51cea9d6a0Suebayasi #include <assert.h>
525ecc953bSthorpej #include <errno.h>
535ecc953bSthorpej #include <stdio.h>
545ecc953bSthorpej #include <stdlib.h>
555ecc953bSthorpej #include <string.h>
56d0fb8901Schristos #include <util.h>
575ecc953bSthorpej #include "defs.h"
585ecc953bSthorpej 
595ecc953bSthorpej extern const char *yyfile;
605ecc953bSthorpej 
619b48d494Suebayasi int nallfiles;
629b48d494Suebayasi size_t nselfiles;
639b48d494Suebayasi struct files **selfiles;
649b48d494Suebayasi 
655ecc953bSthorpej /*
665ecc953bSthorpej  * We check that each full path name is unique.  File base names
675ecc953bSthorpej  * should generally also be unique, e.g., having both a net/xx.c and
685ecc953bSthorpej  * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably
695ecc953bSthorpej  * wrong, but is permitted under some conditions.
705ecc953bSthorpej  */
715ecc953bSthorpej static struct hashtab *basetab;		/* file base names */
725ecc953bSthorpej static struct hashtab *pathtab;		/* full path names */
735ecc953bSthorpej 
745ecc953bSthorpej static struct files **unchecked;
755ecc953bSthorpej 
76fa3d8504Suebayasi static void	addfiletoattr(const char *, struct files *);
775ecc953bSthorpej static int	checkaux(const char *, void *);
785ecc953bSthorpej static int	fixcount(const char *, void *);
795ecc953bSthorpej static int	fixfsel(const char *, void *);
805ecc953bSthorpej static int	fixsel(const char *, void *);
815ecc953bSthorpej 
825ecc953bSthorpej void
initfiles(void)835ecc953bSthorpej initfiles(void)
845ecc953bSthorpej {
855ecc953bSthorpej 
865ecc953bSthorpej 	basetab = ht_new();
875ecc953bSthorpej 	pathtab = ht_new();
885ecc953bSthorpej 	TAILQ_INIT(&allfiles);
890b130540Suebayasi 	TAILQ_INIT(&allcfiles);
900b130540Suebayasi 	TAILQ_INIT(&allsfiles);
910b130540Suebayasi 	TAILQ_INIT(&allofiles);
925ecc953bSthorpej 	unchecked = &TAILQ_FIRST(&allfiles);
935ecc953bSthorpej }
945ecc953bSthorpej 
955ecc953bSthorpej void
addfile(const char * path,struct condexpr * optx,u_char flags,const char * rule)96ca847f03Suebayasi addfile(const char *path, struct condexpr *optx, u_char flags, const char *rule)
975ecc953bSthorpej {
985ecc953bSthorpej 	struct files *fi;
995ecc953bSthorpej 	const char *dotp, *tail;
1005ecc953bSthorpej 	size_t baselen;
101974426ddSuebayasi 	size_t dirlen;
1025ecc953bSthorpej 	int needc, needf;
1035ecc953bSthorpej 	char base[200];
104974426ddSuebayasi 	char dir[MAXPATHLEN];
1055ecc953bSthorpej 
1065ecc953bSthorpej 	/* check various errors */
1075ecc953bSthorpej 	needc = flags & FI_NEEDSCOUNT;
1085ecc953bSthorpej 	needf = flags & FI_NEEDSFLAG;
1095ecc953bSthorpej 	if (needc && needf) {
110c7295a4cSchristos 		cfgerror("cannot mix needs-count and needs-flag");
1115ecc953bSthorpej 		goto bad;
1125ecc953bSthorpej 	}
1135ecc953bSthorpej 	if (optx == NULL && (needc || needf)) {
114c7295a4cSchristos 		cfgerror("nothing to %s for %s", needc ? "count" : "flag",
115c7295a4cSchristos 		    path);
1165ecc953bSthorpej 		goto bad;
1175ecc953bSthorpej 	}
11836644ae2Suebayasi 	if (*path == '/') {
11936644ae2Suebayasi 		cfgerror("path must be relative");
12036644ae2Suebayasi 		goto bad;
12136644ae2Suebayasi 	}
1225ecc953bSthorpej 
1235ecc953bSthorpej 	/* find last part of pathname, and same without trailing suffix */
1245ecc953bSthorpej 	tail = strrchr(path, '/');
125974426ddSuebayasi 	if (tail == NULL) {
126974426ddSuebayasi 		dirlen = 0;
1275ecc953bSthorpej 		tail = path;
128974426ddSuebayasi 	} else {
129974426ddSuebayasi 		dirlen = (size_t)(tail - path);
1305ecc953bSthorpej 		tail++;
131974426ddSuebayasi 	}
132974426ddSuebayasi 	memcpy(dir, path, dirlen);
133974426ddSuebayasi 	dir[dirlen] = '\0';
134974426ddSuebayasi 
1355ecc953bSthorpej 	dotp = strrchr(tail, '.');
1365ecc953bSthorpej 	if (dotp == NULL || dotp[1] == 0 ||
137d12b0036Schristos 	    (baselen = (size_t)(dotp - tail)) >= sizeof(base)) {
138c7295a4cSchristos 		cfgerror("invalid pathname `%s'", path);
1395ecc953bSthorpej 		goto bad;
1405ecc953bSthorpej 	}
1415ecc953bSthorpej 
1425ecc953bSthorpej 	/*
1435ecc953bSthorpej 	 * Commit this file to memory.  We will decide later whether it
1445ecc953bSthorpej 	 * will be used after all.
1455ecc953bSthorpej 	 */
1465ecc953bSthorpej 	fi = ecalloc(1, sizeof *fi);
1475ecc953bSthorpej 	if (ht_insert(pathtab, path, fi)) {
1485ecc953bSthorpej 		free(fi);
1495ecc953bSthorpej 		if ((fi = ht_lookup(pathtab, path)) == NULL)
1505ecc953bSthorpej 			panic("addfile: ht_lookup(%s)", path);
151ca847f03Suebayasi 
152ca847f03Suebayasi 		/*
153ca847f03Suebayasi 		 * If it's a duplicate entry, it is must specify a make
154ca847f03Suebayasi 		 * rule, and only a make rule, and must come from
155ca847f03Suebayasi 		 * a different source file than the original entry.
156ca847f03Suebayasi 		 * If it does otherwise, it is disallowed.  This allows
157ca847f03Suebayasi 		 * machine-dependent files to override the compilation
158ca847f03Suebayasi 		 * options for specific files.
159ca847f03Suebayasi 		 */
160ca847f03Suebayasi 		if (rule != NULL && optx == NULL && flags == 0 &&
16120255392Schristos 		    yyfile != fi->fi_where.w_srcfile) {
162ca847f03Suebayasi 			fi->fi_mkrule = rule;
163ca847f03Suebayasi 			return;
164ca847f03Suebayasi 		}
165c7295a4cSchristos 		cfgerror("duplicate file %s", path);
16620255392Schristos 		cfgxerror(fi->fi_where.w_srcfile, fi->fi_where.w_srcline,
1675ecc953bSthorpej 		    "here is the original definition");
1685ecc953bSthorpej 		goto bad;
1695ecc953bSthorpej 	}
1705ecc953bSthorpej 	memcpy(base, tail, baselen);
171974426ddSuebayasi 	base[baselen] = '\0';
17220255392Schristos 	fi->fi_where.w_srcfile = yyfile;
17320255392Schristos 	fi->fi_where.w_srcline = currentline();
1745ecc953bSthorpej 	fi->fi_flags = flags;
1755ecc953bSthorpej 	fi->fi_path = path;
1765ecc953bSthorpej 	fi->fi_tail = tail;
1775ecc953bSthorpej 	fi->fi_base = intern(base);
178974426ddSuebayasi 	fi->fi_dir = intern(dir);
1795ecc953bSthorpej 	fi->fi_prefix = SLIST_EMPTY(&prefixes) ? NULL :
1805ecc953bSthorpej 			SLIST_FIRST(&prefixes)->pf_prefix;
1812cb009cdSuebayasi 	fi->fi_buildprefix = SLIST_EMPTY(&buildprefixes) ? NULL :
1822cb009cdSuebayasi 			SLIST_FIRST(&buildprefixes)->pf_prefix;
18357751c84Suebayasi 	fi->fi_len = strlen(path);
18457751c84Suebayasi 	fi->fi_suffix = path[fi->fi_len - 1];
1855ecc953bSthorpej 	fi->fi_optx = optx;
1865ecc953bSthorpej 	fi->fi_optf = NULL;
187ca847f03Suebayasi 	fi->fi_mkrule = rule;
188fa3d8504Suebayasi 	fi->fi_attr = NULL;
1899b48d494Suebayasi 	fi->fi_order = (int)nallfiles + (includedepth << 16);
1900b130540Suebayasi 	switch (fi->fi_suffix) {
1910b130540Suebayasi 	case 'c':
1920b130540Suebayasi 		TAILQ_INSERT_TAIL(&allcfiles, fi, fi_snext);
1935ecc953bSthorpej 		TAILQ_INSERT_TAIL(&allfiles, fi, fi_next);
1940b130540Suebayasi 		break;
1950b130540Suebayasi 	case 'S':
1963374c75eSuebayasi 		fi->fi_suffix = 's';
1973374c75eSuebayasi 		/* FALLTHRU */
1980b130540Suebayasi 	case 's':
1990b130540Suebayasi 		TAILQ_INSERT_TAIL(&allsfiles, fi, fi_snext);
2000b130540Suebayasi 		TAILQ_INSERT_TAIL(&allfiles, fi, fi_next);
2010b130540Suebayasi 		break;
2020b130540Suebayasi 	case 'o':
2030b130540Suebayasi 		TAILQ_INSERT_TAIL(&allofiles, fi, fi_snext);
204dc9cfb5dSuebayasi 		TAILQ_INSERT_TAIL(&allfiles, fi, fi_next);
2053374c75eSuebayasi 		break;
2063374c75eSuebayasi 	default:
20720255392Schristos 		cfgxerror(fi->fi_where.w_srcfile, fi->fi_where.w_srcline,
2083374c75eSuebayasi 		    "unknown suffix");
2090b130540Suebayasi 		break;
2100b130540Suebayasi 	}
2119b48d494Suebayasi 	CFGDBG(3, "file added `%s' at order score %d", fi->fi_path, fi->fi_order);
2129b48d494Suebayasi 	nallfiles++;
2135ecc953bSthorpej 	return;
2145ecc953bSthorpej  bad:
215d8da1d60Sdholland 	if (optx != NULL) {
216a551c5e8Sdholland 		condexpr_destroy(optx);
2175ecc953bSthorpej 	}
218d8da1d60Sdholland }
2195ecc953bSthorpej 
220fa3d8504Suebayasi static void
addfiletoattr(const char * name,struct files * fi)221fa3d8504Suebayasi addfiletoattr(const char *name, struct files *fi)
222fa3d8504Suebayasi {
223fa3d8504Suebayasi 	struct attr *a;
224fa3d8504Suebayasi 
225fa3d8504Suebayasi 	a = ht_lookup(attrtab, name);
226adf6a455Suebayasi 	if (a == NULL) {
227adf6a455Suebayasi 		CFGDBG(1, "attr `%s' not found", name);
228adf6a455Suebayasi 	} else {
229fa3d8504Suebayasi 		fi->fi_attr = a;
230adf6a455Suebayasi 		TAILQ_INSERT_TAIL(&a->a_files, fi, fi_anext);
231fa3d8504Suebayasi 	}
232fa3d8504Suebayasi }
233fa3d8504Suebayasi 
2345ecc953bSthorpej /*
2355ecc953bSthorpej  * We have finished reading some "files" file, either ../../conf/files
2365ecc953bSthorpej  * or ./files.$machine.  Make sure that everything that is flagged as
2375ecc953bSthorpej  * needing a count is reasonable.  (This prevents ../../conf/files from
2385ecc953bSthorpej  * depending on some machine-specific device.)
2395ecc953bSthorpej  */
2405ecc953bSthorpej void
checkfiles(void)2415ecc953bSthorpej checkfiles(void)
2425ecc953bSthorpej {
2435ecc953bSthorpej 	struct files *fi, *last;
2445ecc953bSthorpej 
2455ecc953bSthorpej 	last = NULL;
2465ecc953bSthorpej 	for (fi = *unchecked; fi != NULL;
2475ecc953bSthorpej 	    last = fi, fi = TAILQ_NEXT(fi, fi_next)) {
2485ecc953bSthorpej 		if ((fi->fi_flags & FI_NEEDSCOUNT) != 0)
2495ecc953bSthorpej 			(void)expr_eval(fi->fi_optx, checkaux, fi);
2505ecc953bSthorpej 	}
2515ecc953bSthorpej 	if (last != NULL)
2525ecc953bSthorpej 		unchecked = &TAILQ_NEXT(last, fi_next);
2535ecc953bSthorpej }
2545ecc953bSthorpej 
2555ecc953bSthorpej /*
2565ecc953bSthorpej  * Auxiliary function for checkfiles, called from expr_eval.
2575ecc953bSthorpej  * We are not actually interested in the expression's value.
2585ecc953bSthorpej  */
2595ecc953bSthorpej static int
checkaux(const char * name,void * context)2605ecc953bSthorpej checkaux(const char *name, void *context)
2615ecc953bSthorpej {
2625ecc953bSthorpej 	struct files *fi = context;
2635ecc953bSthorpej 
2645ecc953bSthorpej 	if (ht_lookup(devbasetab, name) == NULL) {
26520255392Schristos 		cfgxerror(fi->fi_where.w_srcfile, fi->fi_where.w_srcline,
2665ecc953bSthorpej 		    "`%s' is not a countable device",
2675ecc953bSthorpej 		    name);
2685ecc953bSthorpej 		/* keep fixfiles() from complaining again */
2695ecc953bSthorpej 		fi->fi_flags |= FI_HIDDEN;
2705ecc953bSthorpej 	}
2715ecc953bSthorpej 	return (0);
2725ecc953bSthorpej }
2735ecc953bSthorpej 
2749b48d494Suebayasi static int
cmpfiles(const void * a,const void * b)2759b48d494Suebayasi cmpfiles(const void *a, const void *b)
2769b48d494Suebayasi {
2779b48d494Suebayasi 	const struct files * const *fia = a, * const *fib = b;
2789b48d494Suebayasi 	int sa = (*fia)->fi_order;
2799b48d494Suebayasi 	int sb = (*fib)->fi_order;
2809b48d494Suebayasi 
2819b48d494Suebayasi 	if (sa < sb)
2829b48d494Suebayasi 		return -1;
2839b48d494Suebayasi 	else if (sa > sb)
284*6dc5a3c0Sriastradh 		return +1;
2859b48d494Suebayasi 	else
286*6dc5a3c0Sriastradh 		abort();	/* no ties possible */
2879b48d494Suebayasi }
2889b48d494Suebayasi 
2895ecc953bSthorpej /*
2905ecc953bSthorpej  * We have finished reading everything.  Tack the files down: calculate
2915ecc953bSthorpej  * selection and counts as needed.  Check that the object files built
2925ecc953bSthorpej  * from the selected sources do not collide.
2935ecc953bSthorpej  */
2945ecc953bSthorpej int
fixfiles(void)2955ecc953bSthorpej fixfiles(void)
2965ecc953bSthorpej {
2975ecc953bSthorpej 	struct files *fi, *ofi;
2985ecc953bSthorpej 	struct nvlist *flathead, **flatp;
2995ecc953bSthorpej 	int err, sel;
300bc2bf167Suebayasi 	struct config *cf;
301bc2bf167Suebayasi  	char swapname[100];
3025ecc953bSthorpej 
3039b48d494Suebayasi 	/* Place these files at last. */
3049b48d494Suebayasi 	int onallfiles = nallfiles;
3059b48d494Suebayasi 	nallfiles = 1 << 30;
306bc619545Suebayasi 	addfile("devsw.c", NULL, 0, NULL);
307bc619545Suebayasi 	addfile("ioconf.c", NULL, 0, NULL);
308bc619545Suebayasi 
309b0681745Suebayasi 	TAILQ_FOREACH(cf, &allcf, cf_next) {
310b5b4952dSuebayasi  		(void)snprintf(swapname, sizeof(swapname), "swap%s.c",
311b0681745Suebayasi  		    cf->cf_name);
312b0681745Suebayasi  		addfile(intern(swapname), NULL, 0, NULL);
313b0681745Suebayasi  	}
3149b48d494Suebayasi 	nallfiles = onallfiles;
315b0681745Suebayasi 
3165ecc953bSthorpej 	err = 0;
3175ecc953bSthorpej 	TAILQ_FOREACH(fi, &allfiles, fi_next) {
318cd429362Serh 
3195ecc953bSthorpej 		/* Skip files that generated counted-device complaints. */
3205ecc953bSthorpej 		if (fi->fi_flags & FI_HIDDEN)
3215ecc953bSthorpej 			continue;
3225ecc953bSthorpej 
323b35679c0Suebayasi 		if (fi->fi_optx != NULL) {
324fa3d8504Suebayasi 			if (fi->fi_optx->cx_type == CX_ATOM) {
325fa3d8504Suebayasi 				addfiletoattr(fi->fi_optx->cx_u.atom, fi);
326fa3d8504Suebayasi 			}
3275ecc953bSthorpej 			flathead = NULL;
3285ecc953bSthorpej 			flatp = &flathead;
3295ecc953bSthorpej 			sel = expr_eval(fi->fi_optx,
3305ecc953bSthorpej 			    fi->fi_flags & FI_NEEDSCOUNT ? fixcount :
3315ecc953bSthorpej 			    fi->fi_flags & FI_NEEDSFLAG ? fixfsel :
3325ecc953bSthorpej 			    fixsel,
3335ecc953bSthorpej 			    &flatp);
3345ecc953bSthorpej 			fi->fi_optf = flathead;
3355ecc953bSthorpej 			if (!sel)
3365ecc953bSthorpej 				continue;
3375ecc953bSthorpej 		}
3383a850393Schristos 		if (fi->fi_attr && fi->fi_attr->a_deselected) {
3393a850393Schristos 			CFGDBG(5, "file `%s' deselected because attr `%s' was",
3403a850393Schristos 			    fi->fi_path, fi->fi_attr->a_name);
3413a850393Schristos 			continue;
3423a850393Schristos 		}
3435ecc953bSthorpej 
3445ecc953bSthorpej 		/* We like this file.  Make sure it generates a unique .o. */
3455ecc953bSthorpej 		if (ht_insert(basetab, fi->fi_base, fi)) {
3465ecc953bSthorpej 			if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL)
3475ecc953bSthorpej 				panic("fixfiles ht_lookup(%s)", fi->fi_base);
3485ecc953bSthorpej 			/*
3495ecc953bSthorpej 			 * If the new file comes from a different source,
3505ecc953bSthorpej 			 * allow the new one to override the old one.
3515ecc953bSthorpej 			 */
3525ecc953bSthorpej 			if (fi->fi_path != ofi->fi_path) {
3535ecc953bSthorpej 				if (ht_replace(basetab, fi->fi_base, fi) != 1)
3545ecc953bSthorpej 					panic("fixfiles ht_replace(%s)",
3555ecc953bSthorpej 					    fi->fi_base);
356d12b0036Schristos 				ofi->fi_flags &= (u_char)~FI_SEL;
3575ecc953bSthorpej 				ofi->fi_flags |= FI_HIDDEN;
3585ecc953bSthorpej 			} else {
35920255392Schristos 				cfgxerror(fi->fi_where.w_srcfile, fi->fi_where.w_srcline,
3605ecc953bSthorpej 				    "object file collision on %s.o, from %s",
3615ecc953bSthorpej 				    fi->fi_base, fi->fi_path);
36220255392Schristos 				cfgxerror(ofi->fi_where.w_srcfile, ofi->fi_where.w_srcline,
3635ecc953bSthorpej 				    "here is the previous file: %s",
3645ecc953bSthorpej 				    ofi->fi_path);
3655ecc953bSthorpej 				err = 1;
3665ecc953bSthorpej 			}
3675ecc953bSthorpej 		}
3685ecc953bSthorpej 		fi->fi_flags |= FI_SEL;
3699b48d494Suebayasi 		nselfiles++;
370adf6a455Suebayasi 		CFGDBG(3, "file selected `%s'", fi->fi_path);
371adf6a455Suebayasi 
372adf6a455Suebayasi 		/* Add other files to the default "netbsd" attribute. */
373adf6a455Suebayasi 		if (fi->fi_attr == NULL) {
374adf6a455Suebayasi 			addfiletoattr(allattr.a_name, fi);
375adf6a455Suebayasi 		}
376fa3d8504Suebayasi 		CFGDBG(3, "file `%s' belongs to attr `%s'", fi->fi_path,
377fa3d8504Suebayasi 		    fi->fi_attr->a_name);
3785ecc953bSthorpej 	}
3799b48d494Suebayasi 
3809b48d494Suebayasi 	/* Order files. */
3819b48d494Suebayasi 	selfiles = malloc(nselfiles * sizeof(fi));
38282a183ddSuebayasi 	unsigned i = 0;
3839b48d494Suebayasi 	TAILQ_FOREACH(fi, &allfiles, fi_next) {
3849b48d494Suebayasi 		if ((fi->fi_flags & FI_SEL) == 0)
3859b48d494Suebayasi 			continue;
3869b48d494Suebayasi 		selfiles[i++] = fi;
3879b48d494Suebayasi 	}
388cea9d6a0Suebayasi 	assert(i <= nselfiles);
389cea9d6a0Suebayasi 	nselfiles = i;
3909b48d494Suebayasi 	qsort(selfiles, nselfiles, (unsigned)sizeof(fi), cmpfiles);
3915ecc953bSthorpej 	return (err);
3925ecc953bSthorpej }
3935ecc953bSthorpej 
3945ecc953bSthorpej 
3955ecc953bSthorpej /*
3965ecc953bSthorpej  * We have finished reading everything.  Tack the devsws down: calculate
3975ecc953bSthorpej  * selection.
3985ecc953bSthorpej  */
3995ecc953bSthorpej int
fixdevsw(void)4005ecc953bSthorpej fixdevsw(void)
4015ecc953bSthorpej {
4022f403ebeSalc 	int error;
4035ecc953bSthorpej 	struct devm *dm, *res;
4045ecc953bSthorpej 	struct hashtab *fixdevmtab;
4055ecc953bSthorpej 	char mstr[16];
4065ecc953bSthorpej 
4072f403ebeSalc 	error = 0;
4085ecc953bSthorpej 	fixdevmtab = ht_new();
4095ecc953bSthorpej 
4105ecc953bSthorpej 	TAILQ_FOREACH(dm, &alldevms, dm_next) {
4115ecc953bSthorpej 		res = ht_lookup(fixdevmtab, intern(dm->dm_name));
4125ecc953bSthorpej 		if (res != NULL) {
4135ecc953bSthorpej 			if (res->dm_cmajor != dm->dm_cmajor ||
4145ecc953bSthorpej 			    res->dm_bmajor != dm->dm_bmajor) {
41520255392Schristos 				cfgxerror(res->dm_where.w_srcfile,
41620255392Schristos 				    res->dm_where.w_srcline,
41782225543Sdsl 				    "device-major '%s' "
41882225543Sdsl 				    "block %d, char %d redefined"
41982225543Sdsl 				    " at %s:%d as block %d, char %d",
42082225543Sdsl 				    res->dm_name,
42182225543Sdsl 				    res->dm_bmajor, res->dm_cmajor,
42220255392Schristos 				    dm->dm_where.w_srcfile, dm->dm_where.w_srcline,
4235ecc953bSthorpej 				    dm->dm_bmajor, dm->dm_cmajor);
4245ecc953bSthorpej 			} else {
42520255392Schristos 				cfgxerror(res->dm_where.w_srcfile,
42620255392Schristos 				    res->dm_where.w_srcline,
42782225543Sdsl 				    "device-major '%s' "
42882225543Sdsl 				    "(block %d, char %d) duplicated"
42982225543Sdsl 				    " at %s:%d",
4305ecc953bSthorpej 				    dm->dm_name, dm->dm_bmajor,
43182225543Sdsl 				    dm->dm_cmajor,
43220255392Schristos 				    dm->dm_where.w_srcfile,
43320255392Schristos 				    dm->dm_where.w_srcline);
43482225543Sdsl 			}
4352f403ebeSalc 			error = 1;
436c0156a49Schristos 			goto out;
4375ecc953bSthorpej 		}
4385ecc953bSthorpej 		if (ht_insert(fixdevmtab, intern(dm->dm_name), dm)) {
4395ecc953bSthorpej 			panic("fixdevsw: %s char %d block %d",
4405ecc953bSthorpej 			      dm->dm_name, dm->dm_cmajor, dm->dm_bmajor);
4415ecc953bSthorpej 		}
4425ecc953bSthorpej 
4435ecc953bSthorpej 		if (dm->dm_opts != NULL &&
4445ecc953bSthorpej 		    !expr_eval(dm->dm_opts, fixsel, NULL))
4455ecc953bSthorpej 			continue;
4465ecc953bSthorpej 
447d767912bSdrochner 		if (dm->dm_cmajor != NODEVMAJOR) {
4485ecc953bSthorpej 			if (ht_lookup(cdevmtab, intern(dm->dm_name)) != NULL) {
44920255392Schristos 				cfgxerror(dm->dm_where.w_srcfile,
45020255392Schristos 				    dm->dm_where.w_srcline,
4515ecc953bSthorpej 				   "device-major of character device '%s' "
4525ecc953bSthorpej 				   "is already defined", dm->dm_name);
4532f403ebeSalc 				error = 1;
454c0156a49Schristos 				goto out;
4555ecc953bSthorpej 			}
4565ecc953bSthorpej 			(void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_cmajor);
4575ecc953bSthorpej 			if (ht_lookup(cdevmtab, intern(mstr)) != NULL) {
45820255392Schristos 				cfgxerror(dm->dm_where.w_srcfile, dm->dm_where.w_srcline,
4595ecc953bSthorpej 				       "device-major of character major '%d' "
4605ecc953bSthorpej 				       "is already defined", dm->dm_cmajor);
4612f403ebeSalc 				error = 1;
462c0156a49Schristos 				goto out;
4635ecc953bSthorpej 			}
4645ecc953bSthorpej 			if (ht_insert(cdevmtab, intern(dm->dm_name), dm) ||
4655ecc953bSthorpej 			    ht_insert(cdevmtab, intern(mstr), dm)) {
4665ecc953bSthorpej 				panic("fixdevsw: %s character major %d",
4675ecc953bSthorpej 				      dm->dm_name, dm->dm_cmajor);
4685ecc953bSthorpej 			}
4695ecc953bSthorpej 		}
470d767912bSdrochner 		if (dm->dm_bmajor != NODEVMAJOR) {
4715ecc953bSthorpej 			if (ht_lookup(bdevmtab, intern(dm->dm_name)) != NULL) {
47220255392Schristos 				cfgxerror(dm->dm_where.w_srcfile, dm->dm_where.w_srcline,
4735ecc953bSthorpej 				       "device-major of block device '%s' "
4745ecc953bSthorpej 				       "is already defined", dm->dm_name);
4752f403ebeSalc 				error = 1;
476c0156a49Schristos 				goto out;
4775ecc953bSthorpej 			}
4785ecc953bSthorpej 			(void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_bmajor);
4795ecc953bSthorpej 			if (ht_lookup(bdevmtab, intern(mstr)) != NULL) {
48020255392Schristos 				cfgxerror(dm->dm_where.w_srcfile, dm->dm_where.w_srcline,
4815ecc953bSthorpej 				       "device-major of block major '%d' "
4825ecc953bSthorpej 				       "is already defined", dm->dm_bmajor);
4832f403ebeSalc 				error = 1;
484c0156a49Schristos 				goto out;
4855ecc953bSthorpej 			}
4865ecc953bSthorpej 			if (ht_insert(bdevmtab, intern(dm->dm_name), dm) ||
4875ecc953bSthorpej 			    ht_insert(bdevmtab, intern(mstr), dm)) {
4885ecc953bSthorpej 				panic("fixdevsw: %s block major %d",
4895ecc953bSthorpej 				      dm->dm_name, dm->dm_bmajor);
4905ecc953bSthorpej 			}
4915ecc953bSthorpej 		}
4925ecc953bSthorpej 	}
4935ecc953bSthorpej 
494c0156a49Schristos out:
495c0156a49Schristos 	ht_free(fixdevmtab);
4962f403ebeSalc 	return (error);
4975ecc953bSthorpej }
4985ecc953bSthorpej 
4995ecc953bSthorpej /*
5005ecc953bSthorpej  * Called when evaluating a needs-count expression.  Make sure the
5015ecc953bSthorpej  * atom is a countable device.  The expression succeeds iff there
5025ecc953bSthorpej  * is at least one of them (note that while `xx*' will not always
5035ecc953bSthorpej  * set xx's d_umax > 0, you cannot mix '*' and needs-count).  The
5045ecc953bSthorpej  * mkheaders() routine wants a flattened, in-order list of the
5055ecc953bSthorpej  * atoms for `#define name value' lines, so we build that as we
5065ecc953bSthorpej  * are called to eval each atom.
5075ecc953bSthorpej  */
5085ecc953bSthorpej static int
fixcount(const char * name,void * context)5095ecc953bSthorpej fixcount(const char *name, void *context)
5105ecc953bSthorpej {
5115ecc953bSthorpej 	struct nvlist ***p = context;
5125ecc953bSthorpej 	struct devbase *dev;
5135ecc953bSthorpej 	struct nvlist *nv;
5145ecc953bSthorpej 
5155ecc953bSthorpej 	dev = ht_lookup(devbasetab, name);
5165ecc953bSthorpej 	if (dev == NULL)	/* cannot occur here; we checked earlier */
5175ecc953bSthorpej 		panic("fixcount(%s)", name);
5185ecc953bSthorpej 	nv = newnv(name, NULL, NULL, dev->d_umax, NULL);
5195ecc953bSthorpej 	**p = nv;
5205ecc953bSthorpej 	*p = &nv->nv_next;
5215ecc953bSthorpej 	(void)ht_insert(needcnttab, name, nv);
5225ecc953bSthorpej 	return (dev->d_umax != 0);
5235ecc953bSthorpej }
5245ecc953bSthorpej 
5255ecc953bSthorpej /*
5265ecc953bSthorpej  * Called from fixfiles when eval'ing a selection expression for a
5275ecc953bSthorpej  * file that will generate a .h with flags.  We will need the flat list.
5285ecc953bSthorpej  */
5295ecc953bSthorpej static int
fixfsel(const char * name,void * context)5305ecc953bSthorpej fixfsel(const char *name, void *context)
5315ecc953bSthorpej {
5325ecc953bSthorpej 	struct nvlist ***p = context;
5335ecc953bSthorpej 	struct nvlist *nv;
5345ecc953bSthorpej 	int sel;
5355ecc953bSthorpej 
5365ecc953bSthorpej 	sel = ht_lookup(selecttab, name) != NULL;
5375ecc953bSthorpej 	nv = newnv(name, NULL, NULL, sel, NULL);
5385ecc953bSthorpej 	**p = nv;
5395ecc953bSthorpej 	*p = &nv->nv_next;
5405ecc953bSthorpej 	return (sel);
5415ecc953bSthorpej }
5425ecc953bSthorpej 
5435ecc953bSthorpej /*
5445ecc953bSthorpej  * As for fixfsel above, but we do not need the flat list.
5455ecc953bSthorpej  */
5465ecc953bSthorpej static int
547c7295a4cSchristos /*ARGSUSED*/
fixsel(const char * name,void * context)5485ecc953bSthorpej fixsel(const char *name, void *context)
5495ecc953bSthorpej {
5505ecc953bSthorpej 
5515ecc953bSthorpej 	return (ht_lookup(selecttab, name) != NULL);
5525ecc953bSthorpej }
5535ecc953bSthorpej 
5545ecc953bSthorpej /*
5555ecc953bSthorpej  * Eval an expression tree.  Calls the given function on each node,
5565ecc953bSthorpej  * passing it the given context & the name; return value is &/|/! of
5575ecc953bSthorpej  * results of evaluating atoms.
5585ecc953bSthorpej  *
5595ecc953bSthorpej  * No short circuiting ever occurs.  fn must return 0 or 1 (otherwise
5605ecc953bSthorpej  * our mixing of C's bitwise & boolean here may give surprises).
5615ecc953bSthorpej  */
562a16a6365Scube int
expr_eval(struct condexpr * expr,int (* fn)(const char *,void *),void * ctx)563a551c5e8Sdholland expr_eval(struct condexpr *expr, int (*fn)(const char *, void *), void *ctx)
5645ecc953bSthorpej {
5655ecc953bSthorpej 	int lhs, rhs;
5665ecc953bSthorpej 
567a551c5e8Sdholland 	switch (expr->cx_type) {
5685ecc953bSthorpej 
569a551c5e8Sdholland 	case CX_ATOM:
570a551c5e8Sdholland 		return ((*fn)(expr->cx_atom, ctx));
5715ecc953bSthorpej 
572a551c5e8Sdholland 	case CX_NOT:
573a551c5e8Sdholland 		return (!expr_eval(expr->cx_not, fn, ctx));
5745ecc953bSthorpej 
575a551c5e8Sdholland 	case CX_AND:
576a551c5e8Sdholland 		lhs = expr_eval(expr->cx_and.left, fn, ctx);
577a551c5e8Sdholland 		rhs = expr_eval(expr->cx_and.right, fn, ctx);
5785ecc953bSthorpej 		return (lhs & rhs);
5795ecc953bSthorpej 
580a551c5e8Sdholland 	case CX_OR:
581a551c5e8Sdholland 		lhs = expr_eval(expr->cx_or.left, fn, ctx);
582a551c5e8Sdholland 		rhs = expr_eval(expr->cx_or.right, fn, ctx);
5835ecc953bSthorpej 		return (lhs | rhs);
5845ecc953bSthorpej 	}
585a551c5e8Sdholland 	panic("invalid condexpr type %d", (int)expr->cx_type);
5865ecc953bSthorpej 	/* NOTREACHED */
5875ecc953bSthorpej 	return (0);
5885ecc953bSthorpej }
5895ecc953bSthorpej 
5905ecc953bSthorpej #ifdef DEBUG
5915ecc953bSthorpej /*
5925ecc953bSthorpej  * Print expression tree.
5935ecc953bSthorpej  */
5945ecc953bSthorpej void
prexpr(struct nvlist * expr)5955ecc953bSthorpej prexpr(struct nvlist *expr)
5965ecc953bSthorpej {
5975ecc953bSthorpej 	static void pr0();
5985ecc953bSthorpej 
5995ecc953bSthorpej 	printf("expr =");
6005ecc953bSthorpej 	pr0(expr);
6015ecc953bSthorpej 	printf("\n");
6025ecc953bSthorpej 	(void)fflush(stdout);
6035ecc953bSthorpej }
6045ecc953bSthorpej 
6055ecc953bSthorpej static void
pr0(struct nvlist * e)6065ecc953bSthorpej pr0(struct nvlist *e)
6075ecc953bSthorpej {
6085ecc953bSthorpej 
6090001b928Schristos 	switch (e->nv_num) {
6105ecc953bSthorpej 	case FX_ATOM:
6115ecc953bSthorpej 		printf(" %s", e->nv_name);
6125ecc953bSthorpej 		return;
6135ecc953bSthorpej 	case FX_NOT:
6145ecc953bSthorpej 		printf(" (!");
6155ecc953bSthorpej 		break;
6165ecc953bSthorpej 	case FX_AND:
6175ecc953bSthorpej 		printf(" (&");
6185ecc953bSthorpej 		break;
6195ecc953bSthorpej 	case FX_OR:
6205ecc953bSthorpej 		printf(" (|");
6215ecc953bSthorpej 		break;
6225ecc953bSthorpej 	default:
6230001b928Schristos 		printf(" (?%lld?", e->nv_num);
6245ecc953bSthorpej 		break;
6255ecc953bSthorpej 	}
6265ecc953bSthorpej 	if (e->nv_ptr)
6275ecc953bSthorpej 		pr0(e->nv_ptr);
6285ecc953bSthorpej 	pr0(e->nv_next);
6295ecc953bSthorpej 	printf(")");
6305ecc953bSthorpej }
6315ecc953bSthorpej #endif
632