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