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