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