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