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