1 /* $NetBSD: files.c,v 1.4 2006/09/27 19:05:46 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This software was developed by the Computer Systems Engineering group 8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 * contributed to Berkeley. 10 * 11 * All advertising materials mentioning features or use of this software 12 * must display the following acknowledgement: 13 * This product includes software developed by the University of 14 * California, Lawrence Berkeley Laboratories. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * from: @(#)files.c 8.1 (Berkeley) 6/6/93 41 */ 42 43 #if HAVE_NBTOOL_CONFIG_H 44 #include "nbtool_config.h" 45 #endif 46 47 #include <sys/param.h> 48 #include <errno.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <util.h> 53 #include "defs.h" 54 55 extern const char *yyfile; 56 57 /* 58 * We check that each full path name is unique. File base names 59 * should generally also be unique, e.g., having both a net/xx.c and 60 * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably 61 * wrong, but is permitted under some conditions. 62 */ 63 static struct hashtab *basetab; /* file base names */ 64 static struct hashtab *pathtab; /* full path names */ 65 66 static struct files **unchecked; 67 68 static int checkaux(const char *, void *); 69 static int fixcount(const char *, void *); 70 static int fixfsel(const char *, void *); 71 static int fixsel(const char *, void *); 72 static int expr_eval(struct nvlist *, 73 int (*)(const char *, void *), void *); 74 static void expr_free(struct nvlist *); 75 76 void 77 initfiles(void) 78 { 79 80 basetab = ht_new(); 81 pathtab = ht_new(); 82 TAILQ_INIT(&allfiles); 83 unchecked = &TAILQ_FIRST(&allfiles); 84 TAILQ_INIT(&allobjects); 85 } 86 87 void 88 addfile(const char *path, struct nvlist *optx, int flags, const char *rule) 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 = ecalloc(1, 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 131 /* 132 * If it's a duplicate entry, it is must specify a make 133 * rule, and only a make rule, and must come from 134 * a different source file than the original entry. 135 * If it does otherwise, it is disallowed. This allows 136 * machine-dependent files to override the compilation 137 * options for specific files. 138 */ 139 if (rule != NULL && optx == NULL && flags == 0 && 140 yyfile != fi->fi_srcfile) { 141 fi->fi_mkrule = rule; 142 return; 143 } 144 error("duplicate file %s", path); 145 xerror(fi->fi_srcfile, fi->fi_srcline, 146 "here is the original definition"); 147 goto bad; 148 } 149 memcpy(base, tail, baselen); 150 base[baselen] = 0; 151 fi->fi_srcfile = yyfile; 152 fi->fi_srcline = currentline(); 153 fi->fi_flags = flags; 154 fi->fi_path = path; 155 fi->fi_tail = tail; 156 fi->fi_base = intern(base); 157 fi->fi_prefix = SLIST_EMPTY(&prefixes) ? NULL : 158 SLIST_FIRST(&prefixes)->pf_prefix; 159 fi->fi_optx = optx; 160 fi->fi_optf = NULL; 161 fi->fi_mkrule = rule; 162 TAILQ_INSERT_TAIL(&allfiles, fi, fi_next); 163 return; 164 bad: 165 expr_free(optx); 166 } 167 168 void 169 addobject(const char *path, struct nvlist *optx, int flags) 170 { 171 struct objects *oi; 172 173 /* 174 * Commit this object to memory. We will decide later whether it 175 * will be used after all. 176 */ 177 oi = ecalloc(1, sizeof *oi); 178 if (ht_insert(pathtab, path, oi)) { 179 free(oi); 180 if ((oi = ht_lookup(pathtab, path)) == NULL) 181 panic("addfile: ht_lookup(%s)", path); 182 error("duplicate file %s", path); 183 xerror(oi->oi_srcfile, oi->oi_srcline, 184 "here is the original definition"); 185 } 186 oi->oi_srcfile = yyfile; 187 oi->oi_srcline = currentline(); 188 oi->oi_flags = flags; 189 oi->oi_path = path; 190 oi->oi_prefix = SLIST_EMPTY(&prefixes) ? NULL : 191 SLIST_FIRST(&prefixes)->pf_prefix; 192 oi->oi_optx = optx; 193 oi->oi_optf = NULL; 194 TAILQ_INSERT_TAIL(&allobjects, oi, oi_next); 195 return; 196 } 197 198 /* 199 * We have finished reading some "files" file, either ../../conf/files 200 * or ./files.$machine. Make sure that everything that is flagged as 201 * needing a count is reasonable. (This prevents ../../conf/files from 202 * depending on some machine-specific device.) 203 */ 204 void 205 checkfiles(void) 206 { 207 struct files *fi, *last; 208 209 last = NULL; 210 for (fi = *unchecked; fi != NULL; 211 last = fi, fi = TAILQ_NEXT(fi, fi_next)) { 212 if ((fi->fi_flags & FI_NEEDSCOUNT) != 0) 213 (void)expr_eval(fi->fi_optx, checkaux, fi); 214 } 215 if (last != NULL) 216 unchecked = &TAILQ_NEXT(last, fi_next); 217 } 218 219 /* 220 * Auxiliary function for checkfiles, called from expr_eval. 221 * We are not actually interested in the expression's value. 222 */ 223 static int 224 checkaux(const char *name, void *context) 225 { 226 struct files *fi = context; 227 228 if (ht_lookup(devbasetab, name) == NULL) { 229 xerror(fi->fi_srcfile, fi->fi_srcline, 230 "`%s' is not a countable device", 231 name); 232 /* keep fixfiles() from complaining again */ 233 fi->fi_flags |= FI_HIDDEN; 234 } 235 return (0); 236 } 237 238 /* 239 * We have finished reading everything. Tack the files down: calculate 240 * selection and counts as needed. Check that the object files built 241 * from the selected sources do not collide. 242 */ 243 int 244 fixfiles(void) 245 { 246 struct files *fi, *ofi; 247 struct nvlist *flathead, **flatp; 248 int err, sel; 249 250 err = 0; 251 TAILQ_FOREACH(fi, &allfiles, fi_next) { 252 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_flags & FIT_FORCESELECT) 259 { 260 /* include it */ ; 261 } 262 else 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_path != ofi->fi_path) { 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_path); 293 xerror(ofi->fi_srcfile, ofi->fi_srcline, 294 "here is the previous file: %s", 295 ofi->fi_path); 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 TAILQ_FOREACH(oi, &allobjects, 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 * We have finished reading everything. Tack the devsws down: calculate 337 * selection. 338 */ 339 int 340 fixdevsw(void) 341 { 342 struct devm *dm, *res; 343 struct hashtab *fixdevmtab; 344 char mstr[16]; 345 346 fixdevmtab = ht_new(); 347 348 TAILQ_FOREACH(dm, &alldevms, dm_next) { 349 res = ht_lookup(fixdevmtab, intern(dm->dm_name)); 350 if (res != NULL) { 351 if (res->dm_cmajor != dm->dm_cmajor || 352 res->dm_bmajor != dm->dm_bmajor) { 353 xerror(res->dm_srcfile, res->dm_srcline, 354 "device-major '%s' is inconsistent: " 355 "block %d, char %d", res->dm_name, 356 res->dm_bmajor, res->dm_cmajor); 357 xerror(dm->dm_srcfile, dm->dm_srcline, 358 "device-major '%s' is inconsistent: " 359 "block %d, char %d", dm->dm_name, 360 dm->dm_bmajor, dm->dm_cmajor); 361 goto out; 362 } else { 363 xerror(dm->dm_srcfile, dm->dm_srcline, 364 "device-major '%s' is duplicated: " 365 "block %d, char %d", 366 dm->dm_name, dm->dm_bmajor, 367 dm->dm_cmajor); 368 goto out; 369 } 370 } 371 if (ht_insert(fixdevmtab, intern(dm->dm_name), dm)) { 372 panic("fixdevsw: %s char %d block %d", 373 dm->dm_name, dm->dm_cmajor, dm->dm_bmajor); 374 } 375 376 if (dm->dm_opts != NULL && 377 !expr_eval(dm->dm_opts, fixsel, NULL)) 378 continue; 379 380 if (dm->dm_cmajor != -1) { 381 if (ht_lookup(cdevmtab, intern(dm->dm_name)) != NULL) { 382 xerror(dm->dm_srcfile, dm->dm_srcline, 383 "device-major of character device '%s' " 384 "is already defined", dm->dm_name); 385 goto out; 386 } 387 (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_cmajor); 388 if (ht_lookup(cdevmtab, intern(mstr)) != NULL) { 389 xerror(dm->dm_srcfile, dm->dm_srcline, 390 "device-major of character major '%d' " 391 "is already defined", dm->dm_cmajor); 392 goto out; 393 } 394 if (ht_insert(cdevmtab, intern(dm->dm_name), dm) || 395 ht_insert(cdevmtab, intern(mstr), dm)) { 396 panic("fixdevsw: %s character major %d", 397 dm->dm_name, dm->dm_cmajor); 398 } 399 } 400 if (dm->dm_bmajor != -1) { 401 if (ht_lookup(bdevmtab, intern(dm->dm_name)) != NULL) { 402 xerror(dm->dm_srcfile, dm->dm_srcline, 403 "device-major of block device '%s' " 404 "is already defined", dm->dm_name); 405 goto out; 406 } 407 (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_bmajor); 408 if (ht_lookup(bdevmtab, intern(mstr)) != NULL) { 409 xerror(dm->dm_srcfile, dm->dm_srcline, 410 "device-major of block major '%d' " 411 "is already defined", dm->dm_bmajor); 412 goto out; 413 } 414 if (ht_insert(bdevmtab, intern(dm->dm_name), dm) || 415 ht_insert(bdevmtab, intern(mstr), dm)) { 416 panic("fixdevsw: %s block major %d", 417 dm->dm_name, dm->dm_bmajor); 418 } 419 } 420 } 421 422 return (0); 423 out: 424 ht_free(fixdevmtab); 425 return (1); 426 } 427 428 /* 429 * Called when evaluating a needs-count expression. Make sure the 430 * atom is a countable device. The expression succeeds iff there 431 * is at least one of them (note that while `xx*' will not always 432 * set xx's d_umax > 0, you cannot mix '*' and needs-count). The 433 * mkheaders() routine wants a flattened, in-order list of the 434 * atoms for `#define name value' lines, so we build that as we 435 * are called to eval each atom. 436 */ 437 static int 438 fixcount(const char *name, void *context) 439 { 440 struct nvlist ***p = context; 441 struct devbase *dev; 442 struct nvlist *nv; 443 444 dev = ht_lookup(devbasetab, name); 445 if (dev == NULL) /* cannot occur here; we checked earlier */ 446 panic("fixcount(%s)", name); 447 nv = newnv(name, NULL, NULL, dev->d_umax, NULL); 448 **p = nv; 449 *p = &nv->nv_next; 450 (void)ht_insert(needcnttab, name, nv); 451 return (dev->d_umax != 0); 452 } 453 454 /* 455 * Called from fixfiles when eval'ing a selection expression for a 456 * file that will generate a .h with flags. We will need the flat list. 457 */ 458 static int 459 fixfsel(const char *name, void *context) 460 { 461 struct nvlist ***p = context; 462 struct nvlist *nv; 463 int sel; 464 465 sel = ht_lookup(selecttab, name) != NULL; 466 nv = newnv(name, NULL, NULL, sel, NULL); 467 **p = nv; 468 *p = &nv->nv_next; 469 return (sel); 470 } 471 472 /* 473 * As for fixfsel above, but we do not need the flat list. 474 */ 475 static int 476 fixsel(const char *name, void *context) 477 { 478 479 return (ht_lookup(selecttab, name) != NULL); 480 } 481 482 /* 483 * Eval an expression tree. Calls the given function on each node, 484 * passing it the given context & the name; return value is &/|/! of 485 * results of evaluating atoms. 486 * 487 * No short circuiting ever occurs. fn must return 0 or 1 (otherwise 488 * our mixing of C's bitwise & boolean here may give surprises). 489 */ 490 static int 491 expr_eval(struct nvlist *expr, int (*fn)(const char *, void *), void *context) 492 { 493 int lhs, rhs; 494 495 switch (expr->nv_int) { 496 497 case FX_ATOM: 498 return ((*fn)(expr->nv_name, context)); 499 500 case FX_NOT: 501 return (!expr_eval(expr->nv_next, fn, context)); 502 503 case FX_AND: 504 lhs = expr_eval(expr->nv_ptr, fn, context); 505 rhs = expr_eval(expr->nv_next, fn, context); 506 return (lhs & rhs); 507 508 case FX_OR: 509 lhs = expr_eval(expr->nv_ptr, fn, context); 510 rhs = expr_eval(expr->nv_next, fn, context); 511 return (lhs | rhs); 512 } 513 panic("expr_eval %d", expr->nv_int); 514 /* NOTREACHED */ 515 return (0); 516 } 517 518 /* 519 * Free an expression tree. 520 */ 521 static void 522 expr_free(struct nvlist *expr) 523 { 524 struct nvlist *rhs; 525 526 /* This loop traverses down the RHS of each subexpression. */ 527 for (; expr != NULL; expr = rhs) { 528 switch (expr->nv_int) { 529 530 /* Atoms and !-exprs have no left hand side. */ 531 case FX_ATOM: 532 case FX_NOT: 533 break; 534 535 /* For AND and OR nodes, free the LHS. */ 536 case FX_AND: 537 case FX_OR: 538 expr_free(expr->nv_ptr); 539 break; 540 541 default: 542 panic("expr_free %d", expr->nv_int); 543 } 544 rhs = expr->nv_next; 545 nvfree(expr); 546 } 547 } 548 549 #ifdef DEBUG 550 /* 551 * Print expression tree. 552 */ 553 void 554 prexpr(struct nvlist *expr) 555 { 556 static void pr0(); 557 558 printf("expr ="); 559 pr0(expr); 560 printf("\n"); 561 (void)fflush(stdout); 562 } 563 564 static void 565 pr0(struct nvlist *e) 566 { 567 568 switch (e->nv_int) { 569 case FX_ATOM: 570 printf(" %s", e->nv_name); 571 return; 572 case FX_NOT: 573 printf(" (!"); 574 break; 575 case FX_AND: 576 printf(" (&"); 577 break; 578 case FX_OR: 579 printf(" (|"); 580 break; 581 default: 582 printf(" (?%d?", e->nv_int); 583 break; 584 } 585 if (e->nv_ptr) 586 pr0(e->nv_ptr); 587 pr0(e->nv_next); 588 printf(")"); 589 } 590 #endif 591