1 /* $OpenBSD: files.c,v 1.5 1996/08/29 03:33:05 deraadt Exp $ */ 2 /* $NetBSD: files.c,v 1.6 1996/03/17 13:18:17 cgd Exp $ */ 3 4 /* 5 * Copyright (c) 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This software was developed by the Computer Systems Engineering group 9 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 10 * contributed to Berkeley. 11 * 12 * All advertising materials mentioning features or use of this software 13 * must display the following acknowledgement: 14 * This product includes software developed by the University of 15 * California, Lawrence Berkeley Laboratories. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 3. All advertising materials mentioning features or use of this software 26 * must display the following acknowledgement: 27 * This product includes software developed by the University of 28 * California, Berkeley and its contributors. 29 * 4. Neither the name of the University nor the names of its contributors 30 * may be used to endorse or promote products derived from this software 31 * without specific prior written permission. 32 * 33 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 36 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43 * SUCH DAMAGE. 44 * 45 * from: @(#)files.c 8.1 (Berkeley) 6/6/93 46 */ 47 48 #include <sys/param.h> 49 #include <errno.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include "config.h" 54 55 extern const char *yyfile; 56 57 /* 58 * We check that each full path name is unique. File base names 59 * should generally also be unique, e.g., having both a net/xx.c and 60 * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably 61 * wrong, but is permitted under some conditions. 62 */ 63 static struct hashtab *basetab; /* file base names */ 64 static struct hashtab *pathtab; /* full path names */ 65 66 static struct files **nextfile; 67 static struct files **unchecked; 68 69 static int checkaux __P((const char *, void *)); 70 static int fixcount __P((const char *, void *)); 71 static int fixfsel __P((const char *, void *)); 72 static int fixsel __P((const char *, void *)); 73 static int expr_eval __P((struct nvlist *, 74 int (*)(const char *, void *), void *)); 75 static void expr_free __P((struct nvlist *)); 76 77 void 78 initfiles() 79 { 80 81 basetab = ht_new(); 82 pathtab = ht_new(); 83 nextfile = &allfiles; 84 unchecked = &allfiles; 85 } 86 87 #if 0 88 static void 89 showprev(pref, fi) 90 const char *pref; 91 register struct files *fi; 92 { 93 94 xerror(fi->fi_srcfile, fi->fi_srcline, 95 "%sfile %s ...", pref, fi->fi_path); 96 errors--; 97 } 98 #endif 99 100 void 101 addfile(path, optx, flags, rule) 102 const char *path; 103 struct nvlist *optx; 104 int flags; 105 const char *rule; 106 { 107 struct files *fi; 108 const char *dotp, *tail; 109 size_t baselen; 110 int needc, needf; 111 char base[200]; 112 113 /* check various errors */ 114 needc = flags & FI_NEEDSCOUNT; 115 needf = flags & FI_NEEDSFLAG; 116 if (needc && needf) { 117 error("cannot mix needs-count and needs-flag"); 118 goto bad; 119 } 120 if (optx == NULL && (needc || needf)) { 121 error("nothing to %s for %s", needc ? "count" : "flag", path); 122 goto bad; 123 } 124 125 /* find last part of pathname, and same without trailing suffix */ 126 tail = rindex(path, '/'); 127 if (tail == NULL) 128 tail = path; 129 else 130 tail++; 131 dotp = rindex(tail, '.'); 132 if (dotp == NULL || dotp[1] == 0 || 133 (baselen = dotp - tail) >= sizeof(base)) { 134 error("invalid pathname `%s'", path); 135 goto bad; 136 } 137 138 /* 139 * Commit this file to memory. We will decide later whether it 140 * will be used after all. 141 */ 142 fi = emalloc(sizeof *fi); 143 if (ht_insert(pathtab, path, fi)) { 144 free(fi); 145 if ((fi = ht_lookup(pathtab, path)) == NULL) 146 panic("addfile: ht_lookup(%s)", path); 147 error("duplicate file %s", path); 148 xerror(fi->fi_srcfile, fi->fi_srcline, 149 "here is the original definition"); 150 } 151 memcpy(base, tail, baselen); 152 base[baselen] = 0; 153 fi->fi_next = NULL; 154 fi->fi_srcfile = yyfile; 155 fi->fi_srcline = currentline(); 156 fi->fi_flags = flags; 157 fi->fi_path = path; 158 fi->fi_tail = tail; 159 fi->fi_base = intern(base); 160 fi->fi_optx = optx; 161 fi->fi_optf = NULL; 162 fi->fi_mkrule = rule; 163 *nextfile = fi; 164 nextfile = &fi->fi_next; 165 return; 166 bad: 167 expr_free(optx); 168 } 169 170 /* 171 * We have finished reading some "files" file, either ../../conf/files 172 * or ./files.$machine. Make sure that everything that is flagged as 173 * needing a count is reasonable. (This prevents ../../conf/files from 174 * depending on some machine-specific device.) 175 */ 176 void 177 checkfiles() 178 { 179 register struct files *fi, *last; 180 /*register struct nvlist *nv;*/ 181 182 last = NULL; 183 for (fi = *unchecked; fi != NULL; last = fi, fi = fi->fi_next) 184 if ((fi->fi_flags & FI_NEEDSCOUNT) != 0) 185 (void)expr_eval(fi->fi_optx, checkaux, fi); 186 if (last != NULL) 187 unchecked = &last->fi_next; 188 } 189 190 /* 191 * Auxiliary function for checkfiles, called from expr_eval. 192 * We are not actually interested in the expression's value. 193 */ 194 static int 195 checkaux(name, context) 196 const char *name; 197 void *context; 198 { 199 register struct files *fi = context; 200 201 if (ht_lookup(devbasetab, name) == NULL) { 202 xerror(fi->fi_srcfile, fi->fi_srcline, 203 "`%s' is not a countable device", 204 name); 205 /* keep fixfiles() from complaining again */ 206 fi->fi_flags |= FI_HIDDEN; 207 } 208 return (0); 209 } 210 211 /* 212 * We have finished reading everything. Tack the files down: calculate 213 * selection and counts as needed. Check that the object files built 214 * from the selected sources do not collide. 215 */ 216 int 217 fixfiles() 218 { 219 register struct files *fi, *ofi; 220 struct nvlist *flathead, **flatp; 221 int err, sel; 222 223 err = 0; 224 for (fi = allfiles; fi != NULL; fi = fi->fi_next) { 225 /* Skip files that generated counted-device complaints. */ 226 if (fi->fi_flags & FI_HIDDEN) 227 continue; 228 if (fi->fi_optx != NULL) { 229 /* Optional: see if it is to be included. */ 230 flathead = NULL; 231 flatp = &flathead; 232 sel = expr_eval(fi->fi_optx, 233 fi->fi_flags & FI_NEEDSCOUNT ? fixcount : 234 fi->fi_flags & FI_NEEDSFLAG ? fixfsel : 235 fixsel, 236 &flatp); 237 fi->fi_optf = flathead; 238 if (!sel) 239 continue; 240 } 241 242 /* We like this file. Make sure it generates a unique .o. */ 243 if (ht_insert(basetab, fi->fi_base, fi)) { 244 if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL) 245 panic("fixfiles ht_lookup(%s)", fi->fi_base); 246 /* 247 * If the new file comes from a different source, 248 * allow the new one to override the old one. 249 */ 250 if (fi->fi_path != ofi->fi_path) { 251 if (ht_replace(basetab, fi->fi_base, fi) != 1) 252 panic("fixfiles ht_replace(%s)", 253 fi->fi_base); 254 ofi->fi_flags &= ~FI_SEL; 255 ofi->fi_flags |= FI_HIDDEN; 256 } else { 257 xerror(fi->fi_srcfile, fi->fi_srcline, 258 "object file collision on %s.o, from %s", 259 fi->fi_base, fi->fi_path); 260 xerror(ofi->fi_srcfile, ofi->fi_srcline, 261 "here is the previous file: %s", 262 ofi->fi_path); 263 err = 1; 264 } 265 } 266 fi->fi_flags |= FI_SEL; 267 } 268 return (err); 269 } 270 271 /* 272 * Called when evaluating a needs-count expression. Make sure the 273 * atom is a countable device. The expression succeeds iff there 274 * is at least one of them (note that while `xx*' will not always 275 * set xx's d_umax > 0, you cannot mix '*' and needs-count). The 276 * mkheaders() routine wants a flattened, in-order list of the 277 * atoms for `#define name value' lines, so we build that as we 278 * are called to eval each atom. 279 */ 280 static int 281 fixcount(name, context) 282 register const char *name; 283 void *context; 284 { 285 register struct nvlist ***p = context; 286 register struct devbase *dev; 287 register struct nvlist *nv; 288 289 dev = ht_lookup(devbasetab, name); 290 if (dev == NULL) /* cannot occur here; we checked earlier */ 291 panic("fixcount(%s)", name); 292 nv = newnv(name, NULL, NULL, dev->d_umax, NULL); 293 **p = nv; 294 *p = &nv->nv_next; 295 (void)ht_insert(needcnttab, name, nv); 296 return (dev->d_umax != 0); 297 } 298 299 /* 300 * Called from fixfiles when eval'ing a selection expression for a 301 * file that will generate a .h with flags. We will need the flat list. 302 */ 303 static int 304 fixfsel(name, context) 305 const char *name; 306 void *context; 307 { 308 register struct nvlist ***p = context; 309 register struct nvlist *nv; 310 register int sel; 311 312 sel = ht_lookup(selecttab, name) != NULL; 313 nv = newnv(name, NULL, NULL, sel, NULL); 314 **p = nv; 315 *p = &nv->nv_next; 316 return (sel); 317 } 318 319 /* 320 * As for fixfsel above, but we do not need the flat list. 321 */ 322 static int 323 fixsel(name, context) 324 const char *name; 325 void *context; 326 { 327 328 return (ht_lookup(selecttab, name) != NULL); 329 } 330 331 /* 332 * Eval an expression tree. Calls the given function on each node, 333 * passing it the given context & the name; return value is &/|/! of 334 * results of evaluating atoms. 335 * 336 * No short circuiting ever occurs. fn must return 0 or 1 (otherwise 337 * our mixing of C's bitwise & boolean here may give surprises). 338 */ 339 static int 340 expr_eval(expr, fn, context) 341 register struct nvlist *expr; 342 register int (*fn) __P((const char *, void *)); 343 register void *context; 344 { 345 int lhs, rhs; 346 347 switch (expr->nv_int) { 348 349 case FX_ATOM: 350 return ((*fn)(expr->nv_name, context)); 351 352 case FX_NOT: 353 return (!expr_eval(expr->nv_next, fn, context)); 354 355 case FX_AND: 356 lhs = expr_eval(expr->nv_ptr, fn, context); 357 rhs = expr_eval(expr->nv_next, fn, context); 358 return (lhs & rhs); 359 360 case FX_OR: 361 lhs = expr_eval(expr->nv_ptr, fn, context); 362 rhs = expr_eval(expr->nv_next, fn, context); 363 return (lhs | rhs); 364 } 365 panic("expr_eval %d", expr->nv_int); 366 /* NOTREACHED */ 367 } 368 369 /* 370 * Free an expression tree. 371 */ 372 static void 373 expr_free(expr) 374 register struct nvlist *expr; 375 { 376 register struct nvlist *rhs; 377 378 /* This loop traverses down the RHS of each subexpression. */ 379 for (; expr != NULL; expr = rhs) { 380 switch (expr->nv_int) { 381 382 /* Atoms and !-exprs have no left hand side. */ 383 case FX_ATOM: 384 case FX_NOT: 385 break; 386 387 /* For AND and OR nodes, free the LHS. */ 388 case FX_AND: 389 case FX_OR: 390 expr_free(expr->nv_ptr); 391 break; 392 393 default: 394 panic("expr_free %d", expr->nv_int); 395 } 396 rhs = expr->nv_next; 397 nvfree(expr); 398 } 399 } 400 401 #ifdef DEBUG 402 /* 403 * Print expression tree. 404 */ 405 void 406 prexpr(expr) 407 struct nvlist *expr; 408 { 409 static void pr0(); 410 411 printf("expr ="); 412 pr0(expr); 413 printf("\n"); 414 (void)fflush(stdout); 415 } 416 417 static void 418 pr0(e) 419 register struct nvlist *e; 420 { 421 422 switch (e->nv_int) { 423 case FX_ATOM: 424 printf(" %s", e->nv_name); 425 return; 426 case FX_NOT: 427 printf(" (!"); 428 break; 429 case FX_AND: 430 printf(" (&"); 431 break; 432 case FX_OR: 433 printf(" (|"); 434 break; 435 default: 436 printf(" (?%d?", e->nv_int); 437 break; 438 } 439 if (e->nv_ptr) 440 pr0(e->nv_ptr); 441 pr0(e->nv_next); 442 printf(")"); 443 } 444 #endif 445