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