1 /* $NetBSD: files.c,v 1.1 2005/06/05 18:19:53 thorpej 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 /* Skip files that generated counted-device complaints. */ 252 if (fi->fi_flags & FI_HIDDEN) 253 continue; 254 255 /* Optional: see if it is to be included. */ 256 if (fi->fi_optx != NULL) { 257 flathead = NULL; 258 flatp = &flathead; 259 sel = expr_eval(fi->fi_optx, 260 fi->fi_flags & FI_NEEDSCOUNT ? fixcount : 261 fi->fi_flags & FI_NEEDSFLAG ? fixfsel : 262 fixsel, 263 &flatp); 264 fi->fi_optf = flathead; 265 if (!sel) 266 continue; 267 } 268 269 /* We like this file. Make sure it generates a unique .o. */ 270 if (ht_insert(basetab, fi->fi_base, fi)) { 271 if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL) 272 panic("fixfiles ht_lookup(%s)", fi->fi_base); 273 /* 274 * If the new file comes from a different source, 275 * allow the new one to override the old one. 276 */ 277 if (fi->fi_path != ofi->fi_path) { 278 if (ht_replace(basetab, fi->fi_base, fi) != 1) 279 panic("fixfiles ht_replace(%s)", 280 fi->fi_base); 281 ofi->fi_flags &= ~FI_SEL; 282 ofi->fi_flags |= FI_HIDDEN; 283 } else { 284 xerror(fi->fi_srcfile, fi->fi_srcline, 285 "object file collision on %s.o, from %s", 286 fi->fi_base, fi->fi_path); 287 xerror(ofi->fi_srcfile, ofi->fi_srcline, 288 "here is the previous file: %s", 289 ofi->fi_path); 290 err = 1; 291 } 292 } 293 fi->fi_flags |= FI_SEL; 294 } 295 return (err); 296 } 297 298 /* 299 * We have finished reading everything. Tack the objects down: calculate 300 * selection. 301 */ 302 int 303 fixobjects(void) 304 { 305 struct objects *oi; 306 struct nvlist *flathead, **flatp; 307 int err, sel; 308 309 err = 0; 310 TAILQ_FOREACH(oi, &allobjects, oi_next) { 311 /* Optional: see if it is to be included. */ 312 if (oi->oi_optx != NULL) { 313 flathead = NULL; 314 flatp = &flathead; 315 sel = expr_eval(oi->oi_optx, 316 oi->oi_flags & OI_NEEDSFLAG ? fixfsel : 317 fixsel, 318 &flatp); 319 oi->oi_optf = flathead; 320 if (!sel) 321 continue; 322 } 323 324 oi->oi_flags |= OI_SEL; 325 } 326 return (err); 327 } 328 329 /* 330 * We have finished reading everything. Tack the devsws down: calculate 331 * selection. 332 */ 333 int 334 fixdevsw(void) 335 { 336 struct devm *dm, *res; 337 struct hashtab *fixdevmtab; 338 char mstr[16]; 339 340 fixdevmtab = ht_new(); 341 342 TAILQ_FOREACH(dm, &alldevms, dm_next) { 343 res = ht_lookup(fixdevmtab, intern(dm->dm_name)); 344 if (res != NULL) { 345 if (res->dm_cmajor != dm->dm_cmajor || 346 res->dm_bmajor != dm->dm_bmajor) { 347 xerror(res->dm_srcfile, res->dm_srcline, 348 "device-major '%s' is inconsistent: " 349 "block %d, char %d", res->dm_name, 350 res->dm_bmajor, res->dm_cmajor); 351 xerror(dm->dm_srcfile, dm->dm_srcline, 352 "device-major '%s' is inconsistent: " 353 "block %d, char %d", dm->dm_name, 354 dm->dm_bmajor, dm->dm_cmajor); 355 return (1); 356 } else { 357 xerror(dm->dm_srcfile, dm->dm_srcline, 358 "device-major '%s' is duplicated: " 359 "block %d, char %d", 360 dm->dm_name, dm->dm_bmajor, 361 dm->dm_cmajor); 362 return (1); 363 } 364 } 365 if (ht_insert(fixdevmtab, intern(dm->dm_name), dm)) { 366 panic("fixdevsw: %s char %d block %d", 367 dm->dm_name, dm->dm_cmajor, dm->dm_bmajor); 368 } 369 370 if (dm->dm_opts != NULL && 371 !expr_eval(dm->dm_opts, fixsel, NULL)) 372 continue; 373 374 if (dm->dm_cmajor != -1) { 375 if (ht_lookup(cdevmtab, intern(dm->dm_name)) != NULL) { 376 xerror(dm->dm_srcfile, dm->dm_srcline, 377 "device-major of character device '%s' " 378 "is already defined", dm->dm_name); 379 return (1); 380 } 381 (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_cmajor); 382 if (ht_lookup(cdevmtab, intern(mstr)) != NULL) { 383 xerror(dm->dm_srcfile, dm->dm_srcline, 384 "device-major of character major '%d' " 385 "is already defined", dm->dm_cmajor); 386 return (1); 387 } 388 if (ht_insert(cdevmtab, intern(dm->dm_name), dm) || 389 ht_insert(cdevmtab, intern(mstr), dm)) { 390 panic("fixdevsw: %s character major %d", 391 dm->dm_name, dm->dm_cmajor); 392 } 393 } 394 if (dm->dm_bmajor != -1) { 395 if (ht_lookup(bdevmtab, intern(dm->dm_name)) != NULL) { 396 xerror(dm->dm_srcfile, dm->dm_srcline, 397 "device-major of block device '%s' " 398 "is already defined", dm->dm_name); 399 return (1); 400 } 401 (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_bmajor); 402 if (ht_lookup(bdevmtab, intern(mstr)) != NULL) { 403 xerror(dm->dm_srcfile, dm->dm_srcline, 404 "device-major of block major '%d' " 405 "is already defined", dm->dm_bmajor); 406 return (1); 407 } 408 if (ht_insert(bdevmtab, intern(dm->dm_name), dm) || 409 ht_insert(bdevmtab, intern(mstr), dm)) { 410 panic("fixdevsw: %s block major %d", 411 dm->dm_name, dm->dm_bmajor); 412 } 413 } 414 } 415 416 return (0); 417 } 418 419 /* 420 * Called when evaluating a needs-count expression. Make sure the 421 * atom is a countable device. The expression succeeds iff there 422 * is at least one of them (note that while `xx*' will not always 423 * set xx's d_umax > 0, you cannot mix '*' and needs-count). The 424 * mkheaders() routine wants a flattened, in-order list of the 425 * atoms for `#define name value' lines, so we build that as we 426 * are called to eval each atom. 427 */ 428 static int 429 fixcount(const char *name, void *context) 430 { 431 struct nvlist ***p = context; 432 struct devbase *dev; 433 struct nvlist *nv; 434 435 dev = ht_lookup(devbasetab, name); 436 if (dev == NULL) /* cannot occur here; we checked earlier */ 437 panic("fixcount(%s)", name); 438 nv = newnv(name, NULL, NULL, dev->d_umax, NULL); 439 **p = nv; 440 *p = &nv->nv_next; 441 (void)ht_insert(needcnttab, name, nv); 442 return (dev->d_umax != 0); 443 } 444 445 /* 446 * Called from fixfiles when eval'ing a selection expression for a 447 * file that will generate a .h with flags. We will need the flat list. 448 */ 449 static int 450 fixfsel(const char *name, void *context) 451 { 452 struct nvlist ***p = context; 453 struct nvlist *nv; 454 int sel; 455 456 sel = ht_lookup(selecttab, name) != NULL; 457 nv = newnv(name, NULL, NULL, sel, NULL); 458 **p = nv; 459 *p = &nv->nv_next; 460 return (sel); 461 } 462 463 /* 464 * As for fixfsel above, but we do not need the flat list. 465 */ 466 static int 467 fixsel(const char *name, void *context) 468 { 469 470 return (ht_lookup(selecttab, name) != NULL); 471 } 472 473 /* 474 * Eval an expression tree. Calls the given function on each node, 475 * passing it the given context & the name; return value is &/|/! of 476 * results of evaluating atoms. 477 * 478 * No short circuiting ever occurs. fn must return 0 or 1 (otherwise 479 * our mixing of C's bitwise & boolean here may give surprises). 480 */ 481 static int 482 expr_eval(struct nvlist *expr, int (*fn)(const char *, void *), void *context) 483 { 484 int lhs, rhs; 485 486 switch (expr->nv_int) { 487 488 case FX_ATOM: 489 return ((*fn)(expr->nv_name, context)); 490 491 case FX_NOT: 492 return (!expr_eval(expr->nv_next, fn, context)); 493 494 case FX_AND: 495 lhs = expr_eval(expr->nv_ptr, fn, context); 496 rhs = expr_eval(expr->nv_next, fn, context); 497 return (lhs & rhs); 498 499 case FX_OR: 500 lhs = expr_eval(expr->nv_ptr, fn, context); 501 rhs = expr_eval(expr->nv_next, fn, context); 502 return (lhs | rhs); 503 } 504 panic("expr_eval %d", expr->nv_int); 505 /* NOTREACHED */ 506 return (0); 507 } 508 509 /* 510 * Free an expression tree. 511 */ 512 static void 513 expr_free(struct nvlist *expr) 514 { 515 struct nvlist *rhs; 516 517 /* This loop traverses down the RHS of each subexpression. */ 518 for (; expr != NULL; expr = rhs) { 519 switch (expr->nv_int) { 520 521 /* Atoms and !-exprs have no left hand side. */ 522 case FX_ATOM: 523 case FX_NOT: 524 break; 525 526 /* For AND and OR nodes, free the LHS. */ 527 case FX_AND: 528 case FX_OR: 529 expr_free(expr->nv_ptr); 530 break; 531 532 default: 533 panic("expr_free %d", expr->nv_int); 534 } 535 rhs = expr->nv_next; 536 nvfree(expr); 537 } 538 } 539 540 #ifdef DEBUG 541 /* 542 * Print expression tree. 543 */ 544 void 545 prexpr(struct nvlist *expr) 546 { 547 static void pr0(); 548 549 printf("expr ="); 550 pr0(expr); 551 printf("\n"); 552 (void)fflush(stdout); 553 } 554 555 static void 556 pr0(struct nvlist *e) 557 { 558 559 switch (e->nv_int) { 560 case FX_ATOM: 561 printf(" %s", e->nv_name); 562 return; 563 case FX_NOT: 564 printf(" (!"); 565 break; 566 case FX_AND: 567 printf(" (&"); 568 break; 569 case FX_OR: 570 printf(" (|"); 571 break; 572 default: 573 printf(" (?%d?", e->nv_int); 574 break; 575 } 576 if (e->nv_ptr) 577 pr0(e->nv_ptr); 578 pr0(e->nv_next); 579 printf(")"); 580 } 581 #endif 582