1 /* $NetBSD: files.c,v 1.3 2006/08/26 18:17:13 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 return (1); 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 return (1); 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 return (1); 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 return (1); 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 return (1); 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 return (1); 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 } 424 425 /* 426 * Called when evaluating a needs-count expression. Make sure the 427 * atom is a countable device. The expression succeeds iff there 428 * is at least one of them (note that while `xx*' will not always 429 * set xx's d_umax > 0, you cannot mix '*' and needs-count). The 430 * mkheaders() routine wants a flattened, in-order list of the 431 * atoms for `#define name value' lines, so we build that as we 432 * are called to eval each atom. 433 */ 434 static int 435 fixcount(const char *name, void *context) 436 { 437 struct nvlist ***p = context; 438 struct devbase *dev; 439 struct nvlist *nv; 440 441 dev = ht_lookup(devbasetab, name); 442 if (dev == NULL) /* cannot occur here; we checked earlier */ 443 panic("fixcount(%s)", name); 444 nv = newnv(name, NULL, NULL, dev->d_umax, NULL); 445 **p = nv; 446 *p = &nv->nv_next; 447 (void)ht_insert(needcnttab, name, nv); 448 return (dev->d_umax != 0); 449 } 450 451 /* 452 * Called from fixfiles when eval'ing a selection expression for a 453 * file that will generate a .h with flags. We will need the flat list. 454 */ 455 static int 456 fixfsel(const char *name, void *context) 457 { 458 struct nvlist ***p = context; 459 struct nvlist *nv; 460 int sel; 461 462 sel = ht_lookup(selecttab, name) != NULL; 463 nv = newnv(name, NULL, NULL, sel, NULL); 464 **p = nv; 465 *p = &nv->nv_next; 466 return (sel); 467 } 468 469 /* 470 * As for fixfsel above, but we do not need the flat list. 471 */ 472 static int 473 fixsel(const char *name, void *context) 474 { 475 476 return (ht_lookup(selecttab, name) != NULL); 477 } 478 479 /* 480 * Eval an expression tree. Calls the given function on each node, 481 * passing it the given context & the name; return value is &/|/! of 482 * results of evaluating atoms. 483 * 484 * No short circuiting ever occurs. fn must return 0 or 1 (otherwise 485 * our mixing of C's bitwise & boolean here may give surprises). 486 */ 487 static int 488 expr_eval(struct nvlist *expr, int (*fn)(const char *, void *), void *context) 489 { 490 int lhs, rhs; 491 492 switch (expr->nv_int) { 493 494 case FX_ATOM: 495 return ((*fn)(expr->nv_name, context)); 496 497 case FX_NOT: 498 return (!expr_eval(expr->nv_next, fn, context)); 499 500 case FX_AND: 501 lhs = expr_eval(expr->nv_ptr, fn, context); 502 rhs = expr_eval(expr->nv_next, fn, context); 503 return (lhs & rhs); 504 505 case FX_OR: 506 lhs = expr_eval(expr->nv_ptr, fn, context); 507 rhs = expr_eval(expr->nv_next, fn, context); 508 return (lhs | rhs); 509 } 510 panic("expr_eval %d", expr->nv_int); 511 /* NOTREACHED */ 512 return (0); 513 } 514 515 /* 516 * Free an expression tree. 517 */ 518 static void 519 expr_free(struct nvlist *expr) 520 { 521 struct nvlist *rhs; 522 523 /* This loop traverses down the RHS of each subexpression. */ 524 for (; expr != NULL; expr = rhs) { 525 switch (expr->nv_int) { 526 527 /* Atoms and !-exprs have no left hand side. */ 528 case FX_ATOM: 529 case FX_NOT: 530 break; 531 532 /* For AND and OR nodes, free the LHS. */ 533 case FX_AND: 534 case FX_OR: 535 expr_free(expr->nv_ptr); 536 break; 537 538 default: 539 panic("expr_free %d", expr->nv_int); 540 } 541 rhs = expr->nv_next; 542 nvfree(expr); 543 } 544 } 545 546 #ifdef DEBUG 547 /* 548 * Print expression tree. 549 */ 550 void 551 prexpr(struct nvlist *expr) 552 { 553 static void pr0(); 554 555 printf("expr ="); 556 pr0(expr); 557 printf("\n"); 558 (void)fflush(stdout); 559 } 560 561 static void 562 pr0(struct nvlist *e) 563 { 564 565 switch (e->nv_int) { 566 case FX_ATOM: 567 printf(" %s", e->nv_name); 568 return; 569 case FX_NOT: 570 printf(" (!"); 571 break; 572 case FX_AND: 573 printf(" (&"); 574 break; 575 case FX_OR: 576 printf(" (|"); 577 break; 578 default: 579 printf(" (?%d?", e->nv_int); 580 break; 581 } 582 if (e->nv_ptr) 583 pr0(e->nv_ptr); 584 pr0(e->nv_next); 585 printf(")"); 586 } 587 #endif 588