1 /* $NetBSD: sem.c,v 1.77 2016/09/13 16:06:59 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: @(#)sem.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: sem.c,v 1.77 2016/09/13 16:06:59 christos Exp $"); 49 50 #include <sys/param.h> 51 #include <ctype.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <util.h> 56 #include "defs.h" 57 #include "sem.h" 58 59 /* 60 * config semantics. 61 */ 62 63 #define NAMESIZE 100 /* local name buffers */ 64 65 const char *s_ifnet; /* magic attribute */ 66 const char *s_qmark; 67 const char *s_none; 68 69 static struct hashtab *cfhashtab; /* for config lookup */ 70 struct hashtab *devitab; /* etc */ 71 struct attr allattr; 72 size_t nattrs; 73 74 static struct attr errattr; 75 static struct devbase errdev; 76 static struct deva errdeva; 77 78 static int has_errobj(struct attrlist *, struct attr *); 79 static struct nvlist *addtoattr(struct nvlist *, struct devbase *); 80 static int resolve(struct nvlist **, const char *, const char *, 81 struct nvlist *, int); 82 static struct pspec *getpspec(struct attr *, struct devbase *, int); 83 static struct devi *newdevi(const char *, int, struct devbase *d); 84 static struct devi *getdevi(const char *); 85 static void remove_devi(struct devi *); 86 static const char *concat(const char *, int); 87 static char *extend(char *, const char *); 88 static int split(const char *, size_t, char *, size_t, int *); 89 static void selectbase(struct devbase *, struct deva *); 90 static const char **fixloc(const char *, struct attr *, struct loclist *); 91 static const char *makedevstr(devmajor_t, devminor_t); 92 static const char *major2name(devmajor_t); 93 static devmajor_t dev2major(struct devbase *); 94 95 extern const char *yyfile; 96 extern int vflag; 97 98 #define V_ATTRIBUTE 0 99 #define V_DEVICE 1 100 struct vtype { 101 int type; 102 struct attr *attr; 103 void *value; 104 }; 105 106 static struct nvlist * 107 makedevstack(struct devbase *d) 108 { 109 struct devi *firsti, *i; 110 struct nvlist *stack = NULL; 111 112 for (firsti = d->d_ihead; firsti != NULL; firsti = firsti->i_bsame) 113 for (i = firsti; i != NULL; i = i->i_alias) 114 stack = newnv(NULL, NULL, i, 0, stack); 115 return stack; 116 } 117 118 static void 119 devcleanup(struct nvlist *stack) 120 { 121 struct nvlist *nv; 122 for (nv = stack; nv != NULL; nv = nv->nv_next) 123 remove_devi(nv->nv_ptr); 124 nvfreel(stack); 125 } 126 127 static void * 128 addvalue(int type, struct attr *a, void *value) 129 { 130 struct vtype *vt = emalloc(sizeof(*vt)); 131 vt->type = type; 132 vt->attr = a; 133 vt->value = value; 134 return vt; 135 } 136 137 void 138 initsem(void) 139 { 140 141 attrtab = ht_new(); 142 attrdeptab = ht_new(); 143 144 allattr.a_name = "netbsd"; 145 TAILQ_INIT(&allattr.a_files); 146 (void)ht_insert(attrtab, allattr.a_name, &allattr); 147 selectattr(&allattr); 148 149 errattr.a_name = "<internal>"; 150 151 TAILQ_INIT(&allbases); 152 153 TAILQ_INIT(&alldevas); 154 155 TAILQ_INIT(&allpspecs); 156 157 cfhashtab = ht_new(); 158 TAILQ_INIT(&allcf); 159 160 TAILQ_INIT(&alldevi); 161 errdev.d_name = "<internal>"; 162 163 TAILQ_INIT(&allpseudo); 164 165 TAILQ_INIT(&alldevms); 166 167 s_ifnet = intern("ifnet"); 168 s_qmark = intern("?"); 169 s_none = intern("none"); 170 } 171 172 /* Name of include file just ended (set in scan.l) */ 173 extern const char *lastfile; 174 175 static struct attr * 176 finddep(struct attr *a, const char *name) 177 { 178 struct attrlist *al; 179 180 for (al = a->a_deps; al != NULL; al = al->al_next) { 181 struct attr *this = al->al_this; 182 if (strcmp(this->a_name, name) == 0) 183 return this; 184 } 185 return NULL; 186 } 187 188 static void 189 mergedeps(const char *dname, const char *name) 190 { 191 struct attr *a, *newa; 192 193 CFGDBG(4, "merging attr `%s' to devbase `%s'", name, dname); 194 a = refattr(dname); 195 if (finddep(a, name) == NULL) { 196 newa = refattr(name); 197 a->a_deps = attrlist_cons(a->a_deps, newa); 198 CFGDBG(3, "attr `%s' merged to attr `%s'", newa->a_name, 199 a->a_name); 200 } 201 } 202 203 static void 204 fixdev(struct devbase *dev) 205 { 206 struct attrlist *al; 207 struct attr *devattr, *a; 208 209 devattr = refattr(dev->d_name); 210 if (devattr->a_devclass) 211 panic("%s: dev %s is devclass!", __func__, devattr->a_name); 212 213 CFGDBG(4, "fixing devbase `%s'", dev->d_name); 214 for (al = dev->d_attrs; al != NULL; al = al->al_next) { 215 a = al->al_this; 216 CFGDBG(4, "fixing devbase `%s' attr `%s'", dev->d_name, a->a_name); 217 if (a->a_iattr) { 218 a->a_refs = addtoattr(a->a_refs, dev); 219 CFGDBG(3, "device `%s' has iattr `%s'", dev->d_name, 220 a->a_name); 221 } else if (a->a_devclass != NULL) { 222 if (dev->d_classattr != NULL && dev->d_classattr != a) { 223 cfgwarn("device `%s' has multiple classes " 224 "(`%s' and `%s')", 225 dev->d_name, dev->d_classattr->a_name, 226 a->a_name); 227 } 228 if (dev->d_classattr == NULL) { 229 dev->d_classattr = a; 230 CFGDBG(3, "device `%s' is devclass `%s'", dev->d_name, 231 a->a_name); 232 } 233 } else { 234 if (strcmp(dev->d_name, a->a_name) != 0) { 235 mergedeps(dev->d_name, a->a_name); 236 } 237 } 238 } 239 } 240 241 void 242 enddefs(void) 243 { 244 struct devbase *dev; 245 246 yyfile = "enddefs"; 247 248 TAILQ_FOREACH(dev, &allbases, d_next) { 249 if (!dev->d_isdef) { 250 (void)fprintf(stderr, 251 "%s: device `%s' used but not defined\n", 252 lastfile, dev->d_name); 253 errors++; 254 continue; 255 } 256 fixdev(dev); 257 } 258 if (errors) { 259 (void)fprintf(stderr, "*** Stop.\n"); 260 exit(1); 261 } 262 } 263 264 void 265 setdefmaxusers(int min, int def, int max) 266 { 267 268 if (min < 1 || min > def || def > max) 269 cfgerror("maxusers must have 1 <= min (%d) <= default (%d) " 270 "<= max (%d)", min, def, max); 271 else { 272 minmaxusers = min; 273 defmaxusers = def; 274 maxmaxusers = max; 275 } 276 } 277 278 void 279 setmaxusers(int n) 280 { 281 282 if (maxusers == n) { 283 cfgerror("duplicate maxusers parameter"); 284 return; 285 } 286 if (vflag && maxusers != 0) 287 cfgwarn("warning: maxusers already defined"); 288 maxusers = n; 289 if (n < minmaxusers) { 290 cfgerror("warning: minimum of %d maxusers assumed", 291 minmaxusers); 292 errors--; /* take it away */ 293 maxusers = minmaxusers; 294 } else if (n > maxmaxusers) { 295 cfgerror("warning: maxusers (%d) > %d", n, maxmaxusers); 296 errors--; 297 } 298 } 299 300 void 301 setident(const char *i) 302 { 303 304 if (i) 305 ident = intern(i); 306 else 307 ident = NULL; 308 } 309 310 /* 311 * Define an attribute, optionally with an interface (a locator list) 312 * and a set of attribute-dependencies. 313 * 314 * Attribute dependencies MAY NOT be interface attributes. 315 * 316 * Since an empty locator list is logically different from "no interface", 317 * all locator lists include a dummy head node, which we discard here. 318 */ 319 int 320 defattr0(const char *name, struct loclist *locs, struct attrlist *deps, 321 int devclass) 322 { 323 324 if (locs != NULL) 325 return defiattr(name, locs, deps, devclass); 326 else if (devclass) 327 return defdevclass(name, locs, deps, devclass); 328 else 329 return defattr(name, locs, deps, devclass); 330 } 331 332 int 333 defattr(const char *name, struct loclist *locs, struct attrlist *deps, 334 int devclass) 335 { 336 struct attr *a, *dep; 337 struct attrlist *al; 338 339 if (getrefattr(name, &a)) { 340 cfgerror("attribute `%s' already defined", name); 341 loclist_destroy(locs); 342 return (1); 343 } 344 if (a == NULL) 345 a = mkattr(name); 346 347 /* 348 * If this attribute depends on any others, make sure none of 349 * the dependencies are interface attributes. 350 */ 351 for (al = deps; al != NULL; al = al->al_next) { 352 dep = al->al_this; 353 if (dep->a_iattr) { 354 cfgerror("`%s' dependency `%s' is an interface " 355 "attribute", name, dep->a_name); 356 return (1); 357 } 358 (void)ht_insert2(attrdeptab, name, dep->a_name, 359 addvalue(V_ATTRIBUTE, a, dep)); 360 CFGDBG(2, "attr `%s' depends on attr `%s'", name, dep->a_name); 361 } 362 363 364 a->a_deps = deps; 365 expandattr(a, NULL); 366 CFGDBG(3, "attr `%s' defined", a->a_name); 367 368 return (0); 369 } 370 371 struct attr * 372 mkattr(const char *name) 373 { 374 struct attr *a; 375 376 a = ecalloc(1, sizeof *a); 377 if (ht_insert(attrtab, name, a)) { 378 free(a); 379 return NULL; 380 } 381 a->a_name = name; 382 TAILQ_INIT(&a->a_files); 383 CFGDBG(3, "attr `%s' allocated", name); 384 385 return a; 386 } 387 388 /* "interface attribute" initialization */ 389 int 390 defiattr(const char *name, struct loclist *locs, struct attrlist *deps, 391 int devclass) 392 { 393 struct attr *a; 394 int len; 395 struct loclist *ll; 396 397 if (devclass) 398 panic("defattr(%s): locators and devclass", name); 399 400 if (defattr(name, locs, deps, devclass) != 0) 401 return (1); 402 403 a = getattr(name); 404 a->a_iattr = 1; 405 /* unwrap */ 406 a->a_locs = locs->ll_next; 407 locs->ll_next = NULL; 408 loclist_destroy(locs); 409 len = 0; 410 for (ll = a->a_locs; ll != NULL; ll = ll->ll_next) 411 len++; 412 a->a_loclen = len; 413 if (deps) 414 CFGDBG(2, "attr `%s' iface with deps", a->a_name); 415 return (0); 416 } 417 418 /* "device class" initialization */ 419 int 420 defdevclass(const char *name, struct loclist *locs, struct attrlist *deps, 421 int devclass) 422 { 423 struct attr *a; 424 char classenum[256], *cp; 425 int errored = 0; 426 427 if (deps) 428 panic("defattr(%s): dependencies and devclass", name); 429 430 if (defattr(name, locs, deps, devclass) != 0) 431 return (1); 432 433 a = getattr(name); 434 (void)snprintf(classenum, sizeof(classenum), "DV_%s", name); 435 for (cp = classenum + 3; *cp; cp++) { 436 if (!errored && 437 (!isalnum((unsigned char)*cp) || 438 (isalpha((unsigned char)*cp) && !islower((unsigned char)*cp)))) { 439 cfgerror("device class names must be " 440 "lower-case alphanumeric characters"); 441 errored = 1; 442 } 443 *cp = (char)toupper((unsigned char)*cp); 444 } 445 a->a_devclass = intern(classenum); 446 447 return (0); 448 } 449 450 /* 451 * Return true if the given `error object' is embedded in the given 452 * pointer list. 453 */ 454 static int 455 has_errobj(struct attrlist *al, struct attr *obj) 456 { 457 458 for (; al != NULL; al = al->al_next) 459 if (al->al_this == obj) 460 return (1); 461 return (0); 462 } 463 464 /* 465 * Return true if the given attribute is embedded in the given 466 * pointer list. 467 */ 468 int 469 has_attr(struct attrlist *al, const char *attr) 470 { 471 struct attr *a; 472 473 if ((a = getattr(attr)) == NULL) 474 return (0); 475 476 for (; al != NULL; al = al->al_next) 477 if (al->al_this == a) 478 return (1); 479 return (0); 480 } 481 482 /* 483 * Add a device base to a list in an attribute (actually, to any list). 484 * Note that this does not check for duplicates, and does reverse the 485 * list order, but no one cares anyway. 486 */ 487 static struct nvlist * 488 addtoattr(struct nvlist *l, struct devbase *dev) 489 { 490 struct nvlist *n; 491 492 n = newnv(NULL, NULL, dev, 0, l); 493 return (n); 494 } 495 496 /* 497 * Define a device. This may (or may not) also define an interface 498 * attribute and/or refer to existing attributes. 499 */ 500 void 501 defdev(struct devbase *dev, struct loclist *loclist, struct attrlist *attrs, 502 int ispseudo) 503 { 504 struct loclist *ll; 505 struct attrlist *al; 506 507 if (dev == &errdev) 508 goto bad; 509 if (dev->d_isdef) { 510 cfgerror("redefinition of `%s'", dev->d_name); 511 goto bad; 512 } 513 514 dev->d_isdef = 1; 515 if (has_errobj(attrs, &errattr)) 516 goto bad; 517 518 /* 519 * Handle implicit attribute definition from locator list. Do 520 * this before scanning the `at' list so that we can have, e.g.: 521 * device foo at other, foo { slot = -1 } 522 * (where you can plug in a foo-bus extender to a foo-bus). 523 */ 524 if (loclist != NULL) { 525 ll = loclist; 526 loclist = NULL; /* defattr disposes of them for us */ 527 if (defiattr(dev->d_name, ll, NULL, 0)) 528 goto bad; 529 attrs = attrlist_cons(attrs, getattr(dev->d_name)); 530 /* This used to be stored but was never used */ 531 /* attrs->al_name = dev->d_name; */ 532 } 533 534 /* 535 * Pseudo-devices can have children. Consider them as 536 * attaching at root. 537 */ 538 if (ispseudo) { 539 for (al = attrs; al != NULL; al = al->al_next) 540 if (al->al_this->a_iattr) 541 break; 542 if (al != NULL) { 543 if (ispseudo < 2) { 544 if (version >= 20080610) 545 cfgerror("interface attribute on " 546 "non-device pseudo `%s'", dev->d_name); 547 else { 548 ispseudo = 2; 549 } 550 } 551 ht_insert(devroottab, dev->d_name, dev); 552 } 553 } 554 555 /* Committed! Set up fields. */ 556 dev->d_ispseudo = ispseudo; 557 dev->d_attrs = attrs; 558 dev->d_classattr = NULL; /* for now */ 559 CFGDBG(3, "dev `%s' defined", dev->d_name); 560 561 /* 562 * Implicit attribute definition for device. 563 */ 564 refattr(dev->d_name); 565 566 /* 567 * For each interface attribute this device refers to, add this 568 * device to its reference list. This makes, e.g., finding all 569 * "scsi"s easier. 570 * 571 * While looking through the attributes, set up the device 572 * class if any are devclass attributes (and error out if the 573 * device has two classes). 574 */ 575 for (al = attrs; al != NULL; al = al->al_next) { 576 /* 577 * Implicit attribute definition for device dependencies. 578 */ 579 refattr(al->al_this->a_name); 580 (void)ht_insert2(attrdeptab, dev->d_name, al->al_this->a_name, 581 addvalue(V_DEVICE, al->al_this, dev)); 582 CFGDBG(2, "device `%s' depends on attr `%s'", dev->d_name, 583 al->al_this->a_name); 584 } 585 return; 586 bad: 587 loclist_destroy(loclist); 588 attrlist_destroyall(attrs); 589 } 590 591 /* 592 * Look up a devbase. Also makes sure it is a reasonable name, 593 * i.e., does not end in a digit or contain special characters. 594 */ 595 struct devbase * 596 getdevbase(const char *name) 597 { 598 const u_char *p; 599 struct devbase *dev; 600 601 p = (const u_char *)name; 602 if (!isalpha(*p)) 603 goto badname; 604 while (*++p) { 605 if (!isalnum(*p) && *p != '_') 606 goto badname; 607 } 608 if (isdigit(*--p)) { 609 badname: 610 cfgerror("bad device base name `%s'", name); 611 return (&errdev); 612 } 613 dev = ht_lookup(devbasetab, name); 614 if (dev == NULL) { 615 dev = ecalloc(1, sizeof *dev); 616 dev->d_name = name; 617 dev->d_isdef = 0; 618 dev->d_major = NODEVMAJOR; 619 dev->d_attrs = NULL; 620 dev->d_ihead = NULL; 621 dev->d_ipp = &dev->d_ihead; 622 dev->d_ahead = NULL; 623 dev->d_app = &dev->d_ahead; 624 dev->d_umax = 0; 625 TAILQ_INSERT_TAIL(&allbases, dev, d_next); 626 if (ht_insert(devbasetab, name, dev)) 627 panic("getdevbase(%s)", name); 628 CFGDBG(3, "devbase defined `%s'", dev->d_name); 629 } 630 return (dev); 631 } 632 633 /* 634 * Define some of a device's allowable parent attachments. 635 * There may be a list of (plain) attributes. 636 */ 637 void 638 defdevattach(struct deva *deva, struct devbase *dev, struct nvlist *atlist, 639 struct attrlist *attrs) 640 { 641 struct nvlist *nv; 642 struct attrlist *al; 643 struct attr *a; 644 struct deva *da; 645 646 if (dev == &errdev) 647 goto bad; 648 if (deva == NULL) 649 deva = getdevattach(dev->d_name); 650 if (deva == &errdeva) 651 goto bad; 652 if (!dev->d_isdef) { 653 cfgerror("attaching undefined device `%s'", dev->d_name); 654 goto bad; 655 } 656 if (deva->d_isdef) { 657 cfgerror("redefinition of `%s'", deva->d_name); 658 goto bad; 659 } 660 if (dev->d_ispseudo) { 661 cfgerror("pseudo-devices can't attach"); 662 goto bad; 663 } 664 665 deva->d_isdef = 1; 666 if (has_errobj(attrs, &errattr)) 667 goto bad; 668 for (al = attrs; al != NULL; al = al->al_next) { 669 a = al->al_this; 670 if (a == &errattr) 671 continue; /* already complained */ 672 if (a->a_iattr || a->a_devclass != NULL) 673 cfgerror("`%s' is not a plain attribute", a->a_name); 674 } 675 676 /* Committed! Set up fields. */ 677 deva->d_attrs = attrs; 678 deva->d_atlist = atlist; 679 deva->d_devbase = dev; 680 CFGDBG(3, "deva `%s' defined", deva->d_name); 681 682 /* 683 * Implicit attribute definition for device attachment. 684 */ 685 refattr(deva->d_name); 686 687 /* 688 * Turn the `at' list into interface attributes (map each 689 * nv_name to an attribute, or to NULL for root), and add 690 * this device to those attributes, so that children can 691 * be listed at this particular device if they are supported 692 * by that attribute. 693 */ 694 for (nv = atlist; nv != NULL; nv = nv->nv_next) { 695 if (nv->nv_name == NULL) 696 nv->nv_ptr = a = NULL; /* at root */ 697 else 698 nv->nv_ptr = a = getattr(nv->nv_name); 699 if (a == &errattr) 700 continue; /* already complained */ 701 702 /* 703 * Make sure that an attachment spec doesn't 704 * already say how to attach to this attribute. 705 */ 706 for (da = dev->d_ahead; da != NULL; da = da->d_bsame) 707 if (onlist(da->d_atlist, a)) 708 cfgerror("attach at `%s' already done by `%s'", 709 a ? a->a_name : "root", da->d_name); 710 711 if (a == NULL) { 712 ht_insert(devroottab, dev->d_name, dev); 713 continue; /* at root; don't add */ 714 } 715 if (!a->a_iattr) 716 cfgerror("%s cannot be at plain attribute `%s'", 717 dev->d_name, a->a_name); 718 else 719 a->a_devs = addtoattr(a->a_devs, dev); 720 } 721 722 /* attach to parent */ 723 *dev->d_app = deva; 724 dev->d_app = &deva->d_bsame; 725 return; 726 bad: 727 nvfreel(atlist); 728 attrlist_destroyall(attrs); 729 } 730 731 /* 732 * Look up a device attachment. Also makes sure it is a reasonable 733 * name, i.e., does not contain digits or special characters. 734 */ 735 struct deva * 736 getdevattach(const char *name) 737 { 738 const u_char *p; 739 struct deva *deva; 740 741 p = (const u_char *)name; 742 if (!isalpha(*p)) 743 goto badname; 744 while (*++p) { 745 if (!isalnum(*p) && *p != '_') 746 goto badname; 747 } 748 if (isdigit(*--p)) { 749 badname: 750 cfgerror("bad device attachment name `%s'", name); 751 return (&errdeva); 752 } 753 deva = ht_lookup(devatab, name); 754 if (deva == NULL) { 755 deva = ecalloc(1, sizeof *deva); 756 deva->d_name = name; 757 deva->d_bsame = NULL; 758 deva->d_isdef = 0; 759 deva->d_devbase = NULL; 760 deva->d_atlist = NULL; 761 deva->d_attrs = NULL; 762 deva->d_ihead = NULL; 763 deva->d_ipp = &deva->d_ihead; 764 TAILQ_INSERT_TAIL(&alldevas, deva, d_next); 765 if (ht_insert(devatab, name, deva)) 766 panic("getdeva(%s)", name); 767 } 768 return (deva); 769 } 770 771 /* 772 * Look up an attribute. 773 */ 774 struct attr * 775 getattr(const char *name) 776 { 777 struct attr *a; 778 779 if ((a = ht_lookup(attrtab, name)) == NULL) { 780 cfgerror("undefined attribute `%s'", name); 781 a = &errattr; 782 } 783 return (a); 784 } 785 786 /* 787 * Implicit attribute definition. 788 */ 789 struct attr * 790 refattr(const char *name) 791 { 792 struct attr *a; 793 794 if ((a = ht_lookup(attrtab, name)) == NULL) 795 a = mkattr(name); 796 return a; 797 } 798 799 int 800 getrefattr(const char *name, struct attr **ra) 801 { 802 struct attr *a; 803 804 a = ht_lookup(attrtab, name); 805 if (a == NULL) { 806 *ra = NULL; 807 return (0); 808 } 809 /* 810 * Check if the existing attr is only referenced, not really defined. 811 */ 812 if (a->a_deps == NULL && 813 a->a_iattr == 0 && 814 a->a_devclass == 0) { 815 *ra = a; 816 return (0); 817 } 818 return (1); 819 } 820 821 /* 822 * Recursively expand an attribute and its dependencies, checking for 823 * cycles, and invoking a callback for each attribute found. 824 */ 825 void 826 expandattr(struct attr *a, void (*callback)(struct attr *)) 827 { 828 struct attrlist *al; 829 struct attr *dep; 830 831 if (a->a_expanding) { 832 cfgerror("circular dependency on attribute `%s'", a->a_name); 833 return; 834 } 835 836 a->a_expanding = 1; 837 838 /* First expand all of this attribute's dependencies. */ 839 for (al = a->a_deps; al != NULL; al = al->al_next) { 840 dep = al->al_this; 841 expandattr(dep, callback); 842 } 843 844 /* ...and now invoke the callback for ourself. */ 845 if (callback != NULL) 846 (*callback)(a); 847 848 a->a_expanding = 0; 849 } 850 851 /* 852 * Set the major device number for a device, so that it can be used 853 * as a root/dumps "on" device in a configuration. 854 */ 855 void 856 setmajor(struct devbase *d, devmajor_t n) 857 { 858 859 if (d != &errdev && d->d_major != NODEVMAJOR) 860 cfgerror("device `%s' is already major %d", 861 d->d_name, d->d_major); 862 else 863 d->d_major = n; 864 } 865 866 const char * 867 major2name(devmajor_t maj) 868 { 869 struct devbase *dev; 870 struct devm *dm; 871 872 if (!do_devsw) { 873 TAILQ_FOREACH(dev, &allbases, d_next) { 874 if (dev->d_major == maj) 875 return (dev->d_name); 876 } 877 } else { 878 TAILQ_FOREACH(dm, &alldevms, dm_next) { 879 if (dm->dm_bmajor == maj) 880 return (dm->dm_name); 881 } 882 } 883 return (NULL); 884 } 885 886 devmajor_t 887 dev2major(struct devbase *dev) 888 { 889 struct devm *dm; 890 891 if (!do_devsw) 892 return (dev->d_major); 893 894 TAILQ_FOREACH(dm, &alldevms, dm_next) { 895 if (strcmp(dm->dm_name, dev->d_name) == 0) 896 return (dm->dm_bmajor); 897 } 898 return (NODEVMAJOR); 899 } 900 901 /* 902 * Make a string description of the device at maj/min. 903 */ 904 static const char * 905 makedevstr(devmajor_t maj, devminor_t min) 906 { 907 const char *devicename; 908 char buf[32]; 909 910 devicename = major2name(maj); 911 if (devicename == NULL) 912 (void)snprintf(buf, sizeof(buf), "<%d/%d>", maj, min); 913 else 914 (void)snprintf(buf, sizeof(buf), "%s%d%c", devicename, 915 min / maxpartitions, (min % maxpartitions) + 'a'); 916 917 return (intern(buf)); 918 } 919 920 /* 921 * Map things like "ra0b" => makedev(major("ra"), 0*maxpartitions + 'b'-'a'). 922 * Handle the case where the device number is given but there is no 923 * corresponding name, and map NULL to the default. 924 */ 925 static int 926 resolve(struct nvlist **nvp, const char *name, const char *what, 927 struct nvlist *dflt, int part) 928 { 929 struct nvlist *nv; 930 struct devbase *dev; 931 const char *cp; 932 devmajor_t maj; 933 devminor_t min; 934 size_t i, l; 935 int unit; 936 char buf[NAMESIZE]; 937 938 if ((part -= 'a') >= maxpartitions || part < 0) 939 panic("resolve"); 940 if ((nv = *nvp) == NULL) { 941 dev_t d = NODEV; 942 /* 943 * Apply default. Easiest to do this by number. 944 * Make sure to retain NODEVness, if this is dflt's disposition. 945 */ 946 if ((dev_t)dflt->nv_num != NODEV) { 947 maj = major(dflt->nv_num); 948 min = ((minor(dflt->nv_num) / maxpartitions) * 949 maxpartitions) + part; 950 d = makedev(maj, min); 951 cp = makedevstr(maj, min); 952 } else 953 cp = NULL; 954 *nvp = nv = newnv(NULL, cp, NULL, (long long)d, NULL); 955 } 956 if ((dev_t)nv->nv_num != NODEV) { 957 /* 958 * By the numbers. Find the appropriate major number 959 * to make a name. 960 */ 961 maj = major(nv->nv_num); 962 min = minor(nv->nv_num); 963 nv->nv_str = makedevstr(maj, min); 964 return (0); 965 } 966 967 if (nv->nv_str == NULL || nv->nv_str == s_qmark) 968 /* 969 * Wildcarded or unspecified; leave it as NODEV. 970 */ 971 return (0); 972 973 if (nv->nv_ptr != NULL && strcmp(nv->nv_ptr, "spec") == 0) 974 /* 975 * spec string, interpreted by kernel 976 */ 977 return (0); 978 979 /* 980 * The normal case: things like "ra2b". Check for partition 981 * suffix, remove it if there, and split into name ("ra") and 982 * unit (2). 983 */ 984 l = i = strlen(nv->nv_str); 985 cp = &nv->nv_str[l]; 986 if (l > 1 && *--cp >= 'a' && *cp < 'a' + maxpartitions && 987 isdigit((unsigned char)cp[-1])) { 988 l--; 989 part = *cp - 'a'; 990 } 991 cp = nv->nv_str; 992 if (split(cp, l, buf, sizeof buf, &unit)) { 993 cfgerror("%s: invalid %s device name `%s'", name, what, cp); 994 return (1); 995 } 996 dev = ht_lookup(devbasetab, intern(buf)); 997 if (dev == NULL) { 998 cfgerror("%s: device `%s' does not exist", name, buf); 999 return (1); 1000 } 1001 1002 /* 1003 * Check for the magic network interface attribute, and 1004 * don't bother making a device number. 1005 */ 1006 if (has_attr(dev->d_attrs, s_ifnet)) { 1007 nv->nv_num = (long long)NODEV; 1008 nv->nv_ifunit = unit; /* XXX XXX XXX */ 1009 } else { 1010 maj = dev2major(dev); 1011 if (maj == NODEVMAJOR) { 1012 cfgerror("%s: can't make %s device from `%s'", 1013 name, what, nv->nv_str); 1014 return (1); 1015 } 1016 nv->nv_num = (long long)makedev(maj, unit * maxpartitions + part); 1017 } 1018 1019 nv->nv_name = dev->d_name; 1020 return (0); 1021 } 1022 1023 /* 1024 * Add a completed configuration to the list. 1025 */ 1026 void 1027 addconf(struct config *cf0) 1028 { 1029 struct config *cf; 1030 const char *name; 1031 1032 name = cf0->cf_name; 1033 cf = ecalloc(1, sizeof *cf); 1034 if (ht_insert(cfhashtab, name, cf)) { 1035 cfgerror("configuration `%s' already defined", name); 1036 free(cf); 1037 goto bad; 1038 } 1039 *cf = *cf0; 1040 1041 /* 1042 * Resolve the root device. 1043 */ 1044 if (cf->cf_root == NULL) { 1045 cfgerror("%s: no root device specified", name); 1046 goto bad; 1047 } 1048 if (cf->cf_root && cf->cf_root->nv_str != s_qmark) { 1049 struct nvlist *nv; 1050 nv = cf->cf_root; 1051 if (resolve(&cf->cf_root, name, "root", nv, 'a')) 1052 goto bad; 1053 } 1054 1055 /* 1056 * Resolve the dump device. 1057 */ 1058 if (cf->cf_dump == NULL || cf->cf_dump->nv_str == s_qmark) { 1059 /* 1060 * Wildcarded dump device is equivalent to unspecified. 1061 */ 1062 cf->cf_dump = NULL; 1063 } else if (cf->cf_dump->nv_str == s_none) { 1064 /* 1065 * Operator has requested that no dump device should be 1066 * configured; do nothing. 1067 */ 1068 } else { 1069 if (resolve(&cf->cf_dump, name, "dumps", cf->cf_dump, 'b')) 1070 goto bad; 1071 } 1072 1073 /* Wildcarded fstype is `unspecified'. */ 1074 if (cf->cf_fstype == s_qmark) 1075 cf->cf_fstype = NULL; 1076 1077 TAILQ_INSERT_TAIL(&allcf, cf, cf_next); 1078 return; 1079 bad: 1080 nvfreel(cf0->cf_root); 1081 nvfreel(cf0->cf_dump); 1082 } 1083 1084 void 1085 setconf(struct nvlist **npp, const char *what, struct nvlist *v) 1086 { 1087 1088 if (*npp != NULL) { 1089 cfgerror("duplicate %s specification", what); 1090 nvfreel(v); 1091 } else 1092 *npp = v; 1093 } 1094 1095 void 1096 delconf(const char *name, int nowarn) 1097 { 1098 struct config *cf; 1099 1100 CFGDBG(5, "deselecting config `%s'", name); 1101 if (ht_lookup(cfhashtab, name) == NULL) { 1102 if (!nowarn) 1103 cfgerror("configuration `%s' undefined", name); 1104 return; 1105 } 1106 (void)ht_remove(cfhashtab, name); 1107 1108 TAILQ_FOREACH(cf, &allcf, cf_next) 1109 if (!strcmp(cf->cf_name, name)) 1110 break; 1111 if (cf == NULL) 1112 panic("lost configuration `%s'", name); 1113 1114 TAILQ_REMOVE(&allcf, cf, cf_next); 1115 } 1116 1117 void 1118 setfstype(const char **fstp, const char *v) 1119 { 1120 1121 if (*fstp != NULL) { 1122 cfgerror("multiple fstype specifications"); 1123 return; 1124 } 1125 1126 if (v != s_qmark && OPT_FSOPT(v)) { 1127 cfgerror("\"%s\" is not a configured file system", v); 1128 return; 1129 } 1130 1131 *fstp = v; 1132 } 1133 1134 static struct devi * 1135 newdevi(const char *name, int unit, struct devbase *d) 1136 { 1137 struct devi *i; 1138 1139 i = ecalloc(1, sizeof *i); 1140 i->i_name = name; 1141 i->i_unit = unit; 1142 i->i_base = d; 1143 i->i_bsame = NULL; 1144 i->i_asame = NULL; 1145 i->i_alias = NULL; 1146 i->i_at = NULL; 1147 i->i_pspec = NULL; 1148 i->i_atdeva = NULL; 1149 i->i_locs = NULL; 1150 i->i_cfflags = 0; 1151 i->i_lineno = currentline(); 1152 i->i_srcfile = yyfile; 1153 i->i_active = DEVI_ORPHAN; /* Proper analysis comes later */ 1154 i->i_level = devilevel; 1155 i->i_pseudoroot = 0; 1156 if (unit >= d->d_umax) 1157 d->d_umax = unit + 1; 1158 return (i); 1159 } 1160 1161 /* 1162 * Add the named device as attaching to the named attribute (or perhaps 1163 * another device instead) plus unit number. 1164 */ 1165 void 1166 adddev(const char *name, const char *at, struct loclist *loclist, int flags) 1167 { 1168 struct devi *i; /* the new instance */ 1169 struct pspec *p; /* and its pspec */ 1170 struct attr *attr; /* attribute that allows attach */ 1171 struct devbase *ib; /* i->i_base */ 1172 struct devbase *ab; /* not NULL => at another dev */ 1173 struct attrlist *al; 1174 struct deva *iba; /* devbase attachment used */ 1175 const char *cp; 1176 int atunit; 1177 char atbuf[NAMESIZE]; 1178 int hit; 1179 1180 ab = NULL; 1181 iba = NULL; 1182 if (at == NULL) { 1183 /* "at root" */ 1184 p = NULL; 1185 if ((i = getdevi(name)) == NULL) 1186 goto bad; 1187 /* 1188 * Must warn about i_unit > 0 later, after taking care of 1189 * the STAR cases (we could do non-star's here but why 1190 * bother?). Make sure this device can be at root. 1191 */ 1192 ib = i->i_base; 1193 hit = 0; 1194 for (iba = ib->d_ahead; iba != NULL; iba = iba->d_bsame) 1195 if (onlist(iba->d_atlist, NULL)) { 1196 hit = 1; 1197 break; 1198 } 1199 if (!hit) { 1200 cfgerror("`%s' cannot attach to the root", ib->d_name); 1201 i->i_active = DEVI_BROKEN; 1202 goto bad; 1203 } 1204 attr = &errattr; /* a convenient "empty" attr */ 1205 } else { 1206 if (split(at, strlen(at), atbuf, sizeof atbuf, &atunit)) { 1207 cfgerror("invalid attachment name `%s'", at); 1208 /* (void)getdevi(name); -- ??? */ 1209 goto bad; 1210 } 1211 if ((i = getdevi(name)) == NULL) 1212 goto bad; 1213 ib = i->i_base; 1214 1215 /* 1216 * Devices can attach to two types of things: Attributes, 1217 * and other devices (which have the appropriate attributes 1218 * to allow attachment). 1219 * 1220 * (1) If we're attached to an attribute, then we don't need 1221 * look at the parent base device to see what attributes 1222 * it has, and make sure that we can attach to them. 1223 * 1224 * (2) If we're attached to a real device (i.e. named in 1225 * the config file), we want to remember that so that 1226 * at cross-check time, if the device we're attached to 1227 * is missing but other devices which also provide the 1228 * attribute are present, we don't get a false "OK." 1229 * 1230 * (3) If the thing we're attached to is an attribute 1231 * but is actually named in the config file, we still 1232 * have to remember its devbase. 1233 */ 1234 cp = intern(atbuf); 1235 1236 /* Figure out parent's devbase, to satisfy case (3). */ 1237 ab = ht_lookup(devbasetab, cp); 1238 1239 /* Find out if it's an attribute. */ 1240 attr = ht_lookup(attrtab, cp); 1241 1242 /* Make sure we're _really_ attached to the attr. Case (1). */ 1243 if (attr != NULL && onlist(attr->a_devs, ib)) 1244 goto findattachment; 1245 1246 /* 1247 * Else a real device, and not just an attribute. Case (2). 1248 * 1249 * Have to work a bit harder to see whether we have 1250 * something like "tg0 at esp0" (where esp is merely 1251 * not an attribute) or "tg0 at nonesuch0" (where 1252 * nonesuch is not even a device). 1253 */ 1254 if (ab == NULL) { 1255 cfgerror("%s at %s: `%s' unknown", 1256 name, at, atbuf); 1257 i->i_active = DEVI_BROKEN; 1258 goto bad; 1259 } 1260 1261 /* 1262 * See if the named parent carries an attribute 1263 * that allows it to supervise device ib. 1264 */ 1265 for (al = ab->d_attrs; al != NULL; al = al->al_next) { 1266 attr = al->al_this; 1267 if (onlist(attr->a_devs, ib)) 1268 goto findattachment; 1269 } 1270 cfgerror("`%s' cannot attach to `%s'", ib->d_name, atbuf); 1271 i->i_active = DEVI_BROKEN; 1272 goto bad; 1273 1274 findattachment: 1275 /* 1276 * Find the parent spec. If a matching one has not yet been 1277 * created, create one. 1278 */ 1279 p = getpspec(attr, ab, atunit); 1280 p->p_devs = newnv(NULL, NULL, i, 0, p->p_devs); 1281 1282 /* find out which attachment it uses */ 1283 hit = 0; 1284 for (iba = ib->d_ahead; iba != NULL; iba = iba->d_bsame) 1285 if (onlist(iba->d_atlist, attr)) { 1286 hit = 1; 1287 break; 1288 } 1289 if (!hit) 1290 panic("adddev: can't figure out attachment"); 1291 } 1292 if ((i->i_locs = fixloc(name, attr, loclist)) == NULL) { 1293 i->i_active = DEVI_BROKEN; 1294 goto bad; 1295 } 1296 i->i_at = at; 1297 i->i_pspec = p; 1298 i->i_atdeva = iba; 1299 i->i_cfflags = flags; 1300 CFGDBG(3, "devi `%s' added", i->i_name); 1301 1302 *iba->d_ipp = i; 1303 iba->d_ipp = &i->i_asame; 1304 1305 /* all done, fall into ... */ 1306 bad: 1307 loclist_destroy(loclist); 1308 return; 1309 } 1310 1311 void 1312 deldevi(const char *name, const char *at, int nowarn) 1313 { 1314 struct devi *firsti, *i; 1315 struct devbase *d; 1316 int unit; 1317 char base[NAMESIZE]; 1318 1319 CFGDBG(5, "deselecting devi `%s'", name); 1320 if (split(name, strlen(name), base, sizeof base, &unit)) { 1321 if (!nowarn) { 1322 cfgerror("invalid device name `%s'", name); 1323 return; 1324 } 1325 } 1326 d = ht_lookup(devbasetab, intern(base)); 1327 if (d == NULL) { 1328 if (!nowarn) 1329 cfgerror("%s: unknown device `%s'", name, base); 1330 return; 1331 } 1332 if (d->d_ispseudo) { 1333 cfgerror("%s: %s is a pseudo-device", name, base); 1334 return; 1335 } 1336 if ((firsti = ht_lookup(devitab, name)) == NULL) { 1337 cfgerror("`%s' not defined", name); 1338 return; 1339 } 1340 if (at == NULL && firsti->i_at == NULL) { 1341 /* 'at root' */ 1342 remove_devi(firsti); 1343 return; 1344 } else if (at != NULL) 1345 for (i = firsti; i != NULL; i = i->i_alias) 1346 if (i->i_active != DEVI_BROKEN && 1347 strcmp(at, i->i_at) == 0) { 1348 remove_devi(i); 1349 return; 1350 } 1351 cfgerror("`%s' at `%s' not found", name, at ? at : "root"); 1352 } 1353 1354 static void 1355 remove_devi(struct devi *i) 1356 { 1357 struct devbase *d = i->i_base; 1358 struct devi *f, *j, **ppi; 1359 struct deva *iba; 1360 1361 CFGDBG(5, "removing devi `%s'", i->i_name); 1362 f = ht_lookup(devitab, i->i_name); 1363 if (f == NULL) 1364 panic("remove_devi(): instance %s disappeared from devitab", 1365 i->i_name); 1366 1367 if (i->i_active == DEVI_BROKEN) { 1368 cfgerror("not removing broken instance `%s'", i->i_name); 1369 return; 1370 } 1371 1372 /* 1373 * We have the device instance, i. 1374 * We have to: 1375 * - delete the alias 1376 * 1377 * If the devi was an alias of an already listed devi, all is 1378 * good we don't have to do more. 1379 * If it was the first alias, we have to replace i's entry in 1380 * d's list by its first alias. 1381 * If it was the only entry, we must remove i's entry from d's 1382 * list. 1383 */ 1384 if (i != f) { 1385 for (j = f; j->i_alias != i; j = j->i_alias) 1386 continue; 1387 j->i_alias = i->i_alias; 1388 } else { 1389 if (i->i_alias == NULL) { 1390 /* No alias, must unlink the entry from devitab */ 1391 ht_remove(devitab, i->i_name); 1392 j = i->i_bsame; 1393 } else { 1394 /* Or have the first alias replace i in d's list */ 1395 i->i_alias->i_bsame = i->i_bsame; 1396 j = i->i_alias; 1397 if (i == f) 1398 ht_replace(devitab, i->i_name, i->i_alias); 1399 } 1400 1401 /* 1402 * - remove/replace the instance from the devbase's list 1403 * 1404 * A double-linked list would make this much easier. Oh, well, 1405 * what is done is done. 1406 */ 1407 for (ppi = &d->d_ihead; 1408 *ppi != NULL && *ppi != i && (*ppi)->i_bsame != i; 1409 ppi = &(*ppi)->i_bsame) 1410 continue; 1411 if (*ppi == NULL) 1412 panic("deldev: dev (%s) doesn't list the devi" 1413 " (%s at %s)", d->d_name, i->i_name, i->i_at); 1414 f = *ppi; 1415 if (f == i) 1416 /* That implies d->d_ihead == i */ 1417 *ppi = j; 1418 else 1419 (*ppi)->i_bsame = j; 1420 if (d->d_ipp == &i->i_bsame) { 1421 if (i->i_alias == NULL) { 1422 if (f == i) 1423 d->d_ipp = &d->d_ihead; 1424 else 1425 d->d_ipp = &f->i_bsame; 1426 } else 1427 d->d_ipp = &i->i_alias->i_bsame; 1428 } 1429 } 1430 /* 1431 * - delete the attachment instance 1432 */ 1433 iba = i->i_atdeva; 1434 for (ppi = &iba->d_ihead; 1435 *ppi != NULL && *ppi != i && (*ppi)->i_asame != i; 1436 ppi = &(*ppi)->i_asame) 1437 continue; 1438 if (*ppi == NULL) 1439 panic("deldev: deva (%s) doesn't list the devi (%s)", 1440 iba->d_name, i->i_name); 1441 f = *ppi; 1442 if (f == i) 1443 /* That implies iba->d_ihead == i */ 1444 *ppi = i->i_asame; 1445 else 1446 (*ppi)->i_asame = i->i_asame; 1447 if (iba->d_ipp == &i->i_asame) { 1448 if (f == i) 1449 iba->d_ipp = &iba->d_ihead; 1450 else 1451 iba->d_ipp = &f->i_asame; 1452 } 1453 /* 1454 * - delete the pspec 1455 */ 1456 if (i->i_pspec) { 1457 struct pspec *p = i->i_pspec; 1458 struct nvlist *nv, *onv; 1459 1460 /* Double-linked nvlist anyone? */ 1461 for (nv = p->p_devs; nv->nv_next != NULL; nv = nv->nv_next) { 1462 if (nv->nv_next && nv->nv_next->nv_ptr == i) { 1463 onv = nv->nv_next; 1464 nv->nv_next = onv->nv_next; 1465 nvfree(onv); 1466 break; 1467 } 1468 if (nv->nv_ptr == i) { 1469 /* nv is p->p_devs in that case */ 1470 p->p_devs = nv->nv_next; 1471 nvfree(nv); 1472 break; 1473 } 1474 } 1475 if (p->p_devs == NULL) 1476 TAILQ_REMOVE(&allpspecs, p, p_list); 1477 } 1478 /* 1479 * - delete the alldevi entry 1480 */ 1481 TAILQ_REMOVE(&alldevi, i, i_next); 1482 ndevi--; 1483 /* 1484 * Put it in deaddevitab 1485 * 1486 * Each time a devi is removed, devilevel is increased so that later on 1487 * it is possible to tell if an instance was added before or after the 1488 * removal of its parent. 1489 * 1490 * For active instances, i_level contains the number of devi removed so 1491 * far, and for dead devis, it contains its index. 1492 */ 1493 i->i_level = devilevel++; 1494 i->i_alias = NULL; 1495 f = ht_lookup(deaddevitab, i->i_name); 1496 if (f == NULL) { 1497 if (ht_insert(deaddevitab, i->i_name, i)) 1498 panic("remove_devi(%s) - can't add to deaddevitab", 1499 i->i_name); 1500 } else { 1501 for (j = f; j->i_alias != NULL; j = j->i_alias) 1502 continue; 1503 j->i_alias = i; 1504 } 1505 /* 1506 * - reconstruct d->d_umax 1507 */ 1508 d->d_umax = 0; 1509 for (i = d->d_ihead; i != NULL; i = i->i_bsame) 1510 if (i->i_unit >= d->d_umax) 1511 d->d_umax = i->i_unit + 1; 1512 } 1513 1514 void 1515 deldeva(const char *at, int nowarn) 1516 { 1517 int unit; 1518 const char *cp; 1519 struct devbase *d, *ad; 1520 struct devi *i, *j; 1521 struct attr *a; 1522 struct pspec *p; 1523 struct nvlist *nv, *stack = NULL; 1524 1525 if (at == NULL) { 1526 TAILQ_FOREACH(i, &alldevi, i_next) 1527 if (i->i_at == NULL) 1528 stack = newnv(NULL, NULL, i, 0, stack); 1529 } else { 1530 size_t l; 1531 1532 CFGDBG(5, "deselecting deva `%s'", at); 1533 if (at[0] == '\0') 1534 goto out; 1535 1536 l = strlen(at) - 1; 1537 if (at[l] == '?' || isdigit((unsigned char)at[l])) { 1538 char base[NAMESIZE]; 1539 1540 if (split(at, l+1, base, sizeof base, &unit)) { 1541 out: 1542 cfgerror("invalid attachment name `%s'", at); 1543 return; 1544 } 1545 cp = intern(base); 1546 } else { 1547 cp = intern(at); 1548 unit = STAR; 1549 } 1550 1551 ad = ht_lookup(devbasetab, cp); 1552 a = ht_lookup(attrtab, cp); 1553 if (a == NULL) { 1554 cfgerror("unknown attachment attribute or device `%s'", 1555 cp); 1556 return; 1557 } 1558 if (!a->a_iattr) { 1559 cfgerror("plain attribute `%s' cannot have children", 1560 a->a_name); 1561 return; 1562 } 1563 1564 /* 1565 * remove_devi() makes changes to the devbase's list and the 1566 * alias list, * so the actual deletion of the instances must 1567 * be delayed. 1568 */ 1569 for (nv = a->a_devs; nv != NULL; nv = nv->nv_next) { 1570 d = nv->nv_ptr; 1571 for (i = d->d_ihead; i != NULL; i = i->i_bsame) 1572 for (j = i; j != NULL; j = j->i_alias) { 1573 /* Ignore devices at root */ 1574 if (j->i_at == NULL) 1575 continue; 1576 p = j->i_pspec; 1577 /* 1578 * There are three cases: 1579 * 1580 * 1. unit is not STAR. Consider 'at' 1581 * to be explicit, even if it 1582 * references an interface 1583 * attribute. 1584 * 1585 * 2. unit is STAR and 'at' references 1586 * a real device. Look for pspec 1587 * that have a matching p_atdev 1588 * field. 1589 * 1590 * 3. unit is STAR and 'at' references 1591 * an interface attribute. Look 1592 * for pspec that have a matching 1593 * p_iattr field. 1594 */ 1595 if ((unit != STAR && /* Case */ 1596 !strcmp(j->i_at, at)) || /* 1 */ 1597 (unit == STAR && 1598 ((ad != NULL && /* Case */ 1599 p->p_atdev == ad) || /* 2 */ 1600 (ad == NULL && /* Case */ 1601 p->p_iattr == a)))) /* 3 */ 1602 stack = newnv(NULL, NULL, j, 0, 1603 stack); 1604 } 1605 } 1606 } 1607 1608 devcleanup(stack); 1609 } 1610 1611 void 1612 deldev(const char *name, int nowarn) 1613 { 1614 size_t l; 1615 struct devi *firsti, *i; 1616 struct nvlist *stack = NULL; 1617 1618 CFGDBG(5, "deselecting dev `%s'", name); 1619 if (name[0] == '\0') 1620 goto out; 1621 1622 l = strlen(name) - 1; 1623 if (name[l] == '*' || isdigit((unsigned char)name[l])) { 1624 /* `no mydev0' or `no mydev*' */ 1625 firsti = ht_lookup(devitab, name); 1626 if (firsti == NULL) { 1627 out: 1628 if (!nowarn) 1629 cfgerror("unknown instance %s", name); 1630 return; 1631 } 1632 for (i = firsti; i != NULL; i = i->i_alias) 1633 stack = newnv(NULL, NULL, i, 0, stack); 1634 } else { 1635 struct devbase *d = ht_lookup(devbasetab, name); 1636 1637 if (d == NULL) { 1638 cfgerror("unknown device %s", name); 1639 return; 1640 } 1641 if (d->d_ispseudo) { 1642 cfgerror("%s is a pseudo-device; " 1643 "use \"no pseudo-device %s\" instead", name, 1644 name); 1645 return; 1646 } 1647 stack = makedevstack(d); 1648 } 1649 1650 devcleanup(stack); 1651 } 1652 1653 /* 1654 * Insert given device "name" into devroottab. In case "name" 1655 * designates a pure interface attribute, create a fake device 1656 * instance for the attribute and insert that into the roottab 1657 * (this scheme avoids mucking around with the orphanage analysis). 1658 */ 1659 void 1660 addpseudoroot(const char *name) 1661 { 1662 char buf[NAMESIZE]; 1663 int unit; 1664 struct attr *attr; 1665 struct devi *i; 1666 struct deva *iba; 1667 struct devbase *ib; 1668 1669 if (split(name, strlen(name), buf, sizeof(buf), &unit)) { 1670 cfgerror("invalid pseudo-root name `%s'", name); 1671 return; 1672 } 1673 1674 /* 1675 * Prefer device because devices with locators define an 1676 * implicit interface attribute. However, if a device is 1677 * not available, try to attach to the interface attribute. 1678 * This makes sure adddev() doesn't get confused when we 1679 * are really attaching to a device (alternatively we maybe 1680 * could specify a non-NULL atlist to defdevattach() below). 1681 */ 1682 ib = ht_lookup(devbasetab, intern(buf)); 1683 if (ib == NULL) { 1684 struct devbase *fakedev; 1685 char fakename[NAMESIZE]; 1686 1687 attr = ht_lookup(attrtab, intern(buf)); 1688 if (!(attr && attr->a_iattr)) { 1689 cfgerror("pseudo-root `%s' not available", name); 1690 return; 1691 } 1692 1693 /* 1694 * here we cheat a bit: create a fake devbase with the 1695 * interface attribute and instantiate it. quick, cheap, 1696 * dirty & bad for you, much like the stuff in the fridge. 1697 * and, it works, since the pseudoroot device is not included 1698 * in ioconf, just used by config to make sure we start from 1699 * the right place. 1700 */ 1701 snprintf(fakename, sizeof(fakename), "%s_devattrs", buf); 1702 fakedev = getdevbase(intern(fakename)); 1703 fakedev->d_isdef = 1; 1704 fakedev->d_ispseudo = 0; 1705 fakedev->d_attrs = attrlist_cons(NULL, attr); 1706 defdevattach(NULL, fakedev, NULL, NULL); 1707 1708 if (unit == STAR) 1709 snprintf(buf, sizeof(buf), "%s*", fakename); 1710 else 1711 snprintf(buf, sizeof(buf), "%s%d", fakename, unit); 1712 name = buf; 1713 } 1714 1715 /* ok, everything should be set up, so instantiate a fake device */ 1716 i = getdevi(name); 1717 if (i == NULL) 1718 panic("device `%s' expected to be present", name); 1719 ib = i->i_base; 1720 iba = ib->d_ahead; 1721 1722 i->i_atdeva = iba; 1723 i->i_cfflags = 0; 1724 i->i_locs = fixloc(name, &errattr, NULL); 1725 i->i_pseudoroot = 1; 1726 i->i_active = DEVI_ORPHAN; /* set active by kill_orphans() */ 1727 1728 *iba->d_ipp = i; 1729 iba->d_ipp = &i->i_asame; 1730 1731 ht_insert(devroottab, ib->d_name, ib); 1732 } 1733 1734 static void 1735 deldevbase(struct devbase *d) 1736 { 1737 struct devi *i; 1738 const char *name = d->d_name; 1739 1740 if (!d->d_ispseudo) { 1741 devcleanup(makedevstack(d)); 1742 return; 1743 } 1744 1745 if ((i = ht_lookup(devitab, name)) == NULL) 1746 return; 1747 1748 d->d_umax = 0; /* clear neads-count entries */ 1749 d->d_ihead = NULL; /* make sure it won't be considered active */ 1750 TAILQ_REMOVE(&allpseudo, i, i_next); 1751 if (ht_remove(devitab, name)) 1752 panic("%s(%s) - can't remove from devitab", __func__, name); 1753 if (ht_insert(deaddevitab, name, i)) 1754 panic("%s(%s) - can't add to deaddevitab", __func__, name); 1755 } 1756 1757 void 1758 addpseudo(const char *name, int number) 1759 { 1760 struct devbase *d; 1761 struct devi *i; 1762 1763 d = ht_lookup(devbasetab, name); 1764 if (d == NULL) { 1765 cfgerror("undefined pseudo-device %s", name); 1766 return; 1767 } 1768 if (!d->d_ispseudo) { 1769 cfgerror("%s is a real device, not a pseudo-device", name); 1770 return; 1771 } 1772 if (ht_lookup(devitab, name) != NULL) { 1773 cfgerror("`%s' already defined", name); 1774 return; 1775 } 1776 i = newdevi(name, number - 1, d); /* foo 16 => "foo0..foo15" */ 1777 if (ht_insert(devitab, name, i)) 1778 panic("addpseudo(%s)", name); 1779 /* Useful to retrieve the instance from the devbase */ 1780 d->d_ihead = i; 1781 i->i_active = DEVI_ACTIVE; 1782 TAILQ_INSERT_TAIL(&allpseudo, i, i_next); 1783 } 1784 1785 void 1786 delpseudo(const char *name, int nowarn) 1787 { 1788 struct devbase *d; 1789 1790 CFGDBG(5, "deselecting pseudo `%s'", name); 1791 d = ht_lookup(devbasetab, name); 1792 if (d == NULL) { 1793 if (!nowarn) 1794 cfgerror("undefined pseudo-device %s", name); 1795 return; 1796 } 1797 if (!d->d_ispseudo) { 1798 cfgerror("%s is a real device, not a pseudo-device", name); 1799 return; 1800 } 1801 deldevbase(d); 1802 } 1803 1804 void 1805 adddevm(const char *name, devmajor_t cmajor, devmajor_t bmajor, 1806 struct condexpr *cond, struct nvlist *nv_nodes) 1807 { 1808 struct devm *dm; 1809 1810 if (cmajor != NODEVMAJOR && (cmajor < 0 || cmajor >= 4096)) { 1811 cfgerror("character major %d is invalid", cmajor); 1812 condexpr_destroy(cond); 1813 nvfreel(nv_nodes); 1814 return; 1815 } 1816 1817 if (bmajor != NODEVMAJOR && (bmajor < 0 || bmajor >= 4096)) { 1818 cfgerror("block major %d is invalid", bmajor); 1819 condexpr_destroy(cond); 1820 nvfreel(nv_nodes); 1821 return; 1822 } 1823 if (cmajor == NODEVMAJOR && bmajor == NODEVMAJOR) { 1824 cfgerror("both character/block majors are not specified"); 1825 condexpr_destroy(cond); 1826 nvfreel(nv_nodes); 1827 return; 1828 } 1829 1830 dm = ecalloc(1, sizeof(*dm)); 1831 dm->dm_srcfile = yyfile; 1832 dm->dm_srcline = currentline(); 1833 dm->dm_name = name; 1834 dm->dm_cmajor = cmajor; 1835 dm->dm_bmajor = bmajor; 1836 dm->dm_opts = cond; 1837 dm->dm_devnodes = nv_nodes; 1838 1839 TAILQ_INSERT_TAIL(&alldevms, dm, dm_next); 1840 1841 maxcdevm = MAX(maxcdevm, dm->dm_cmajor); 1842 maxbdevm = MAX(maxbdevm, dm->dm_bmajor); 1843 } 1844 1845 int 1846 fixdevis(void) 1847 { 1848 struct devi *i; 1849 int error = 0; 1850 1851 TAILQ_FOREACH(i, &alldevi, i_next) { 1852 CFGDBG(3, "fixing devis `%s'", i->i_name); 1853 if (i->i_active == DEVI_ACTIVE) 1854 selectbase(i->i_base, i->i_atdeva); 1855 else if (i->i_active == DEVI_ORPHAN) { 1856 /* 1857 * At this point, we can't have instances for which 1858 * i_at or i_pspec are NULL. 1859 */ 1860 ++error; 1861 cfgxerror(i->i_srcfile, i->i_lineno, 1862 "`%s at %s' is orphaned (%s `%s' found)", 1863 i->i_name, i->i_at, i->i_pspec->p_atunit == WILD ? 1864 "nothing matching" : "no", i->i_at); 1865 } else if (vflag && i->i_active == DEVI_IGNORED) 1866 cfgxwarn(i->i_srcfile, i->i_lineno, "ignoring " 1867 "explicitly orphaned instance `%s at %s'", 1868 i->i_name, i->i_at); 1869 } 1870 1871 if (error) 1872 return error; 1873 1874 TAILQ_FOREACH(i, &allpseudo, i_next) 1875 if (i->i_active == DEVI_ACTIVE) 1876 selectbase(i->i_base, NULL); 1877 return 0; 1878 } 1879 1880 /* 1881 * Look up a parent spec, creating a new one if it does not exist. 1882 */ 1883 static struct pspec * 1884 getpspec(struct attr *attr, struct devbase *ab, int atunit) 1885 { 1886 struct pspec *p; 1887 1888 TAILQ_FOREACH(p, &allpspecs, p_list) { 1889 if (p->p_iattr == attr && 1890 p->p_atdev == ab && 1891 p->p_atunit == atunit) 1892 return (p); 1893 } 1894 1895 p = ecalloc(1, sizeof(*p)); 1896 1897 p->p_iattr = attr; 1898 p->p_atdev = ab; 1899 p->p_atunit = atunit; 1900 p->p_inst = npspecs++; 1901 p->p_active = 0; 1902 1903 TAILQ_INSERT_TAIL(&allpspecs, p, p_list); 1904 1905 return (p); 1906 } 1907 1908 /* 1909 * Define a new instance of a specific device. 1910 */ 1911 static struct devi * 1912 getdevi(const char *name) 1913 { 1914 struct devi *i, *firsti; 1915 struct devbase *d; 1916 int unit; 1917 char base[NAMESIZE]; 1918 1919 if (split(name, strlen(name), base, sizeof base, &unit)) { 1920 cfgerror("invalid device name `%s'", name); 1921 return (NULL); 1922 } 1923 d = ht_lookup(devbasetab, intern(base)); 1924 if (d == NULL) { 1925 cfgerror("%s: unknown device `%s'", name, base); 1926 return (NULL); 1927 } 1928 if (d->d_ispseudo) { 1929 cfgerror("%s: %s is a pseudo-device", name, base); 1930 return (NULL); 1931 } 1932 firsti = ht_lookup(devitab, name); 1933 i = newdevi(name, unit, d); 1934 if (firsti == NULL) { 1935 if (ht_insert(devitab, name, i)) 1936 panic("getdevi(%s)", name); 1937 *d->d_ipp = i; 1938 d->d_ipp = &i->i_bsame; 1939 } else { 1940 while (firsti->i_alias) 1941 firsti = firsti->i_alias; 1942 firsti->i_alias = i; 1943 } 1944 TAILQ_INSERT_TAIL(&alldevi, i, i_next); 1945 ndevi++; 1946 return (i); 1947 } 1948 1949 static const char * 1950 concat(const char *name, int c) 1951 { 1952 size_t len; 1953 char buf[NAMESIZE]; 1954 1955 len = strlen(name); 1956 if (len + 2 > sizeof(buf)) { 1957 cfgerror("device name `%s%c' too long", name, c); 1958 len = sizeof(buf) - 2; 1959 } 1960 memmove(buf, name, len); 1961 buf[len] = (char)c; 1962 buf[len + 1] = '\0'; 1963 return (intern(buf)); 1964 } 1965 1966 const char * 1967 starref(const char *name) 1968 { 1969 1970 return (concat(name, '*')); 1971 } 1972 1973 const char * 1974 wildref(const char *name) 1975 { 1976 1977 return (concat(name, '?')); 1978 } 1979 1980 /* 1981 * Split a name like "foo0" into base name (foo) and unit number (0). 1982 * Return 0 on success. To make this useful for names like "foo0a", 1983 * the length of the "foo0" part is one of the arguments. 1984 */ 1985 static int 1986 split(const char *name, size_t nlen, char *base, size_t bsize, int *aunit) 1987 { 1988 const char *cp; 1989 int c; 1990 size_t l; 1991 1992 l = nlen; 1993 if (l < 2 || l >= bsize || isdigit((unsigned char)*name)) 1994 return (1); 1995 c = (u_char)name[--l]; 1996 if (!isdigit(c)) { 1997 if (c == '*') 1998 *aunit = STAR; 1999 else if (c == '?') 2000 *aunit = WILD; 2001 else 2002 return (1); 2003 } else { 2004 cp = &name[l]; 2005 while (isdigit((unsigned char)cp[-1])) 2006 l--, cp--; 2007 *aunit = atoi(cp); 2008 } 2009 memmove(base, name, l); 2010 base[l] = 0; 2011 return (0); 2012 } 2013 2014 void 2015 addattr(const char *name) 2016 { 2017 struct attr *a; 2018 2019 a = refattr(name); 2020 selectattr(a); 2021 } 2022 2023 void 2024 delattr(const char *name, int nowarn) 2025 { 2026 struct attr *a; 2027 2028 a = refattr(name); 2029 deselectattr(a); 2030 } 2031 2032 void 2033 selectattr(struct attr *a) 2034 { 2035 struct attrlist *al; 2036 struct attr *dep; 2037 2038 CFGDBG(5, "selecting attr `%s'", a->a_name); 2039 for (al = a->a_deps; al != NULL; al = al->al_next) { 2040 dep = al->al_this; 2041 selectattr(dep); 2042 } 2043 if (ht_insert(selecttab, a->a_name, __UNCONST(a->a_name)) == 0) 2044 nattrs++; 2045 CFGDBG(3, "attr selected `%s'", a->a_name); 2046 } 2047 2048 static int 2049 deselectattrcb2(const char *name1, const char *name2, void *v, void *arg) 2050 { 2051 struct attr *a = arg; 2052 const char *name = a->a_name; 2053 struct vtype *vt = v; 2054 2055 if (strcmp(name, name2) == 0) { 2056 delattr(name1, 0); 2057 return 0; 2058 } 2059 2060 if (!vt->attr->a_deselected) 2061 return 0; 2062 2063 switch (vt->type) { 2064 case V_ATTRIBUTE: 2065 #ifdef notyet 2066 // XXX: Loops 2067 deselectattr(vt->value); 2068 #endif 2069 break; 2070 case V_DEVICE: 2071 CFGDBG(5, "removing device `%s' with attr `%s' because attr `%s'" 2072 " is deselected", name1, name2, name); 2073 deldevbase(vt->value); 2074 break; 2075 default: 2076 abort(); 2077 } 2078 return 0; 2079 } 2080 2081 void 2082 deselectattr(struct attr *a) 2083 { 2084 CFGDBG(5, "deselecting attr `%s'", a->a_name); 2085 a->a_deselected = 1; 2086 ht_enumerate2(attrdeptab, deselectattrcb2, a); 2087 if (ht_remove(selecttab, a->a_name) == 0) 2088 nattrs--; 2089 CFGDBG(3, "attr deselected `%s'", a->a_name); 2090 } 2091 2092 static int 2093 dumpattrdepcb2(const char *name1, const char *name2, void *v, void *arg) 2094 { 2095 2096 CFGDBG(3, "attr `%s' depends on attr `%s'", name1, name2); 2097 return 0; 2098 } 2099 2100 void 2101 dependattrs(void) 2102 { 2103 2104 ht_enumerate2(attrdeptab, dumpattrdepcb2, NULL); 2105 } 2106 2107 /* 2108 * We have an instance of the base foo, so select it and all its 2109 * attributes for "optional foo". 2110 */ 2111 static void 2112 selectbase(struct devbase *d, struct deva *da) 2113 { 2114 struct attr *a; 2115 struct attrlist *al; 2116 2117 (void)ht_insert(selecttab, d->d_name, __UNCONST(d->d_name)); 2118 CFGDBG(3, "devbase selected `%s'", d->d_name); 2119 CFGDBG(5, "selecting dependencies of devbase `%s'", d->d_name); 2120 for (al = d->d_attrs; al != NULL; al = al->al_next) { 2121 a = al->al_this; 2122 expandattr(a, selectattr); 2123 } 2124 2125 struct attr *devattr; 2126 devattr = refattr(d->d_name); 2127 expandattr(devattr, selectattr); 2128 2129 if (da != NULL) { 2130 (void)ht_insert(selecttab, da->d_name, __UNCONST(da->d_name)); 2131 CFGDBG(3, "devattr selected `%s'", da->d_name); 2132 for (al = da->d_attrs; al != NULL; al = al->al_next) { 2133 a = al->al_this; 2134 expandattr(a, selectattr); 2135 } 2136 } 2137 2138 fixdev(d); 2139 } 2140 2141 /* 2142 * Is the given pointer on the given list of pointers? 2143 */ 2144 int 2145 onlist(struct nvlist *nv, void *ptr) 2146 { 2147 for (; nv != NULL; nv = nv->nv_next) 2148 if (nv->nv_ptr == ptr) 2149 return (1); 2150 return (0); 2151 } 2152 2153 static char * 2154 extend(char *p, const char *name) 2155 { 2156 size_t l; 2157 2158 l = strlen(name); 2159 memmove(p, name, l); 2160 p += l; 2161 *p++ = ','; 2162 *p++ = ' '; 2163 return (p); 2164 } 2165 2166 /* 2167 * Check that we got all required locators, and default any that are 2168 * given as "?" and have defaults. Return 0 on success. 2169 */ 2170 static const char ** 2171 fixloc(const char *name, struct attr *attr, struct loclist *got) 2172 { 2173 struct loclist *m, *n; 2174 int ord; 2175 const char **lp; 2176 int nmissing, nextra, nnodefault; 2177 char *mp, *ep, *ndp; 2178 char missing[1000], extra[1000], nodefault[1000]; 2179 static const char *nullvec[1]; 2180 2181 /* 2182 * Look for all required locators, and number the given ones 2183 * according to the required order. While we are numbering, 2184 * set default values for defaulted locators. 2185 */ 2186 if (attr->a_loclen == 0) /* e.g., "at root" */ 2187 lp = nullvec; 2188 else 2189 lp = emalloc((size_t)(attr->a_loclen + 1) * sizeof(const char *)); 2190 for (n = got; n != NULL; n = n->ll_next) 2191 n->ll_num = -1; 2192 nmissing = 0; 2193 mp = missing; 2194 /* yes, this is O(mn), but m and n should be small */ 2195 for (ord = 0, m = attr->a_locs; m != NULL; m = m->ll_next, ord++) { 2196 for (n = got; n != NULL; n = n->ll_next) { 2197 if (n->ll_name == m->ll_name) { 2198 n->ll_num = ord; 2199 break; 2200 } 2201 } 2202 if (n == NULL && m->ll_num == 0) { 2203 nmissing++; 2204 mp = extend(mp, m->ll_name); 2205 } 2206 lp[ord] = m->ll_string; 2207 } 2208 if (ord != attr->a_loclen) 2209 panic("fixloc"); 2210 lp[ord] = NULL; 2211 nextra = 0; 2212 ep = extra; 2213 nnodefault = 0; 2214 ndp = nodefault; 2215 for (n = got; n != NULL; n = n->ll_next) { 2216 if (n->ll_num >= 0) { 2217 if (n->ll_string != NULL) 2218 lp[n->ll_num] = n->ll_string; 2219 else if (lp[n->ll_num] == NULL) { 2220 nnodefault++; 2221 ndp = extend(ndp, n->ll_name); 2222 } 2223 } else { 2224 nextra++; 2225 ep = extend(ep, n->ll_name); 2226 } 2227 } 2228 if (nextra) { 2229 ep[-2] = 0; /* kill ", " */ 2230 cfgerror("%s: extraneous locator%s: %s", 2231 name, nextra > 1 ? "s" : "", extra); 2232 } 2233 if (nmissing) { 2234 mp[-2] = 0; 2235 cfgerror("%s: must specify %s", name, missing); 2236 } 2237 if (nnodefault) { 2238 ndp[-2] = 0; 2239 cfgerror("%s: cannot wildcard %s", name, nodefault); 2240 } 2241 if (nmissing || nnodefault) { 2242 free(lp); 2243 lp = NULL; 2244 } 2245 return (lp); 2246 } 2247 2248 void 2249 setversion(int newver) 2250 { 2251 if (newver > CONFIG_VERSION) 2252 cfgerror("your sources require a newer version of config(1) " 2253 "-- please rebuild it."); 2254 else if (newver < CONFIG_MINVERSION) 2255 cfgerror("your sources are out of date -- please update."); 2256 else 2257 version = newver; 2258 } 2259