GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/config/files.c Lines: 0 149 0.0 %
Date: 2017-11-13 Branches: 0 76 0.0 %

Line Branch Exec Source
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
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
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
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
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
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
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
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
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
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
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
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
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
456
prexpr(struct nvlist *expr)
457
{
458
	printf("expr =");
459
	pr0(expr);
460
	printf("\n");
461
	(void)fflush(stdout);
462
}
463
464
static void
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