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
initfiles()41 initfiles()
42 {
43
44 basetab = ht_new();
45 pathtab = ht_new();
46 nextfile = &allfiles;
47 unchecked = &allfiles;
48 }
49
50 static void
showprev(pref,fi)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
addfile(path,opts,flags,rule)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
checkfiles()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
fixfiles()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