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