1 /* $NetBSD: files.c,v 1.12 2014/05/21 05:25:34 dholland 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 73 void 74 initfiles(void) 75 { 76 77 basetab = ht_new(); 78 pathtab = ht_new(); 79 TAILQ_INIT(&allfiles); 80 unchecked = &TAILQ_FIRST(&allfiles); 81 TAILQ_INIT(&allobjects); 82 } 83 84 void 85 addfile(const char *path, struct condexpr *optx, int flags, const char *rule) 86 { 87 struct files *fi; 88 const char *dotp, *tail; 89 size_t baselen; 90 int needc, needf; 91 char base[200]; 92 93 /* check various errors */ 94 needc = flags & FI_NEEDSCOUNT; 95 needf = flags & FI_NEEDSFLAG; 96 if (needc && needf) { 97 cfgerror("cannot mix needs-count and needs-flag"); 98 goto bad; 99 } 100 if (optx == NULL && (needc || needf)) { 101 cfgerror("nothing to %s for %s", needc ? "count" : "flag", 102 path); 103 goto bad; 104 } 105 106 /* find last part of pathname, and same without trailing suffix */ 107 tail = strrchr(path, '/'); 108 if (tail == NULL) 109 tail = path; 110 else 111 tail++; 112 dotp = strrchr(tail, '.'); 113 if (dotp == NULL || dotp[1] == 0 || 114 (baselen = dotp - tail) >= sizeof(base)) { 115 cfgerror("invalid pathname `%s'", path); 116 goto bad; 117 } 118 119 /* 120 * Commit this file to memory. We will decide later whether it 121 * will be used after all. 122 */ 123 fi = ecalloc(1, sizeof *fi); 124 if (ht_insert(pathtab, path, fi)) { 125 free(fi); 126 if ((fi = ht_lookup(pathtab, path)) == NULL) 127 panic("addfile: ht_lookup(%s)", path); 128 129 /* 130 * If it's a duplicate entry, it is must specify a make 131 * rule, and only a make rule, and must come from 132 * a different source file than the original entry. 133 * If it does otherwise, it is disallowed. This allows 134 * machine-dependent files to override the compilation 135 * options for specific files. 136 */ 137 if (rule != NULL && optx == NULL && flags == 0 && 138 yyfile != fi->fi_srcfile) { 139 fi->fi_mkrule = rule; 140 return; 141 } 142 cfgerror("duplicate file %s", path); 143 cfgxerror(fi->fi_srcfile, fi->fi_srcline, 144 "here is the original definition"); 145 goto bad; 146 } 147 memcpy(base, tail, baselen); 148 base[baselen] = 0; 149 fi->fi_srcfile = yyfile; 150 fi->fi_srcline = currentline(); 151 fi->fi_flags = flags; 152 fi->fi_path = path; 153 fi->fi_tail = tail; 154 fi->fi_base = intern(base); 155 fi->fi_prefix = SLIST_EMPTY(&prefixes) ? NULL : 156 SLIST_FIRST(&prefixes)->pf_prefix; 157 fi->fi_optx = optx; 158 fi->fi_optf = NULL; 159 fi->fi_mkrule = rule; 160 TAILQ_INSERT_TAIL(&allfiles, fi, fi_next); 161 return; 162 bad: 163 if (optx != NULL) { 164 condexpr_destroy(optx); 165 } 166 } 167 168 void 169 addobject(const char *path, struct condexpr *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 cfgerror("duplicate file %s", path); 183 cfgxerror(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 cfgxerror(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 cfgxerror(fi->fi_srcfile, fi->fi_srcline, 291 "object file collision on %s.o, from %s", 292 fi->fi_base, fi->fi_path); 293 cfgxerror(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 int error; 343 struct devm *dm, *res; 344 struct hashtab *fixdevmtab; 345 char mstr[16]; 346 347 error = 0; 348 fixdevmtab = ht_new(); 349 350 TAILQ_FOREACH(dm, &alldevms, dm_next) { 351 res = ht_lookup(fixdevmtab, intern(dm->dm_name)); 352 if (res != NULL) { 353 if (res->dm_cmajor != dm->dm_cmajor || 354 res->dm_bmajor != dm->dm_bmajor) { 355 cfgxerror(res->dm_srcfile, res->dm_srcline, 356 "device-major '%s' " 357 "block %d, char %d redefined" 358 " at %s:%d as block %d, char %d", 359 res->dm_name, 360 res->dm_bmajor, res->dm_cmajor, 361 dm->dm_srcfile, dm->dm_srcline, 362 dm->dm_bmajor, dm->dm_cmajor); 363 } else { 364 cfgxerror(res->dm_srcfile, res->dm_srcline, 365 "device-major '%s' " 366 "(block %d, char %d) duplicated" 367 " at %s:%d", 368 dm->dm_name, dm->dm_bmajor, 369 dm->dm_cmajor, 370 dm->dm_srcfile, dm->dm_srcline); 371 } 372 error = 1; 373 goto out; 374 } 375 if (ht_insert(fixdevmtab, intern(dm->dm_name), dm)) { 376 panic("fixdevsw: %s char %d block %d", 377 dm->dm_name, dm->dm_cmajor, dm->dm_bmajor); 378 } 379 380 if (dm->dm_opts != NULL && 381 !expr_eval(dm->dm_opts, fixsel, NULL)) 382 continue; 383 384 if (dm->dm_cmajor != NODEVMAJOR) { 385 if (ht_lookup(cdevmtab, intern(dm->dm_name)) != NULL) { 386 cfgxerror(dm->dm_srcfile, dm->dm_srcline, 387 "device-major of character device '%s' " 388 "is already defined", dm->dm_name); 389 error = 1; 390 goto out; 391 } 392 (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_cmajor); 393 if (ht_lookup(cdevmtab, intern(mstr)) != NULL) { 394 cfgxerror(dm->dm_srcfile, dm->dm_srcline, 395 "device-major of character major '%d' " 396 "is already defined", dm->dm_cmajor); 397 error = 1; 398 goto out; 399 } 400 if (ht_insert(cdevmtab, intern(dm->dm_name), dm) || 401 ht_insert(cdevmtab, intern(mstr), dm)) { 402 panic("fixdevsw: %s character major %d", 403 dm->dm_name, dm->dm_cmajor); 404 } 405 } 406 if (dm->dm_bmajor != NODEVMAJOR) { 407 if (ht_lookup(bdevmtab, intern(dm->dm_name)) != NULL) { 408 cfgxerror(dm->dm_srcfile, dm->dm_srcline, 409 "device-major of block device '%s' " 410 "is already defined", dm->dm_name); 411 error = 1; 412 goto out; 413 } 414 (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_bmajor); 415 if (ht_lookup(bdevmtab, intern(mstr)) != NULL) { 416 cfgxerror(dm->dm_srcfile, dm->dm_srcline, 417 "device-major of block major '%d' " 418 "is already defined", dm->dm_bmajor); 419 error = 1; 420 goto out; 421 } 422 if (ht_insert(bdevmtab, intern(dm->dm_name), dm) || 423 ht_insert(bdevmtab, intern(mstr), dm)) { 424 panic("fixdevsw: %s block major %d", 425 dm->dm_name, dm->dm_bmajor); 426 } 427 } 428 } 429 430 out: 431 ht_free(fixdevmtab); 432 return (error); 433 } 434 435 /* 436 * Called when evaluating a needs-count expression. Make sure the 437 * atom is a countable device. The expression succeeds iff there 438 * is at least one of them (note that while `xx*' will not always 439 * set xx's d_umax > 0, you cannot mix '*' and needs-count). The 440 * mkheaders() routine wants a flattened, in-order list of the 441 * atoms for `#define name value' lines, so we build that as we 442 * are called to eval each atom. 443 */ 444 static int 445 fixcount(const char *name, void *context) 446 { 447 struct nvlist ***p = context; 448 struct devbase *dev; 449 struct nvlist *nv; 450 451 dev = ht_lookup(devbasetab, name); 452 if (dev == NULL) /* cannot occur here; we checked earlier */ 453 panic("fixcount(%s)", name); 454 nv = newnv(name, NULL, NULL, dev->d_umax, NULL); 455 **p = nv; 456 *p = &nv->nv_next; 457 (void)ht_insert(needcnttab, name, nv); 458 return (dev->d_umax != 0); 459 } 460 461 /* 462 * Called from fixfiles when eval'ing a selection expression for a 463 * file that will generate a .h with flags. We will need the flat list. 464 */ 465 static int 466 fixfsel(const char *name, void *context) 467 { 468 struct nvlist ***p = context; 469 struct nvlist *nv; 470 int sel; 471 472 sel = ht_lookup(selecttab, name) != NULL; 473 nv = newnv(name, NULL, NULL, sel, NULL); 474 **p = nv; 475 *p = &nv->nv_next; 476 return (sel); 477 } 478 479 /* 480 * As for fixfsel above, but we do not need the flat list. 481 */ 482 static int 483 /*ARGSUSED*/ 484 fixsel(const char *name, void *context) 485 { 486 487 return (ht_lookup(selecttab, name) != NULL); 488 } 489 490 /* 491 * Eval an expression tree. Calls the given function on each node, 492 * passing it the given context & the name; return value is &/|/! of 493 * results of evaluating atoms. 494 * 495 * No short circuiting ever occurs. fn must return 0 or 1 (otherwise 496 * our mixing of C's bitwise & boolean here may give surprises). 497 */ 498 int 499 expr_eval(struct condexpr *expr, int (*fn)(const char *, void *), void *ctx) 500 { 501 int lhs, rhs; 502 503 switch (expr->cx_type) { 504 505 case CX_ATOM: 506 return ((*fn)(expr->cx_atom, ctx)); 507 508 case CX_NOT: 509 return (!expr_eval(expr->cx_not, fn, ctx)); 510 511 case CX_AND: 512 lhs = expr_eval(expr->cx_and.left, fn, ctx); 513 rhs = expr_eval(expr->cx_and.right, fn, ctx); 514 return (lhs & rhs); 515 516 case CX_OR: 517 lhs = expr_eval(expr->cx_or.left, fn, ctx); 518 rhs = expr_eval(expr->cx_or.right, fn, ctx); 519 return (lhs | rhs); 520 } 521 panic("invalid condexpr type %d", (int)expr->cx_type); 522 /* NOTREACHED */ 523 return (0); 524 } 525 526 #ifdef DEBUG 527 /* 528 * Print expression tree. 529 */ 530 void 531 prexpr(struct nvlist *expr) 532 { 533 static void pr0(); 534 535 printf("expr ="); 536 pr0(expr); 537 printf("\n"); 538 (void)fflush(stdout); 539 } 540 541 static void 542 pr0(struct nvlist *e) 543 { 544 545 switch (e->nv_num) { 546 case FX_ATOM: 547 printf(" %s", e->nv_name); 548 return; 549 case FX_NOT: 550 printf(" (!"); 551 break; 552 case FX_AND: 553 printf(" (&"); 554 break; 555 case FX_OR: 556 printf(" (|"); 557 break; 558 default: 559 printf(" (?%lld?", e->nv_num); 560 break; 561 } 562 if (e->nv_ptr) 563 pr0(e->nv_ptr); 564 pr0(e->nv_next); 565 printf(")"); 566 } 567 #endif 568