xref: /csrg-svn/usr.sbin/config.new/files.c (revision 57488)
1 /*
2  * Copyright (c) 1992 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This software was developed by the Computer Systems Engineering group
6  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7  * contributed to Berkeley.
8  *
9  * All advertising materials mentioning features or use of this software
10  * must display the following acknowledgement:
11  *	This product includes software developed by the University of
12  *	California, Lawrence Berkeley Laboratories.
13  *
14  * %sccs.include.redist.c%
15  *
16  *	@(#)files.c	5.1 (Berkeley) 01/12/93
17  *
18  * from: $Header: files.c,v 1.4 93/01/12 03:56:19 torek Exp $
19  */
20 
21 #include <sys/param.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include "config.h"
27 
28 extern const char *yyfile;
29 
30 /*
31  * We check that each full path name is unique.  File base names
32  * should generally also be unique, e.g., having both a net/xx.c and
33  * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably
34  * wrong, but is permitted under some conditions.
35  */
36 static struct hashtab *basetab;		/* file base names */
37 static struct hashtab *pathtab;		/* full path names */
38 
39 static struct files **nextfile;
40 static struct files **unchecked;
41 
42 void
43 initfiles()
44 {
45 
46 	basetab = ht_new();
47 	pathtab = ht_new();
48 	nextfile = &allfiles;
49 	unchecked = &allfiles;
50 }
51 
52 static void
53 showprev(pref, fi)
54 	const char *pref;
55 	register struct files *fi;
56 {
57 
58 	xerror(fi->fi_srcfile, fi->fi_srcline,
59 	    "%sfile %s ...", pref, fi->fi_path);
60 	errors--;
61 }
62 
63 void
64 addfile(path, opts, flags, rule)
65 	const char *path;
66 	struct nvlist *opts;
67 	int flags;
68 	const char *rule;
69 {
70 	struct files *fi;
71 	const char *base, *dotp, *tail;
72 	size_t baselen;
73 	int needc, needf;
74 	char buf[200];
75 
76 	/* check various errors */
77 	needc = flags & FI_NEEDSCOUNT;
78 	needf = flags & FI_NEEDSFLAG;
79 	if (needc && needf) {
80 		error("cannot mix needs-count and needs-flag");
81 		goto bad;
82 	}
83 	if (opts == NULL && (needc || needf)) {
84 		error("nothing to %s for %s", needc ? "count" : "flag", path);
85 		goto bad;
86 	}
87 	if ((fi = ht_lookup(pathtab, path)) != NULL) {
88 		showprev("", fi);
89 		error("file %s listed again", path);
90 		goto bad;
91 	}
92 
93 	/* find last part of pathname, and same without trailing suffix */
94 	tail = rindex(path, '/');
95 	if (tail == NULL)
96 		tail = path;
97 	else
98 		tail++;
99 	dotp = rindex(tail, '.');
100 	if (dotp == NULL || dotp[1] == 0 ||
101 	    (baselen = dotp - tail) >= sizeof(buf)) {
102 		error("invalid pathname `%s'", path);
103 		goto bad;
104 	}
105 
106 	/*
107 	 * Make a copy of the path without the .c/.s/whatever suffix.
108 	 * This must be unique per "files" file (e.g., a specific
109 	 * file can override a standard file, but no standard file
110 	 * can override another standard file).  This is not perfect
111 	 * but should catch any major errors.
112 	 */
113 	bcopy(tail, buf, baselen);
114 	buf[baselen] = 0;
115 	base = intern(buf);
116 	if ((fi = ht_lookup(basetab, base)) != NULL) {
117 		if (fi->fi_srcfile != yyfile) {
118 			showprev("note: ", fi);
119 			error("is overriden by %s", path);
120 			errors--;	/* take it away */
121 			fi->fi_flags |= FI_HIDDEN;
122 		} else {
123 			showprev("", fi);
124 			error("collides with %s (both make %s.o)",
125 			    path, base);
126 			goto bad;
127 		}
128 	}
129 
130 	/*
131 	 * Commit this file to memory.
132 	 */
133 	fi = emalloc(sizeof *fi);
134 	fi->fi_next = NULL;
135 	fi->fi_srcfile = yyfile;
136 	fi->fi_srcline = currentline();
137 	fi->fi_flags = flags;
138 	fi->fi_lastc = dotp[strlen(dotp) - 1];
139 	fi->fi_path = path;
140 	fi->fi_tail = tail;
141 	fi->fi_base = base;
142 	fi->fi_opt = opts;
143 	fi->fi_mkrule = rule;
144 	if (ht_insert(pathtab, path, fi))
145 		panic("addfile: ht_insert(%s)", path);
146 	(void)ht_replace(basetab, base, fi);
147 	*nextfile = fi;
148 	nextfile = &fi->fi_next;
149 	return;
150 bad:
151 	nvfreel(opts);
152 }
153 
154 /*
155  * We have finished reading some "files" file, either ../../conf/files
156  * or ./files.$machine.  Make sure that everything that is flagged as
157  * needing a count is reasonable.  (This prevents ../../conf/files from
158  * depending on some machine-specific device.)
159  */
160 void
161 checkfiles()
162 {
163 	register struct files *fi, *last;
164 	register struct nvlist *nv;
165 
166 	last = NULL;
167 	for (fi = *unchecked; fi != NULL; last = fi, fi = fi->fi_next) {
168 		if ((fi->fi_flags & FI_NEEDSCOUNT) == 0)
169 			continue;
170 		for (nv = fi->fi_opt; nv != NULL; nv = nv->nv_next)
171 			if (ht_lookup(devbasetab, nv->nv_name) == NULL) {
172 				xerror(fi->fi_srcfile, fi->fi_srcline,
173 				    "`%s' is not a countable device",
174 				    nv->nv_name);
175 				/* keep fixfiles() from complaining again */
176 				fi->fi_flags |= FI_HIDDEN;
177 			}
178 	}
179 	if (last != NULL)
180 		unchecked = &last->fi_next;
181 }
182 
183 /*
184  * We have finished reading everything.  Tack the files down: calculate
185  * selection and counts as needed.
186  */
187 int
188 fixfiles()
189 {
190 	register struct files *fi;
191 	register struct nvlist *nv;
192 	register struct devbase *dev;
193 	int sel, err;
194 
195 	err = 0;
196 	for (fi = allfiles; fi != NULL; fi = fi->fi_next) {
197 		if (fi->fi_flags & FI_HIDDEN)
198 			continue;
199 		if ((nv = fi->fi_opt) == NULL) {	/* standard */
200 			fi->fi_flags |= FI_SEL;
201 			continue;
202 		}
203 		/* figure out whether it is selected */
204 		sel = 0;
205 		if (fi->fi_flags & FI_NEEDSCOUNT) {
206 			/* ... and compute counts too */
207 			do {
208 				dev = ht_lookup(devbasetab, nv->nv_name);
209 				if (dev == NULL) {
210 					xerror(fi->fi_srcfile, fi->fi_srcline,
211 					    "`%s' is not a countable device",
212 					    nv->nv_name);
213 					err = 1;
214 				} else {
215 					if (dev->d_umax)
216 						sel = 1;
217 					nv->nv_int = dev->d_umax;
218 					(void)ht_insert(needcnttab,
219 					    nv->nv_name, nv);
220 				}
221 			} while ((nv = nv->nv_next) != NULL);
222 		} else {
223 			do {
224 				if (ht_lookup(selecttab, nv->nv_name)) {
225 					sel = 1;
226 					break;
227 				}
228 			} while ((nv = nv->nv_next) != NULL);
229 			if (fi->fi_flags & FI_NEEDSFLAG)
230 				for (nv = fi->fi_opt; nv; nv = nv->nv_next)
231 					nv->nv_int = sel;
232 		}
233 		/* if selected, we are go */
234 		if (sel)
235 			fi->fi_flags |= FI_SEL;
236 	}
237 	return (err);
238 }
239