1 /* $NetBSD: files.c,v 1.2 2005/11/07 03:26:20 erh 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 "defs.h" 53 54 extern const char *yyfile; 55 56 /* 57 * We check that each full path name is unique. File base names 58 * should generally also be unique, e.g., having both a net/xx.c and 59 * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably 60 * wrong, but is permitted under some conditions. 61 */ 62 static struct hashtab *basetab; /* file base names */ 63 static struct hashtab *pathtab; /* full path names */ 64 65 static struct files **unchecked; 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 TAILQ_INIT(&allfiles); 82 unchecked = &TAILQ_FIRST(&allfiles); 83 TAILQ_INIT(&allobjects); 84 } 85 86 void 87 addfile(const char *path, struct nvlist *optx, int flags, const char *rule) 88 { 89 struct files *fi; 90 const char *dotp, *tail; 91 size_t baselen; 92 int needc, needf; 93 char base[200]; 94 95 /* check various errors */ 96 needc = flags & FI_NEEDSCOUNT; 97 needf = flags & FI_NEEDSFLAG; 98 if (needc && needf) { 99 error("cannot mix needs-count and needs-flag"); 100 goto bad; 101 } 102 if (optx == NULL && (needc || needf)) { 103 error("nothing to %s for %s", needc ? "count" : "flag", path); 104 goto bad; 105 } 106 107 /* find last part of pathname, and same without trailing suffix */ 108 tail = strrchr(path, '/'); 109 if (tail == NULL) 110 tail = path; 111 else 112 tail++; 113 dotp = strrchr(tail, '.'); 114 if (dotp == NULL || dotp[1] == 0 || 115 (baselen = dotp - tail) >= sizeof(base)) { 116 error("invalid pathname `%s'", path); 117 goto bad; 118 } 119 120 /* 121 * Commit this file to memory. We will decide later whether it 122 * will be used after all. 123 */ 124 fi = ecalloc(1, sizeof *fi); 125 if (ht_insert(pathtab, path, fi)) { 126 free(fi); 127 if ((fi = ht_lookup(pathtab, path)) == NULL) 128 panic("addfile: ht_lookup(%s)", path); 129 130 /* 131 * If it's a duplicate entry, it is must specify a make 132 * rule, and only a make rule, and must come from 133 * a different source file than the original entry. 134 * If it does otherwise, it is disallowed. This allows 135 * machine-dependent files to override the compilation 136 * options for specific files. 137 */ 138 if (rule != NULL && optx == NULL && flags == 0 && 139 yyfile != fi->fi_srcfile) { 140 fi->fi_mkrule = rule; 141 return; 142 } 143 error("duplicate file %s", path); 144 xerror(fi->fi_srcfile, fi->fi_srcline, 145 "here is the original definition"); 146 goto bad; 147 } 148 memcpy(base, tail, baselen); 149 base[baselen] = 0; 150 fi->fi_srcfile = yyfile; 151 fi->fi_srcline = currentline(); 152 fi->fi_flags = flags; 153 fi->fi_path = path; 154 fi->fi_tail = tail; 155 fi->fi_base = intern(base); 156 fi->fi_prefix = SLIST_EMPTY(&prefixes) ? NULL : 157 SLIST_FIRST(&prefixes)->pf_prefix; 158 fi->fi_optx = optx; 159 fi->fi_optf = NULL; 160 fi->fi_mkrule = rule; 161 TAILQ_INSERT_TAIL(&allfiles, fi, fi_next); 162 return; 163 bad: 164 expr_free(optx); 165 } 166 167 void 168 addobject(const char *path, struct nvlist *optx, int flags) 169 { 170 struct objects *oi; 171 172 /* 173 * Commit this object to memory. We will decide later whether it 174 * will be used after all. 175 */ 176 oi = ecalloc(1, sizeof *oi); 177 if (ht_insert(pathtab, path, oi)) { 178 free(oi); 179 if ((oi = ht_lookup(pathtab, path)) == NULL) 180 panic("addfile: ht_lookup(%s)", path); 181 error("duplicate file %s", path); 182 xerror(oi->oi_srcfile, oi->oi_srcline, 183 "here is the original definition"); 184 } 185 oi->oi_srcfile = yyfile; 186 oi->oi_srcline = currentline(); 187 oi->oi_flags = flags; 188 oi->oi_path = path; 189 oi->oi_prefix = SLIST_EMPTY(&prefixes) ? NULL : 190 SLIST_FIRST(&prefixes)->pf_prefix; 191 oi->oi_optx = optx; 192 oi->oi_optf = NULL; 193 TAILQ_INSERT_TAIL(&allobjects, oi, oi_next); 194 return; 195 } 196 197 /* 198 * We have finished reading some "files" file, either ../../conf/files 199 * or ./files.$machine. Make sure that everything that is flagged as 200 * needing a count is reasonable. (This prevents ../../conf/files from 201 * depending on some machine-specific device.) 202 */ 203 void 204 checkfiles(void) 205 { 206 struct files *fi, *last; 207 208 last = NULL; 209 for (fi = *unchecked; fi != NULL; 210 last = fi, fi = TAILQ_NEXT(fi, fi_next)) { 211 if ((fi->fi_flags & FI_NEEDSCOUNT) != 0) 212 (void)expr_eval(fi->fi_optx, checkaux, fi); 213 } 214 if (last != NULL) 215 unchecked = &TAILQ_NEXT(last, fi_next); 216 } 217 218 /* 219 * Auxiliary function for checkfiles, called from expr_eval. 220 * We are not actually interested in the expression's value. 221 */ 222 static int 223 checkaux(const char *name, void *context) 224 { 225 struct files *fi = context; 226 227 if (ht_lookup(devbasetab, name) == NULL) { 228 xerror(fi->fi_srcfile, fi->fi_srcline, 229 "`%s' is not a countable device", 230 name); 231 /* keep fixfiles() from complaining again */ 232 fi->fi_flags |= FI_HIDDEN; 233 } 234 return (0); 235 } 236 237 /* 238 * We have finished reading everything. Tack the files down: calculate 239 * selection and counts as needed. Check that the object files built 240 * from the selected sources do not collide. 241 */ 242 int 243 fixfiles(void) 244 { 245 struct files *fi, *ofi; 246 struct nvlist *flathead, **flatp; 247 int err, sel; 248 249 err = 0; 250 TAILQ_FOREACH(fi, &allfiles, fi_next) { 251 252 /* Skip files that generated counted-device complaints. */ 253 if (fi->fi_flags & FI_HIDDEN) 254 continue; 255 256 /* Optional: see if it is to be included. */ 257 if (fi->fi_flags & FIT_FORCESELECT) 258 { 259 /* include it */ ; 260 } 261 else if (fi->fi_optx != NULL) { 262 flathead = NULL; 263 flatp = &flathead; 264 sel = expr_eval(fi->fi_optx, 265 fi->fi_flags & FI_NEEDSCOUNT ? fixcount : 266 fi->fi_flags & FI_NEEDSFLAG ? fixfsel : 267 fixsel, 268 &flatp); 269 fi->fi_optf = flathead; 270 if (!sel) 271 continue; 272 } 273 274 /* We like this file. Make sure it generates a unique .o. */ 275 if (ht_insert(basetab, fi->fi_base, fi)) { 276 if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL) 277 panic("fixfiles ht_lookup(%s)", fi->fi_base); 278 /* 279 * If the new file comes from a different source, 280 * allow the new one to override the old one. 281 */ 282 if (fi->fi_path != ofi->fi_path) { 283 if (ht_replace(basetab, fi->fi_base, fi) != 1) 284 panic("fixfiles ht_replace(%s)", 285 fi->fi_base); 286 ofi->fi_flags &= ~FI_SEL; 287 ofi->fi_flags |= FI_HIDDEN; 288 } else { 289 xerror(fi->fi_srcfile, fi->fi_srcline, 290 "object file collision on %s.o, from %s", 291 fi->fi_base, fi->fi_path); 292 xerror(ofi->fi_srcfile, ofi->fi_srcline, 293 "here is the previous file: %s", 294 ofi->fi_path); 295 err = 1; 296 } 297 } 298 fi->fi_flags |= FI_SEL; 299 } 300 return (err); 301 } 302 303 /* 304 * We have finished reading everything. Tack the objects down: calculate 305 * selection. 306 */ 307 int 308 fixobjects(void) 309 { 310 struct objects *oi; 311 struct nvlist *flathead, **flatp; 312 int err, sel; 313 314 err = 0; 315 TAILQ_FOREACH(oi, &allobjects, oi_next) { 316 /* Optional: see if it is to be included. */ 317 if (oi->oi_optx != NULL) { 318 flathead = NULL; 319 flatp = &flathead; 320 sel = expr_eval(oi->oi_optx, 321 oi->oi_flags & OI_NEEDSFLAG ? fixfsel : 322 fixsel, 323 &flatp); 324 oi->oi_optf = flathead; 325 if (!sel) 326 continue; 327 } 328 329 oi->oi_flags |= OI_SEL; 330 } 331 return (err); 332 } 333 334 /* 335 * We have finished reading everything. Tack the devsws down: calculate 336 * selection. 337 */ 338 int 339 fixdevsw(void) 340 { 341 struct devm *dm, *res; 342 struct hashtab *fixdevmtab; 343 char mstr[16]; 344 345 fixdevmtab = ht_new(); 346 347 TAILQ_FOREACH(dm, &alldevms, dm_next) { 348 res = ht_lookup(fixdevmtab, intern(dm->dm_name)); 349 if (res != NULL) { 350 if (res->dm_cmajor != dm->dm_cmajor || 351 res->dm_bmajor != dm->dm_bmajor) { 352 xerror(res->dm_srcfile, res->dm_srcline, 353 "device-major '%s' is inconsistent: " 354 "block %d, char %d", res->dm_name, 355 res->dm_bmajor, res->dm_cmajor); 356 xerror(dm->dm_srcfile, dm->dm_srcline, 357 "device-major '%s' is inconsistent: " 358 "block %d, char %d", dm->dm_name, 359 dm->dm_bmajor, dm->dm_cmajor); 360 return (1); 361 } else { 362 xerror(dm->dm_srcfile, dm->dm_srcline, 363 "device-major '%s' is duplicated: " 364 "block %d, char %d", 365 dm->dm_name, dm->dm_bmajor, 366 dm->dm_cmajor); 367 return (1); 368 } 369 } 370 if (ht_insert(fixdevmtab, intern(dm->dm_name), dm)) { 371 panic("fixdevsw: %s char %d block %d", 372 dm->dm_name, dm->dm_cmajor, dm->dm_bmajor); 373 } 374 375 if (dm->dm_opts != NULL && 376 !expr_eval(dm->dm_opts, fixsel, NULL)) 377 continue; 378 379 if (dm->dm_cmajor != -1) { 380 if (ht_lookup(cdevmtab, intern(dm->dm_name)) != NULL) { 381 xerror(dm->dm_srcfile, dm->dm_srcline, 382 "device-major of character device '%s' " 383 "is already defined", dm->dm_name); 384 return (1); 385 } 386 (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_cmajor); 387 if (ht_lookup(cdevmtab, intern(mstr)) != NULL) { 388 xerror(dm->dm_srcfile, dm->dm_srcline, 389 "device-major of character major '%d' " 390 "is already defined", dm->dm_cmajor); 391 return (1); 392 } 393 if (ht_insert(cdevmtab, intern(dm->dm_name), dm) || 394 ht_insert(cdevmtab, intern(mstr), dm)) { 395 panic("fixdevsw: %s character major %d", 396 dm->dm_name, dm->dm_cmajor); 397 } 398 } 399 if (dm->dm_bmajor != -1) { 400 if (ht_lookup(bdevmtab, intern(dm->dm_name)) != NULL) { 401 xerror(dm->dm_srcfile, dm->dm_srcline, 402 "device-major of block device '%s' " 403 "is already defined", dm->dm_name); 404 return (1); 405 } 406 (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_bmajor); 407 if (ht_lookup(bdevmtab, intern(mstr)) != NULL) { 408 xerror(dm->dm_srcfile, dm->dm_srcline, 409 "device-major of block major '%d' " 410 "is already defined", dm->dm_bmajor); 411 return (1); 412 } 413 if (ht_insert(bdevmtab, intern(dm->dm_name), dm) || 414 ht_insert(bdevmtab, intern(mstr), dm)) { 415 panic("fixdevsw: %s block major %d", 416 dm->dm_name, dm->dm_bmajor); 417 } 418 } 419 } 420 421 return (0); 422 } 423 424 /* 425 * Called when evaluating a needs-count expression. Make sure the 426 * atom is a countable device. The expression succeeds iff there 427 * is at least one of them (note that while `xx*' will not always 428 * set xx's d_umax > 0, you cannot mix '*' and needs-count). The 429 * mkheaders() routine wants a flattened, in-order list of the 430 * atoms for `#define name value' lines, so we build that as we 431 * are called to eval each atom. 432 */ 433 static int 434 fixcount(const char *name, void *context) 435 { 436 struct nvlist ***p = context; 437 struct devbase *dev; 438 struct nvlist *nv; 439 440 dev = ht_lookup(devbasetab, name); 441 if (dev == NULL) /* cannot occur here; we checked earlier */ 442 panic("fixcount(%s)", name); 443 nv = newnv(name, NULL, NULL, dev->d_umax, NULL); 444 **p = nv; 445 *p = &nv->nv_next; 446 (void)ht_insert(needcnttab, name, nv); 447 return (dev->d_umax != 0); 448 } 449 450 /* 451 * Called from fixfiles when eval'ing a selection expression for a 452 * file that will generate a .h with flags. We will need the flat list. 453 */ 454 static int 455 fixfsel(const char *name, void *context) 456 { 457 struct nvlist ***p = context; 458 struct nvlist *nv; 459 int sel; 460 461 sel = ht_lookup(selecttab, name) != NULL; 462 nv = newnv(name, NULL, NULL, sel, NULL); 463 **p = nv; 464 *p = &nv->nv_next; 465 return (sel); 466 } 467 468 /* 469 * As for fixfsel above, but we do not need the flat list. 470 */ 471 static int 472 fixsel(const char *name, void *context) 473 { 474 475 return (ht_lookup(selecttab, name) != NULL); 476 } 477 478 /* 479 * Eval an expression tree. Calls the given function on each node, 480 * passing it the given context & the name; return value is &/|/! of 481 * results of evaluating atoms. 482 * 483 * No short circuiting ever occurs. fn must return 0 or 1 (otherwise 484 * our mixing of C's bitwise & boolean here may give surprises). 485 */ 486 static int 487 expr_eval(struct nvlist *expr, int (*fn)(const char *, void *), void *context) 488 { 489 int lhs, rhs; 490 491 switch (expr->nv_int) { 492 493 case FX_ATOM: 494 return ((*fn)(expr->nv_name, context)); 495 496 case FX_NOT: 497 return (!expr_eval(expr->nv_next, fn, context)); 498 499 case FX_AND: 500 lhs = expr_eval(expr->nv_ptr, fn, context); 501 rhs = expr_eval(expr->nv_next, fn, context); 502 return (lhs & rhs); 503 504 case FX_OR: 505 lhs = expr_eval(expr->nv_ptr, fn, context); 506 rhs = expr_eval(expr->nv_next, fn, context); 507 return (lhs | rhs); 508 } 509 panic("expr_eval %d", expr->nv_int); 510 /* NOTREACHED */ 511 return (0); 512 } 513 514 /* 515 * Free an expression tree. 516 */ 517 static void 518 expr_free(struct nvlist *expr) 519 { 520 struct nvlist *rhs; 521 522 /* This loop traverses down the RHS of each subexpression. */ 523 for (; expr != NULL; expr = rhs) { 524 switch (expr->nv_int) { 525 526 /* Atoms and !-exprs have no left hand side. */ 527 case FX_ATOM: 528 case FX_NOT: 529 break; 530 531 /* For AND and OR nodes, free the LHS. */ 532 case FX_AND: 533 case FX_OR: 534 expr_free(expr->nv_ptr); 535 break; 536 537 default: 538 panic("expr_free %d", expr->nv_int); 539 } 540 rhs = expr->nv_next; 541 nvfree(expr); 542 } 543 } 544 545 #ifdef DEBUG 546 /* 547 * Print expression tree. 548 */ 549 void 550 prexpr(struct nvlist *expr) 551 { 552 static void pr0(); 553 554 printf("expr ="); 555 pr0(expr); 556 printf("\n"); 557 (void)fflush(stdout); 558 } 559 560 static void 561 pr0(struct nvlist *e) 562 { 563 564 switch (e->nv_int) { 565 case FX_ATOM: 566 printf(" %s", e->nv_name); 567 return; 568 case FX_NOT: 569 printf(" (!"); 570 break; 571 case FX_AND: 572 printf(" (&"); 573 break; 574 case FX_OR: 575 printf(" (|"); 576 break; 577 default: 578 printf(" (?%d?", e->nv_int); 579 break; 580 } 581 if (e->nv_ptr) 582 pr0(e->nv_ptr); 583 pr0(e->nv_next); 584 printf(")"); 585 } 586 #endif 587