xref: /openbsd-src/usr.sbin/config/files.c (revision ce7e0fc6a9d74d25b78fb6ad846387717f5172b6)
1 /*	$OpenBSD: files.c,v 1.11 2002/03/14 16:44:24 mpech 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 struct objects **nextobject;
70 
71 static int	checkaux(const char *, void *);
72 static int	fixcount(const char *, void *);
73 static int	fixfsel(const char *, void *);
74 static int	fixsel(const char *, void *);
75 static int	expr_eval(struct nvlist *,
76 		    int (*)(const char *, void *), void *);
77 static void	expr_free(struct nvlist *);
78 
79 void
80 initfiles()
81 {
82 
83 	basetab = ht_new();
84 	pathtab = ht_new();
85 	nextfile = &allfiles;
86 	unchecked = &allfiles;
87 	nextobject = &allobjects;
88 }
89 
90 void
91 addfile(path, optx, flags, rule)
92 	const char *path;
93 	struct nvlist *optx;
94 	int flags;
95 	const char *rule;
96 {
97 	struct files *fi;
98 	const char *dotp, *tail;
99 	size_t baselen;
100 	int needc, needf;
101 	char base[200];
102 
103 	/* check various errors */
104 	needc = flags & FI_NEEDSCOUNT;
105 	needf = flags & FI_NEEDSFLAG;
106 	if (needc && needf) {
107 		error("cannot mix needs-count and needs-flag");
108 		goto bad;
109 	}
110 	if (optx == NULL && (needc || needf)) {
111 		error("nothing to %s for %s", needc ? "count" : "flag", path);
112 		goto bad;
113 	}
114 
115 	/* find last part of pathname, and same without trailing suffix */
116 	tail = strrchr(path, '/');
117 	if (tail == NULL)
118 		tail = path;
119 	else
120 		tail++;
121 	dotp = strrchr(tail, '.');
122 	if (dotp == NULL || dotp[1] == 0 ||
123 	    (baselen = dotp - tail) >= sizeof(base)) {
124 		error("invalid pathname `%s'", path);
125 		goto bad;
126 	}
127 
128 	/*
129 	 * Commit this file to memory.  We will decide later whether it
130 	 * will be used after all.
131 	 */
132 	fi = emalloc(sizeof *fi);
133 	if (ht_insert(pathtab, path, fi)) {
134 		free(fi);
135 		if ((fi = ht_lookup(pathtab, path)) == NULL)
136 			panic("addfile: ht_lookup(%s)", path);
137 		error("duplicate file %s", path);
138 		xerror(fi->fi_srcfile, fi->fi_srcline,
139 		    "here is the original definition");
140 	}
141 	memcpy(base, tail, baselen);
142 	base[baselen] = 0;
143 	fi->fi_next = NULL;
144 	fi->fi_srcfile = yyfile;
145 	fi->fi_srcline = currentline();
146 	fi->fi_flags = flags;
147 	fi->fi_path = path;
148 	fi->fi_tail = tail;
149 	fi->fi_base = intern(base);
150 	fi->fi_optx = optx;
151 	fi->fi_optf = NULL;
152 	fi->fi_mkrule = rule;
153 	*nextfile = fi;
154 	nextfile = &fi->fi_next;
155 	return;
156 bad:
157 	expr_free(optx);
158 }
159 
160 void
161 addobject(path, optx, flags)
162 	const char *path;
163 	struct nvlist *optx;
164 	int flags;
165 {
166 	struct objects *oi;
167 
168 	/*
169 	 * Commit this object to memory.  We will decide later whether it
170 	 * will be used after all.
171 	 */
172 	oi = emalloc(sizeof *oi);
173 	if (ht_insert(pathtab, path, oi)) {
174 		free(oi);
175 		if ((oi = ht_lookup(pathtab, path)) == NULL)
176 			panic("addfile: ht_lookup(%s)", path);
177 		error("duplicate file %s", path);
178 		xerror(oi->oi_srcfile, oi->oi_srcline,
179 		    "here is the original definition");
180 	}
181 	oi->oi_next = NULL;
182 	oi->oi_srcfile = yyfile;
183 	oi->oi_srcline = currentline();
184 	oi->oi_flags = flags;
185 	oi->oi_path = path;
186 	oi->oi_optx = optx;
187 	oi->oi_optf = NULL;
188 	*nextobject = oi;
189 	nextobject = &oi->oi_next;
190 }
191 
192 /*
193  * We have finished reading some "files" file, either ../../conf/files
194  * or ./files.$machine.  Make sure that everything that is flagged as
195  * needing a count is reasonable.  (This prevents ../../conf/files from
196  * depending on some machine-specific device.)
197  */
198 void
199 checkfiles()
200 {
201 	struct files *fi, *last;
202 
203 	last = NULL;
204 	for (fi = *unchecked; fi != NULL; last = fi, fi = fi->fi_next)
205 		if ((fi->fi_flags & FI_NEEDSCOUNT) != 0)
206 			(void)expr_eval(fi->fi_optx, checkaux, fi);
207 	if (last != NULL)
208 		unchecked = &last->fi_next;
209 }
210 
211 /*
212  * Auxiliary function for checkfiles, called from expr_eval.
213  * We are not actually interested in the expression's value.
214  */
215 static int
216 checkaux(name, context)
217 	const char *name;
218 	void *context;
219 {
220 	struct files *fi = context;
221 
222 	if (ht_lookup(devbasetab, name) == NULL) {
223 		xerror(fi->fi_srcfile, fi->fi_srcline,
224 		    "`%s' is not a countable device",
225 		    name);
226 		/* keep fixfiles() from complaining again */
227 		fi->fi_flags |= FI_HIDDEN;
228 	}
229 	return (0);
230 }
231 
232 /*
233  * We have finished reading everything.  Tack the files down: calculate
234  * selection and counts as needed.  Check that the object files built
235  * from the selected sources do not collide.
236  */
237 int
238 fixfiles()
239 {
240 	struct files *fi, *ofi;
241 	struct nvlist *flathead, **flatp;
242 	int err, sel;
243 
244 	err = 0;
245 	for (fi = allfiles; fi != NULL; fi = fi->fi_next) {
246 		/* Skip files that generated counted-device complaints. */
247 		if (fi->fi_flags & FI_HIDDEN)
248 			continue;
249 
250 		/* Optional: see if it is to be included. */
251 		if (fi->fi_optx != NULL) {
252 			flathead = NULL;
253 			flatp = &flathead;
254 			sel = expr_eval(fi->fi_optx,
255 			    fi->fi_flags & FI_NEEDSCOUNT ? fixcount :
256 			    fi->fi_flags & FI_NEEDSFLAG ? fixfsel :
257 			    fixsel,
258 			    &flatp);
259 			fi->fi_optf = flathead;
260 			if (!sel)
261 				continue;
262 		}
263 
264 		/* We like this file.  Make sure it generates a unique .o. */
265 		if (ht_insert(basetab, fi->fi_base, fi)) {
266 			if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL)
267 				panic("fixfiles ht_lookup(%s)", fi->fi_base);
268 			/*
269 			 * If the new file comes from a different source,
270 			 * allow the new one to override the old one.
271 			 */
272 			if (fi->fi_path != ofi->fi_path) {
273 				if (ht_replace(basetab, fi->fi_base, fi) != 1)
274 					panic("fixfiles ht_replace(%s)",
275 					    fi->fi_base);
276 				ofi->fi_flags &= ~FI_SEL;
277 				ofi->fi_flags |= FI_HIDDEN;
278 			} else {
279 				xerror(fi->fi_srcfile, fi->fi_srcline,
280 				    "object file collision on %s.o, from %s",
281 				    fi->fi_base, fi->fi_path);
282 				xerror(ofi->fi_srcfile, ofi->fi_srcline,
283 				    "here is the previous file: %s",
284 				    ofi->fi_path);
285 				err = 1;
286 			}
287 		}
288 		fi->fi_flags |= FI_SEL;
289 	}
290 	return (err);
291 }
292 
293 /*
294  * We have finished reading everything.  Tack the objects down: calculate
295  * selection.
296  */
297 int
298 fixobjects()
299 {
300 	struct objects *oi;
301 	struct nvlist *flathead, **flatp;
302 	int err, sel;
303 
304 	err = 0;
305 	for (oi = allobjects; oi != NULL; oi = oi->oi_next) {
306 		/* Optional: see if it is to be included. */
307 		if (oi->oi_optx != NULL) {
308 			flathead = NULL;
309 			flatp = &flathead;
310 			sel = expr_eval(oi->oi_optx,
311 			    oi->oi_flags & OI_NEEDSFLAG ? fixfsel :
312 			    fixsel,
313 			    &flatp);
314 			oi->oi_optf = flathead;
315 			if (!sel)
316 				continue;
317 		}
318 
319 		oi->oi_flags |= OI_SEL;
320 	}
321 	return (err);
322 }
323 
324 /*
325  * Called when evaluating a needs-count expression.  Make sure the
326  * atom is a countable device.  The expression succeeds iff there
327  * is at least one of them (note that while `xx*' will not always
328  * set xx's d_umax > 0, you cannot mix '*' and needs-count).  The
329  * mkheaders() routine wants a flattened, in-order list of the
330  * atoms for `#define name value' lines, so we build that as we
331  * are called to eval each atom.
332  */
333 static int
334 fixcount(name, context)
335 	const char *name;
336 	void *context;
337 {
338 	struct nvlist ***p = context;
339 	struct devbase *dev;
340 	struct nvlist *nv;
341 
342 	dev = ht_lookup(devbasetab, name);
343 	if (dev == NULL)	/* cannot occur here; we checked earlier */
344 		panic("fixcount(%s)", name);
345 	nv = newnv(name, NULL, NULL, dev->d_umax, NULL);
346 	**p = nv;
347 	*p = &nv->nv_next;
348 	(void)ht_insert(needcnttab, name, nv);
349 	return (dev->d_umax != 0);
350 }
351 
352 /*
353  * Called from fixfiles when eval'ing a selection expression for a
354  * file that will generate a .h with flags.  We will need the flat list.
355  */
356 static int
357 fixfsel(name, context)
358 	const char *name;
359 	void *context;
360 {
361 	struct nvlist ***p = context;
362 	struct nvlist *nv;
363 	int sel;
364 
365 	sel = ht_lookup(selecttab, name) != NULL;
366 	nv = newnv(name, NULL, NULL, sel, NULL);
367 	**p = nv;
368 	*p = &nv->nv_next;
369 	return (sel);
370 }
371 
372 /*
373  * As for fixfsel above, but we do not need the flat list.
374  */
375 static int
376 fixsel(name, context)
377 	const char *name;
378 	void *context;
379 {
380 
381 	return (ht_lookup(selecttab, name) != NULL);
382 }
383 
384 /*
385  * Eval an expression tree.  Calls the given function on each node,
386  * passing it the given context & the name; return value is &/|/! of
387  * results of evaluating atoms.
388  *
389  * No short circuiting ever occurs.  fn must return 0 or 1 (otherwise
390  * our mixing of C's bitwise & boolean here may give surprises).
391  */
392 static int
393 expr_eval(expr, fn, context)
394 	struct nvlist *expr;
395 	int (*fn)(const char *, void *);
396 	void *context;
397 {
398 	int lhs, rhs;
399 
400 	switch (expr->nv_int) {
401 
402 	case FX_ATOM:
403 		return ((*fn)(expr->nv_name, context));
404 
405 	case FX_NOT:
406 		return (!expr_eval(expr->nv_next, fn, context));
407 
408 	case FX_AND:
409 		lhs = expr_eval(expr->nv_ptr, fn, context);
410 		rhs = expr_eval(expr->nv_next, fn, context);
411 		return (lhs & rhs);
412 
413 	case FX_OR:
414 		lhs = expr_eval(expr->nv_ptr, fn, context);
415 		rhs = expr_eval(expr->nv_next, fn, context);
416 		return (lhs | rhs);
417 	}
418 	panic("expr_eval %d", expr->nv_int);
419 	return (0);
420 }
421 
422 /*
423  * Free an expression tree.
424  */
425 static void
426 expr_free(expr)
427 	struct nvlist *expr;
428 {
429 	struct nvlist *rhs;
430 
431 	/* This loop traverses down the RHS of each subexpression. */
432 	for (; expr != NULL; expr = rhs) {
433 		switch (expr->nv_int) {
434 
435 		/* Atoms and !-exprs have no left hand side. */
436 		case FX_ATOM:
437 		case FX_NOT:
438 			break;
439 
440 		/* For AND and OR nodes, free the LHS. */
441 		case FX_AND:
442 		case FX_OR:
443 			expr_free(expr->nv_ptr);
444 			break;
445 
446 		default:
447 			panic("expr_free %d", expr->nv_int);
448 		}
449 		rhs = expr->nv_next;
450 		nvfree(expr);
451 	}
452 }
453 
454 #ifdef DEBUG
455 /*
456  * Print expression tree.
457  */
458 void
459 prexpr(expr)
460 	struct nvlist *expr;
461 {
462 	static void pr0();
463 
464 	printf("expr =");
465 	pr0(expr);
466 	printf("\n");
467 	(void)fflush(stdout);
468 }
469 
470 static void
471 pr0(e)
472 	struct nvlist *e;
473 {
474 
475 	switch (e->nv_int) {
476 	case FX_ATOM:
477 		printf(" %s", e->nv_name);
478 		return;
479 	case FX_NOT:
480 		printf(" (!");
481 		break;
482 	case FX_AND:
483 		printf(" (&");
484 		break;
485 	case FX_OR:
486 		printf(" (|");
487 		break;
488 	default:
489 		printf(" (?%d?", e->nv_int);
490 		break;
491 	}
492 	if (e->nv_ptr)
493 		pr0(e->nv_ptr);
494 	pr0(e->nv_next);
495 	printf(")");
496 }
497 #endif
498