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