1 /* $OpenBSD: files.c,v 1.11 2002/03/14 16:44:24 mpech 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 struct objects **nextobject; 70 71 static int checkaux(const char *, void *); 72 static int fixcount(const char *, void *); 73 static int fixfsel(const char *, void *); 74 static int fixsel(const char *, void *); 75 static int expr_eval(struct nvlist *, 76 int (*)(const char *, void *), void *); 77 static void expr_free(struct nvlist *); 78 79 void 80 initfiles() 81 { 82 83 basetab = ht_new(); 84 pathtab = ht_new(); 85 nextfile = &allfiles; 86 unchecked = &allfiles; 87 nextobject = &allobjects; 88 } 89 90 void 91 addfile(path, optx, flags, rule) 92 const char *path; 93 struct nvlist *optx; 94 int flags; 95 const char *rule; 96 { 97 struct files *fi; 98 const char *dotp, *tail; 99 size_t baselen; 100 int needc, needf; 101 char base[200]; 102 103 /* check various errors */ 104 needc = flags & FI_NEEDSCOUNT; 105 needf = flags & FI_NEEDSFLAG; 106 if (needc && needf) { 107 error("cannot mix needs-count and needs-flag"); 108 goto bad; 109 } 110 if (optx == NULL && (needc || needf)) { 111 error("nothing to %s for %s", needc ? "count" : "flag", path); 112 goto bad; 113 } 114 115 /* find last part of pathname, and same without trailing suffix */ 116 tail = strrchr(path, '/'); 117 if (tail == NULL) 118 tail = path; 119 else 120 tail++; 121 dotp = strrchr(tail, '.'); 122 if (dotp == NULL || dotp[1] == 0 || 123 (baselen = dotp - tail) >= sizeof(base)) { 124 error("invalid pathname `%s'", path); 125 goto bad; 126 } 127 128 /* 129 * Commit this file to memory. We will decide later whether it 130 * will be used after all. 131 */ 132 fi = emalloc(sizeof *fi); 133 if (ht_insert(pathtab, path, fi)) { 134 free(fi); 135 if ((fi = ht_lookup(pathtab, path)) == NULL) 136 panic("addfile: ht_lookup(%s)", path); 137 error("duplicate file %s", path); 138 xerror(fi->fi_srcfile, fi->fi_srcline, 139 "here is the original definition"); 140 } 141 memcpy(base, tail, baselen); 142 base[baselen] = 0; 143 fi->fi_next = NULL; 144 fi->fi_srcfile = yyfile; 145 fi->fi_srcline = currentline(); 146 fi->fi_flags = flags; 147 fi->fi_path = path; 148 fi->fi_tail = tail; 149 fi->fi_base = intern(base); 150 fi->fi_optx = optx; 151 fi->fi_optf = NULL; 152 fi->fi_mkrule = rule; 153 *nextfile = fi; 154 nextfile = &fi->fi_next; 155 return; 156 bad: 157 expr_free(optx); 158 } 159 160 void 161 addobject(path, optx, flags) 162 const char *path; 163 struct nvlist *optx; 164 int flags; 165 { 166 struct objects *oi; 167 168 /* 169 * Commit this object to memory. We will decide later whether it 170 * will be used after all. 171 */ 172 oi = emalloc(sizeof *oi); 173 if (ht_insert(pathtab, path, oi)) { 174 free(oi); 175 if ((oi = ht_lookup(pathtab, path)) == NULL) 176 panic("addfile: ht_lookup(%s)", path); 177 error("duplicate file %s", path); 178 xerror(oi->oi_srcfile, oi->oi_srcline, 179 "here is the original definition"); 180 } 181 oi->oi_next = NULL; 182 oi->oi_srcfile = yyfile; 183 oi->oi_srcline = currentline(); 184 oi->oi_flags = flags; 185 oi->oi_path = path; 186 oi->oi_optx = optx; 187 oi->oi_optf = NULL; 188 *nextobject = oi; 189 nextobject = &oi->oi_next; 190 } 191 192 /* 193 * We have finished reading some "files" file, either ../../conf/files 194 * or ./files.$machine. Make sure that everything that is flagged as 195 * needing a count is reasonable. (This prevents ../../conf/files from 196 * depending on some machine-specific device.) 197 */ 198 void 199 checkfiles() 200 { 201 struct files *fi, *last; 202 203 last = NULL; 204 for (fi = *unchecked; fi != NULL; last = fi, fi = fi->fi_next) 205 if ((fi->fi_flags & FI_NEEDSCOUNT) != 0) 206 (void)expr_eval(fi->fi_optx, checkaux, fi); 207 if (last != NULL) 208 unchecked = &last->fi_next; 209 } 210 211 /* 212 * Auxiliary function for checkfiles, called from expr_eval. 213 * We are not actually interested in the expression's value. 214 */ 215 static int 216 checkaux(name, context) 217 const char *name; 218 void *context; 219 { 220 struct files *fi = context; 221 222 if (ht_lookup(devbasetab, name) == NULL) { 223 xerror(fi->fi_srcfile, fi->fi_srcline, 224 "`%s' is not a countable device", 225 name); 226 /* keep fixfiles() from complaining again */ 227 fi->fi_flags |= FI_HIDDEN; 228 } 229 return (0); 230 } 231 232 /* 233 * We have finished reading everything. Tack the files down: calculate 234 * selection and counts as needed. Check that the object files built 235 * from the selected sources do not collide. 236 */ 237 int 238 fixfiles() 239 { 240 struct files *fi, *ofi; 241 struct nvlist *flathead, **flatp; 242 int err, sel; 243 244 err = 0; 245 for (fi = allfiles; fi != NULL; fi = fi->fi_next) { 246 /* Skip files that generated counted-device complaints. */ 247 if (fi->fi_flags & FI_HIDDEN) 248 continue; 249 250 /* Optional: see if it is to be included. */ 251 if (fi->fi_optx != NULL) { 252 flathead = NULL; 253 flatp = &flathead; 254 sel = expr_eval(fi->fi_optx, 255 fi->fi_flags & FI_NEEDSCOUNT ? fixcount : 256 fi->fi_flags & FI_NEEDSFLAG ? fixfsel : 257 fixsel, 258 &flatp); 259 fi->fi_optf = flathead; 260 if (!sel) 261 continue; 262 } 263 264 /* We like this file. Make sure it generates a unique .o. */ 265 if (ht_insert(basetab, fi->fi_base, fi)) { 266 if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL) 267 panic("fixfiles ht_lookup(%s)", fi->fi_base); 268 /* 269 * If the new file comes from a different source, 270 * allow the new one to override the old one. 271 */ 272 if (fi->fi_path != ofi->fi_path) { 273 if (ht_replace(basetab, fi->fi_base, fi) != 1) 274 panic("fixfiles ht_replace(%s)", 275 fi->fi_base); 276 ofi->fi_flags &= ~FI_SEL; 277 ofi->fi_flags |= FI_HIDDEN; 278 } else { 279 xerror(fi->fi_srcfile, fi->fi_srcline, 280 "object file collision on %s.o, from %s", 281 fi->fi_base, fi->fi_path); 282 xerror(ofi->fi_srcfile, ofi->fi_srcline, 283 "here is the previous file: %s", 284 ofi->fi_path); 285 err = 1; 286 } 287 } 288 fi->fi_flags |= FI_SEL; 289 } 290 return (err); 291 } 292 293 /* 294 * We have finished reading everything. Tack the objects down: calculate 295 * selection. 296 */ 297 int 298 fixobjects() 299 { 300 struct objects *oi; 301 struct nvlist *flathead, **flatp; 302 int err, sel; 303 304 err = 0; 305 for (oi = allobjects; oi != NULL; oi = oi->oi_next) { 306 /* Optional: see if it is to be included. */ 307 if (oi->oi_optx != NULL) { 308 flathead = NULL; 309 flatp = &flathead; 310 sel = expr_eval(oi->oi_optx, 311 oi->oi_flags & OI_NEEDSFLAG ? fixfsel : 312 fixsel, 313 &flatp); 314 oi->oi_optf = flathead; 315 if (!sel) 316 continue; 317 } 318 319 oi->oi_flags |= OI_SEL; 320 } 321 return (err); 322 } 323 324 /* 325 * Called when evaluating a needs-count expression. Make sure the 326 * atom is a countable device. The expression succeeds iff there 327 * is at least one of them (note that while `xx*' will not always 328 * set xx's d_umax > 0, you cannot mix '*' and needs-count). The 329 * mkheaders() routine wants a flattened, in-order list of the 330 * atoms for `#define name value' lines, so we build that as we 331 * are called to eval each atom. 332 */ 333 static int 334 fixcount(name, context) 335 const char *name; 336 void *context; 337 { 338 struct nvlist ***p = context; 339 struct devbase *dev; 340 struct nvlist *nv; 341 342 dev = ht_lookup(devbasetab, name); 343 if (dev == NULL) /* cannot occur here; we checked earlier */ 344 panic("fixcount(%s)", name); 345 nv = newnv(name, NULL, NULL, dev->d_umax, NULL); 346 **p = nv; 347 *p = &nv->nv_next; 348 (void)ht_insert(needcnttab, name, nv); 349 return (dev->d_umax != 0); 350 } 351 352 /* 353 * Called from fixfiles when eval'ing a selection expression for a 354 * file that will generate a .h with flags. We will need the flat list. 355 */ 356 static int 357 fixfsel(name, context) 358 const char *name; 359 void *context; 360 { 361 struct nvlist ***p = context; 362 struct nvlist *nv; 363 int sel; 364 365 sel = ht_lookup(selecttab, name) != NULL; 366 nv = newnv(name, NULL, NULL, sel, NULL); 367 **p = nv; 368 *p = &nv->nv_next; 369 return (sel); 370 } 371 372 /* 373 * As for fixfsel above, but we do not need the flat list. 374 */ 375 static int 376 fixsel(name, context) 377 const char *name; 378 void *context; 379 { 380 381 return (ht_lookup(selecttab, name) != NULL); 382 } 383 384 /* 385 * Eval an expression tree. Calls the given function on each node, 386 * passing it the given context & the name; return value is &/|/! of 387 * results of evaluating atoms. 388 * 389 * No short circuiting ever occurs. fn must return 0 or 1 (otherwise 390 * our mixing of C's bitwise & boolean here may give surprises). 391 */ 392 static int 393 expr_eval(expr, fn, context) 394 struct nvlist *expr; 395 int (*fn)(const char *, void *); 396 void *context; 397 { 398 int lhs, rhs; 399 400 switch (expr->nv_int) { 401 402 case FX_ATOM: 403 return ((*fn)(expr->nv_name, context)); 404 405 case FX_NOT: 406 return (!expr_eval(expr->nv_next, fn, context)); 407 408 case FX_AND: 409 lhs = expr_eval(expr->nv_ptr, fn, context); 410 rhs = expr_eval(expr->nv_next, fn, context); 411 return (lhs & rhs); 412 413 case FX_OR: 414 lhs = expr_eval(expr->nv_ptr, fn, context); 415 rhs = expr_eval(expr->nv_next, fn, context); 416 return (lhs | rhs); 417 } 418 panic("expr_eval %d", expr->nv_int); 419 return (0); 420 } 421 422 /* 423 * Free an expression tree. 424 */ 425 static void 426 expr_free(expr) 427 struct nvlist *expr; 428 { 429 struct nvlist *rhs; 430 431 /* This loop traverses down the RHS of each subexpression. */ 432 for (; expr != NULL; expr = rhs) { 433 switch (expr->nv_int) { 434 435 /* Atoms and !-exprs have no left hand side. */ 436 case FX_ATOM: 437 case FX_NOT: 438 break; 439 440 /* For AND and OR nodes, free the LHS. */ 441 case FX_AND: 442 case FX_OR: 443 expr_free(expr->nv_ptr); 444 break; 445 446 default: 447 panic("expr_free %d", expr->nv_int); 448 } 449 rhs = expr->nv_next; 450 nvfree(expr); 451 } 452 } 453 454 #ifdef DEBUG 455 /* 456 * Print expression tree. 457 */ 458 void 459 prexpr(expr) 460 struct nvlist *expr; 461 { 462 static void pr0(); 463 464 printf("expr ="); 465 pr0(expr); 466 printf("\n"); 467 (void)fflush(stdout); 468 } 469 470 static void 471 pr0(e) 472 struct nvlist *e; 473 { 474 475 switch (e->nv_int) { 476 case FX_ATOM: 477 printf(" %s", e->nv_name); 478 return; 479 case FX_NOT: 480 printf(" (!"); 481 break; 482 case FX_AND: 483 printf(" (&"); 484 break; 485 case FX_OR: 486 printf(" (|"); 487 break; 488 default: 489 printf(" (?%d?", e->nv_int); 490 break; 491 } 492 if (e->nv_ptr) 493 pr0(e->nv_ptr); 494 pr0(e->nv_next); 495 printf(")"); 496 } 497 #endif 498