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