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