xref: /openbsd/usr.sbin/config/files.c (revision b9fc9a72)
1 /*	$OpenBSD: files.c,v 1.20 2015/01/16 06:40:16 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. Neither the name of the University nor the names of its contributors
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  *	from: @(#)files.c	8.1 (Berkeley) 6/6/93
42  */
43 
44 #include <errno.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 
49 #include "config.h"
50 
51 extern const char *yyfile;
52 
53 /*
54  * We check that each full path name is unique.  File base names
55  * should generally also be unique, e.g., having both a net/xx.c and
56  * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably
57  * wrong, but is permitted under some conditions.
58  */
59 static struct hashtab *basetab;		/* file base names */
60 static struct hashtab *pathtab;		/* full path names */
61 
62 static struct files **nextfile;
63 static struct files **unchecked;
64 
65 static struct objects **nextobject;
66 
67 static int	checkaux(const char *, void *);
68 static int	fixcount(const char *, void *);
69 static int	fixfsel(const char *, void *);
70 static int	fixsel(const char *, void *);
71 static int	expr_eval(struct nvlist *,
72 		    int (*)(const char *, void *), void *);
73 static void	expr_free(struct nvlist *);
74 
75 #ifdef DEBUG
76 static void	pr0();
77 #endif
78 
79 void
initfiles(void)80 initfiles(void)
81 {
82 
83 	basetab = ht_new();
84 	pathtab = ht_new();
85 	nextfile = &allfiles;
86 	unchecked = &allfiles;
87 	nextobject = &allobjects;
88 }
89 
90 void
addfile(struct nvlist * nvpath,struct nvlist * optx,int flags,const char * rule)91 addfile(struct nvlist *nvpath, struct nvlist *optx, int flags, const char *rule)
92 {
93 	struct files *fi;
94 	const char *dotp, *dotp1, *tail, *path, *tail1 = NULL;
95 	struct nvlist *nv;
96 	size_t baselen;
97 	int needc, needf;
98 	char base[200];
99 
100 	/* check various errors */
101 	needc = flags & FI_NEEDSCOUNT;
102 	needf = flags & FI_NEEDSFLAG;
103 	if (needc && needf) {
104 		error("cannot mix needs-count and needs-flag");
105 		goto bad;
106 	}
107 	if (optx == NULL && (needc || needf)) {
108 		error("nothing to %s", needc ? "count" : "flag");
109 		goto bad;
110 	}
111 
112 	for (nv = nvpath; nv; nv = nv->nv_next) {
113 		path = nv->nv_name;
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 		 * Ensure all tailnames are identical, because .o
130 		 * filenames must be identical too.
131 		 */
132 		if (tail1 &&
133 		    (dotp - tail != dotp1 - tail1 ||
134 		    strncmp(tail1, tail, dotp - tail)))
135 			error("different production from %s %s",
136 			    nvpath->nv_name, tail);
137 		tail1 = tail;
138 		dotp1 = dotp;
139 	}
140 
141 	/*
142 	 * Commit this file to memory.  We will decide later whether it
143 	 * will be used after all.
144 	 */
145 	fi = emalloc(sizeof *fi);
146 	if (ht_insert(pathtab, path, fi)) {
147 		free(fi);
148 		if ((fi = ht_lookup(pathtab, path)) == NULL)
149 			panic("addfile: ht_lookup(%s)", path);
150 		error("duplicate file %s", path);
151 		xerror(fi->fi_srcfile, fi->fi_srcline,
152 		    "here is the original definition");
153 	}
154 	memcpy(base, tail, baselen);
155 	base[baselen] = 0;
156 	fi->fi_next = NULL;
157 	fi->fi_srcfile = yyfile;
158 	fi->fi_srcline = currentline();
159 	fi->fi_flags = flags;
160 	fi->fi_nvpath = nvpath;
161 	fi->fi_base = intern(base);
162 	fi->fi_optx = optx;
163 	fi->fi_optf = NULL;
164 	fi->fi_mkrule = rule;
165 	*nextfile = fi;
166 	nextfile = &fi->fi_next;
167 	return;
168 bad:
169 	expr_free(optx);
170 }
171 
172 void
addobject(const char * path,struct nvlist * optx,int flags)173 addobject(const char *path, struct nvlist *optx, int flags)
174 {
175 	struct objects *oi;
176 
177 	/*
178 	 * Commit this object to memory.  We will decide later whether it
179 	 * will be used after all.
180 	 */
181 	oi = emalloc(sizeof *oi);
182 	if (ht_insert(pathtab, path, oi)) {
183 		free(oi);
184 		if ((oi = ht_lookup(pathtab, path)) == NULL)
185 			panic("addfile: ht_lookup(%s)", path);
186 		error("duplicate file %s", path);
187 		xerror(oi->oi_srcfile, oi->oi_srcline,
188 		    "here is the original definition");
189 	}
190 	oi->oi_next = NULL;
191 	oi->oi_srcfile = yyfile;
192 	oi->oi_srcline = currentline();
193 	oi->oi_flags = flags;
194 	oi->oi_path = path;
195 	oi->oi_optx = optx;
196 	oi->oi_optf = NULL;
197 	*nextobject = oi;
198 	nextobject = &oi->oi_next;
199 }
200 
201 /*
202  * We have finished reading some "files" file, either ../../conf/files
203  * or ./files.$machine.  Make sure that everything that is flagged as
204  * needing a count is reasonable.  (This prevents ../../conf/files from
205  * depending on some machine-specific device.)
206  */
207 void
checkfiles(void)208 checkfiles(void)
209 {
210 	struct files *fi, *last;
211 
212 	last = NULL;
213 	for (fi = *unchecked; fi != NULL; last = fi, fi = fi->fi_next)
214 		if ((fi->fi_flags & FI_NEEDSCOUNT) != 0)
215 			(void)expr_eval(fi->fi_optx, checkaux, fi);
216 	if (last != NULL)
217 		unchecked = &last->fi_next;
218 }
219 
220 /*
221  * Auxiliary function for checkfiles, called from expr_eval.
222  * We are not actually interested in the expression's value.
223  */
224 static int
checkaux(const char * name,void * context)225 checkaux(const char *name, void *context)
226 {
227 	struct files *fi = context;
228 
229 	if (ht_lookup(devbasetab, name) == NULL) {
230 		xerror(fi->fi_srcfile, fi->fi_srcline,
231 		    "`%s' is not a countable device",
232 		    name);
233 		/* keep fixfiles() from complaining again */
234 		fi->fi_flags |= FI_HIDDEN;
235 	}
236 	return (0);
237 }
238 
239 /*
240  * We have finished reading everything.  Tack the files down: calculate
241  * selection and counts as needed.  Check that the object files built
242  * from the selected sources do not collide.
243  */
244 int
fixfiles(void)245 fixfiles(void)
246 {
247 	struct files *fi, *ofi;
248 	struct nvlist *flathead, **flatp;
249 	int err, sel;
250 
251 	err = 0;
252 	for (fi = allfiles; fi != NULL; fi = fi->fi_next) {
253 		/* Skip files that generated counted-device complaints. */
254 		if (fi->fi_flags & FI_HIDDEN)
255 			continue;
256 
257 		/* Optional: see if it is to be included. */
258 		if (fi->fi_optx != NULL) {
259 			flathead = NULL;
260 			flatp = &flathead;
261 			sel = expr_eval(fi->fi_optx,
262 			    fi->fi_flags & FI_NEEDSCOUNT ? fixcount :
263 			    fi->fi_flags & FI_NEEDSFLAG ? fixfsel :
264 			    fixsel,
265 			    &flatp);
266 			fi->fi_optf = flathead;
267 			if (!sel)
268 				continue;
269 		}
270 
271 		/* We like this file.  Make sure it generates a unique .o. */
272 		if (ht_insert(basetab, fi->fi_base, fi)) {
273 			if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL)
274 				panic("fixfiles ht_lookup(%s)", fi->fi_base);
275 			/*
276 			 * If the new file comes from a different source,
277 			 * allow the new one to override the old one.
278 			 */
279 			if (fi->fi_nvpath != ofi->fi_nvpath) {
280 				if (ht_replace(basetab, fi->fi_base, fi) != 1)
281 					panic("fixfiles ht_replace(%s)",
282 					    fi->fi_base);
283 				ofi->fi_flags &= ~FI_SEL;
284 				ofi->fi_flags |= FI_HIDDEN;
285 			} else {
286 				xerror(fi->fi_srcfile, fi->fi_srcline,
287 				    "object file collision on %s.o, from %s",
288 				    fi->fi_base, fi->fi_nvpath->nv_name);
289 				xerror(ofi->fi_srcfile, ofi->fi_srcline,
290 				    "here is the previous file: %s",
291 				    ofi->fi_nvpath->nv_name);
292 				err = 1;
293 			}
294 		}
295 		fi->fi_flags |= FI_SEL;
296 	}
297 	return (err);
298 }
299 
300 /*
301  * We have finished reading everything.  Tack the objects down: calculate
302  * selection.
303  */
304 int
fixobjects(void)305 fixobjects(void)
306 {
307 	struct objects *oi;
308 	struct nvlist *flathead, **flatp;
309 	int err, sel;
310 
311 	err = 0;
312 	for (oi = allobjects; oi != NULL; oi = oi->oi_next) {
313 		/* Optional: see if it is to be included. */
314 		if (oi->oi_optx != NULL) {
315 			flathead = NULL;
316 			flatp = &flathead;
317 			sel = expr_eval(oi->oi_optx,
318 			    oi->oi_flags & OI_NEEDSFLAG ? fixfsel :
319 			    fixsel,
320 			    &flatp);
321 			oi->oi_optf = flathead;
322 			if (!sel)
323 				continue;
324 		}
325 
326 		oi->oi_flags |= OI_SEL;
327 	}
328 	return (err);
329 }
330 
331 /*
332  * Called when evaluating a needs-count expression.  Make sure the
333  * atom is a countable device.  The expression succeeds iff there
334  * is at least one of them (note that while `xx*' will not always
335  * set xx's d_umax > 0, you cannot mix '*' and needs-count).  The
336  * mkheaders() routine wants a flattened, in-order list of the
337  * atoms for `#define name value' lines, so we build that as we
338  * are called to eval each atom.
339  */
340 static int
fixcount(const char * name,void * context)341 fixcount(const char *name, void *context)
342 {
343 	struct nvlist ***p = context;
344 	struct devbase *dev;
345 	struct nvlist *nv;
346 
347 	dev = ht_lookup(devbasetab, name);
348 	if (dev == NULL)	/* cannot occur here; we checked earlier */
349 		panic("fixcount(%s)", name);
350 	nv = newnv(name, NULL, NULL, dev->d_umax, NULL);
351 	**p = nv;
352 	*p = &nv->nv_next;
353 	(void)ht_insert(needcnttab, name, nv);
354 	return (dev->d_umax != 0);
355 }
356 
357 /*
358  * Called from fixfiles when eval'ing a selection expression for a
359  * file that will generate a .h with flags.  We will need the flat list.
360  */
361 static int
fixfsel(const char * name,void * context)362 fixfsel(const char *name, void *context)
363 {
364 	struct nvlist ***p = context;
365 	struct nvlist *nv;
366 	int sel;
367 
368 	sel = ht_lookup(selecttab, name) != NULL;
369 	nv = newnv(name, NULL, NULL, sel, NULL);
370 	**p = nv;
371 	*p = &nv->nv_next;
372 	return (sel);
373 }
374 
375 /*
376  * As for fixfsel above, but we do not need the flat list.
377  */
378 static int
fixsel(const char * name,void * context)379 fixsel(const char *name, void *context)
380 {
381 
382 	return (ht_lookup(selecttab, name) != NULL);
383 }
384 
385 /*
386  * Eval an expression tree.  Calls the given function on each node,
387  * passing it the given context & the name; return value is &/|/! of
388  * results of evaluating atoms.
389  *
390  * No short circuiting ever occurs.  fn must return 0 or 1 (otherwise
391  * our mixing of C's bitwise & boolean here may give surprises).
392  */
393 static int
expr_eval(struct nvlist * expr,int (* fn)(const char *,void *),void * context)394 expr_eval(struct nvlist *expr, int (*fn)(const char *, void *), void *context)
395 {
396 	int lhs, rhs;
397 
398 	switch (expr->nv_int) {
399 
400 	case FX_ATOM:
401 		return ((*fn)(expr->nv_name, context));
402 
403 	case FX_NOT:
404 		return (!expr_eval(expr->nv_next, fn, context));
405 
406 	case FX_AND:
407 		lhs = expr_eval(expr->nv_ptr, fn, context);
408 		rhs = expr_eval(expr->nv_next, fn, context);
409 		return (lhs & rhs);
410 
411 	case FX_OR:
412 		lhs = expr_eval(expr->nv_ptr, fn, context);
413 		rhs = expr_eval(expr->nv_next, fn, context);
414 		return (lhs | rhs);
415 	}
416 	panic("expr_eval %d", expr->nv_int);
417 	return (0);
418 }
419 
420 /*
421  * Free an expression tree.
422  */
423 static void
expr_free(struct nvlist * expr)424 expr_free(struct nvlist *expr)
425 {
426 	struct nvlist *rhs;
427 
428 	/* This loop traverses down the RHS of each subexpression. */
429 	for (; expr != NULL; expr = rhs) {
430 		switch (expr->nv_int) {
431 
432 		/* Atoms and !-exprs have no left hand side. */
433 		case FX_ATOM:
434 		case FX_NOT:
435 			break;
436 
437 		/* For AND and OR nodes, free the LHS. */
438 		case FX_AND:
439 		case FX_OR:
440 			expr_free(expr->nv_ptr);
441 			break;
442 
443 		default:
444 			panic("expr_free %d", expr->nv_int);
445 		}
446 		rhs = expr->nv_next;
447 		nvfree(expr);
448 	}
449 }
450 
451 #ifdef DEBUG
452 /*
453  * Print expression tree.
454  */
455 void
prexpr(struct nvlist * expr)456 prexpr(struct nvlist *expr)
457 {
458 	printf("expr =");
459 	pr0(expr);
460 	printf("\n");
461 	(void)fflush(stdout);
462 }
463 
464 static void
pr0(struct nvlist * e)465 pr0(struct nvlist *e)
466 {
467 
468 	switch (e->nv_int) {
469 	case FX_ATOM:
470 		printf(" %s", e->nv_name);
471 		return;
472 	case FX_NOT:
473 		printf(" (!");
474 		break;
475 	case FX_AND:
476 		printf(" (&");
477 		break;
478 	case FX_OR:
479 		printf(" (|");
480 		break;
481 	default:
482 		printf(" (?%d?", e->nv_int);
483 		break;
484 	}
485 	if (e->nv_ptr)
486 		pr0(e->nv_ptr);
487 	pr0(e->nv_next);
488 	printf(")");
489 }
490 #endif
491