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