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