xref: /openbsd-src/usr.sbin/config/files.c (revision a4afd6dad3fba28f80e70208181c06c482259988)
1 /*	$OpenBSD: files.c,v 1.5 1996/08/29 03:33:05 deraadt Exp $	*/
2 /*	$NetBSD: files.c,v 1.6 1996/03/17 13:18:17 cgd Exp $	*/
3 
4 /*
5  * Copyright (c) 1992, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This software was developed by the Computer Systems Engineering group
9  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
10  * contributed to Berkeley.
11  *
12  * All advertising materials mentioning features or use of this software
13  * must display the following acknowledgement:
14  *	This product includes software developed by the University of
15  *	California, Lawrence Berkeley Laboratories.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  *    notice, this list of conditions and the following disclaimer in the
24  *    documentation and/or other materials provided with the distribution.
25  * 3. All advertising materials mentioning features or use of this software
26  *    must display the following acknowledgement:
27  *	This product includes software developed by the University of
28  *	California, Berkeley and its contributors.
29  * 4. Neither the name of the University nor the names of its contributors
30  *    may be used to endorse or promote products derived from this software
31  *    without specific prior written permission.
32  *
33  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
34  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
37  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43  * SUCH DAMAGE.
44  *
45  *	from: @(#)files.c	8.1 (Berkeley) 6/6/93
46  */
47 
48 #include <sys/param.h>
49 #include <errno.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include "config.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 **nextfile;
67 static struct files **unchecked;
68 
69 static int	checkaux __P((const char *, void *));
70 static int	fixcount __P((const char *, void *));
71 static int	fixfsel __P((const char *, void *));
72 static int	fixsel __P((const char *, void *));
73 static int	expr_eval __P((struct nvlist *,
74 		    int (*)(const char *, void *), void *));
75 static void	expr_free __P((struct nvlist *));
76 
77 void
78 initfiles()
79 {
80 
81 	basetab = ht_new();
82 	pathtab = ht_new();
83 	nextfile = &allfiles;
84 	unchecked = &allfiles;
85 }
86 
87 #if 0
88 static void
89 showprev(pref, fi)
90 	const char *pref;
91 	register struct files *fi;
92 {
93 
94 	xerror(fi->fi_srcfile, fi->fi_srcline,
95 	    "%sfile %s ...", pref, fi->fi_path);
96 	errors--;
97 }
98 #endif
99 
100 void
101 addfile(path, optx, flags, rule)
102 	const char *path;
103 	struct nvlist *optx;
104 	int flags;
105 	const char *rule;
106 {
107 	struct files *fi;
108 	const char *dotp, *tail;
109 	size_t baselen;
110 	int needc, needf;
111 	char base[200];
112 
113 	/* check various errors */
114 	needc = flags & FI_NEEDSCOUNT;
115 	needf = flags & FI_NEEDSFLAG;
116 	if (needc && needf) {
117 		error("cannot mix needs-count and needs-flag");
118 		goto bad;
119 	}
120 	if (optx == NULL && (needc || needf)) {
121 		error("nothing to %s for %s", needc ? "count" : "flag", path);
122 		goto bad;
123 	}
124 
125 	/* find last part of pathname, and same without trailing suffix */
126 	tail = rindex(path, '/');
127 	if (tail == NULL)
128 		tail = path;
129 	else
130 		tail++;
131 	dotp = rindex(tail, '.');
132 	if (dotp == NULL || dotp[1] == 0 ||
133 	    (baselen = dotp - tail) >= sizeof(base)) {
134 		error("invalid pathname `%s'", path);
135 		goto bad;
136 	}
137 
138 	/*
139 	 * Commit this file to memory.  We will decide later whether it
140 	 * will be used after all.
141 	 */
142 	fi = emalloc(sizeof *fi);
143 	if (ht_insert(pathtab, path, fi)) {
144 		free(fi);
145 		if ((fi = ht_lookup(pathtab, path)) == NULL)
146 			panic("addfile: ht_lookup(%s)", path);
147 		error("duplicate file %s", path);
148 		xerror(fi->fi_srcfile, fi->fi_srcline,
149 		    "here is the original definition");
150 	}
151 	memcpy(base, tail, baselen);
152 	base[baselen] = 0;
153 	fi->fi_next = NULL;
154 	fi->fi_srcfile = yyfile;
155 	fi->fi_srcline = currentline();
156 	fi->fi_flags = flags;
157 	fi->fi_path = path;
158 	fi->fi_tail = tail;
159 	fi->fi_base = intern(base);
160 	fi->fi_optx = optx;
161 	fi->fi_optf = NULL;
162 	fi->fi_mkrule = rule;
163 	*nextfile = fi;
164 	nextfile = &fi->fi_next;
165 	return;
166 bad:
167 	expr_free(optx);
168 }
169 
170 /*
171  * We have finished reading some "files" file, either ../../conf/files
172  * or ./files.$machine.  Make sure that everything that is flagged as
173  * needing a count is reasonable.  (This prevents ../../conf/files from
174  * depending on some machine-specific device.)
175  */
176 void
177 checkfiles()
178 {
179 	register struct files *fi, *last;
180 	/*register struct nvlist *nv;*/
181 
182 	last = NULL;
183 	for (fi = *unchecked; fi != NULL; last = fi, fi = fi->fi_next)
184 		if ((fi->fi_flags & FI_NEEDSCOUNT) != 0)
185 			(void)expr_eval(fi->fi_optx, checkaux, fi);
186 	if (last != NULL)
187 		unchecked = &last->fi_next;
188 }
189 
190 /*
191  * Auxiliary function for checkfiles, called from expr_eval.
192  * We are not actually interested in the expression's value.
193  */
194 static int
195 checkaux(name, context)
196 	const char *name;
197 	void *context;
198 {
199 	register struct files *fi = context;
200 
201 	if (ht_lookup(devbasetab, name) == NULL) {
202 		xerror(fi->fi_srcfile, fi->fi_srcline,
203 		    "`%s' is not a countable device",
204 		    name);
205 		/* keep fixfiles() from complaining again */
206 		fi->fi_flags |= FI_HIDDEN;
207 	}
208 	return (0);
209 }
210 
211 /*
212  * We have finished reading everything.  Tack the files down: calculate
213  * selection and counts as needed.  Check that the object files built
214  * from the selected sources do not collide.
215  */
216 int
217 fixfiles()
218 {
219 	register struct files *fi, *ofi;
220 	struct nvlist *flathead, **flatp;
221 	int err, sel;
222 
223 	err = 0;
224 	for (fi = allfiles; fi != NULL; fi = fi->fi_next) {
225 		/* Skip files that generated counted-device complaints. */
226 		if (fi->fi_flags & FI_HIDDEN)
227 			continue;
228 		if (fi->fi_optx != NULL) {
229 			/* Optional: see if it is to be included. */
230 			flathead = NULL;
231 			flatp = &flathead;
232 			sel = expr_eval(fi->fi_optx,
233 			    fi->fi_flags & FI_NEEDSCOUNT ? fixcount :
234 			    fi->fi_flags & FI_NEEDSFLAG ? fixfsel :
235 			    fixsel,
236 			    &flatp);
237 			fi->fi_optf = flathead;
238 			if (!sel)
239 				continue;
240 		}
241 
242 		/* We like this file.  Make sure it generates a unique .o. */
243 		if (ht_insert(basetab, fi->fi_base, fi)) {
244 			if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL)
245 				panic("fixfiles ht_lookup(%s)", fi->fi_base);
246 			/*
247 			 * If the new file comes from a different source,
248 			 * allow the new one to override the old one.
249 			 */
250 			if (fi->fi_path != ofi->fi_path) {
251 				if (ht_replace(basetab, fi->fi_base, fi) != 1)
252 					panic("fixfiles ht_replace(%s)",
253 					    fi->fi_base);
254 				ofi->fi_flags &= ~FI_SEL;
255 				ofi->fi_flags |= FI_HIDDEN;
256 			} else {
257 				xerror(fi->fi_srcfile, fi->fi_srcline,
258 				    "object file collision on %s.o, from %s",
259 				    fi->fi_base, fi->fi_path);
260 				xerror(ofi->fi_srcfile, ofi->fi_srcline,
261 				    "here is the previous file: %s",
262 				    ofi->fi_path);
263 				err = 1;
264 			}
265 		}
266 		fi->fi_flags |= FI_SEL;
267 	}
268 	return (err);
269 }
270 
271 /*
272  * Called when evaluating a needs-count expression.  Make sure the
273  * atom is a countable device.  The expression succeeds iff there
274  * is at least one of them (note that while `xx*' will not always
275  * set xx's d_umax > 0, you cannot mix '*' and needs-count).  The
276  * mkheaders() routine wants a flattened, in-order list of the
277  * atoms for `#define name value' lines, so we build that as we
278  * are called to eval each atom.
279  */
280 static int
281 fixcount(name, context)
282 	register const char *name;
283 	void *context;
284 {
285 	register struct nvlist ***p = context;
286 	register struct devbase *dev;
287 	register struct nvlist *nv;
288 
289 	dev = ht_lookup(devbasetab, name);
290 	if (dev == NULL)	/* cannot occur here; we checked earlier */
291 		panic("fixcount(%s)", name);
292 	nv = newnv(name, NULL, NULL, dev->d_umax, NULL);
293 	**p = nv;
294 	*p = &nv->nv_next;
295 	(void)ht_insert(needcnttab, name, nv);
296 	return (dev->d_umax != 0);
297 }
298 
299 /*
300  * Called from fixfiles when eval'ing a selection expression for a
301  * file that will generate a .h with flags.  We will need the flat list.
302  */
303 static int
304 fixfsel(name, context)
305 	const char *name;
306 	void *context;
307 {
308 	register struct nvlist ***p = context;
309 	register struct nvlist *nv;
310 	register int sel;
311 
312 	sel = ht_lookup(selecttab, name) != NULL;
313 	nv = newnv(name, NULL, NULL, sel, NULL);
314 	**p = nv;
315 	*p = &nv->nv_next;
316 	return (sel);
317 }
318 
319 /*
320  * As for fixfsel above, but we do not need the flat list.
321  */
322 static int
323 fixsel(name, context)
324 	const char *name;
325 	void *context;
326 {
327 
328 	return (ht_lookup(selecttab, name) != NULL);
329 }
330 
331 /*
332  * Eval an expression tree.  Calls the given function on each node,
333  * passing it the given context & the name; return value is &/|/! of
334  * results of evaluating atoms.
335  *
336  * No short circuiting ever occurs.  fn must return 0 or 1 (otherwise
337  * our mixing of C's bitwise & boolean here may give surprises).
338  */
339 static int
340 expr_eval(expr, fn, context)
341 	register struct nvlist *expr;
342 	register int (*fn) __P((const char *, void *));
343 	register void *context;
344 {
345 	int lhs, rhs;
346 
347 	switch (expr->nv_int) {
348 
349 	case FX_ATOM:
350 		return ((*fn)(expr->nv_name, context));
351 
352 	case FX_NOT:
353 		return (!expr_eval(expr->nv_next, fn, context));
354 
355 	case FX_AND:
356 		lhs = expr_eval(expr->nv_ptr, fn, context);
357 		rhs = expr_eval(expr->nv_next, fn, context);
358 		return (lhs & rhs);
359 
360 	case FX_OR:
361 		lhs = expr_eval(expr->nv_ptr, fn, context);
362 		rhs = expr_eval(expr->nv_next, fn, context);
363 		return (lhs | rhs);
364 	}
365 	panic("expr_eval %d", expr->nv_int);
366 	/* NOTREACHED */
367 }
368 
369 /*
370  * Free an expression tree.
371  */
372 static void
373 expr_free(expr)
374 	register struct nvlist *expr;
375 {
376 	register struct nvlist *rhs;
377 
378 	/* This loop traverses down the RHS of each subexpression. */
379 	for (; expr != NULL; expr = rhs) {
380 		switch (expr->nv_int) {
381 
382 		/* Atoms and !-exprs have no left hand side. */
383 		case FX_ATOM:
384 		case FX_NOT:
385 			break;
386 
387 		/* For AND and OR nodes, free the LHS. */
388 		case FX_AND:
389 		case FX_OR:
390 			expr_free(expr->nv_ptr);
391 			break;
392 
393 		default:
394 			panic("expr_free %d", expr->nv_int);
395 		}
396 		rhs = expr->nv_next;
397 		nvfree(expr);
398 	}
399 }
400 
401 #ifdef DEBUG
402 /*
403  * Print expression tree.
404  */
405 void
406 prexpr(expr)
407 	struct nvlist *expr;
408 {
409 	static void pr0();
410 
411 	printf("expr =");
412 	pr0(expr);
413 	printf("\n");
414 	(void)fflush(stdout);
415 }
416 
417 static void
418 pr0(e)
419 	register struct nvlist *e;
420 {
421 
422 	switch (e->nv_int) {
423 	case FX_ATOM:
424 		printf(" %s", e->nv_name);
425 		return;
426 	case FX_NOT:
427 		printf(" (!");
428 		break;
429 	case FX_AND:
430 		printf(" (&");
431 		break;
432 	case FX_OR:
433 		printf(" (|");
434 		break;
435 	default:
436 		printf(" (?%d?", e->nv_int);
437 		break;
438 	}
439 	if (e->nv_ptr)
440 		pr0(e->nv_ptr);
441 	pr0(e->nv_next);
442 	printf(")");
443 }
444 #endif
445