1 /* 2 * Copyright (c) 1992 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This software was developed by the Computer Systems Engineering group 6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 * contributed to Berkeley. 8 * 9 * All advertising materials mentioning features or use of this software 10 * must display the following acknowledgement: 11 * This product includes software developed by the University of 12 * California, Lawrence Berkeley Laboratories. 13 * 14 * %sccs.include.redist.c% 15 * 16 * @(#)sem.c 5.1 (Berkeley) 01/12/93 17 * 18 * from: $Header: sem.c,v 1.5 93/01/12 03:57:11 torek Exp $ 19 */ 20 21 #include <sys/param.h> 22 #include <ctype.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include "config.h" 27 #include "sem.h" 28 29 /* 30 * config semantics. 31 */ 32 33 #define NAMESIZE 100 /* local name buffers */ 34 35 static const char *s_generic; 36 static const char *s_qmark; 37 38 static struct hashtab *attrtab; /* for attribute lookup */ 39 static struct hashtab *cfhashtab; /* for config lookup */ 40 static struct hashtab *devitab; /* etc */ 41 42 static struct attr errattr; 43 static struct devbase errdev; 44 static struct devbase **nextbase; 45 static struct config **nextcf; 46 static struct devi **nextdevi; 47 static struct devi **nextpseudo; 48 49 static int has_errobj __P((struct nvlist *, void *)); 50 static struct nvlist *addtoattr __P((struct nvlist *, struct devbase *)); 51 static int exclude __P((struct nvlist *, const char *, const char *)); 52 static int resolve __P((struct nvlist **, const char *, const char *, 53 struct nvlist *, int)); 54 static int lresolve __P((struct nvlist **, const char *, const char *, 55 struct nvlist *, int)); 56 static struct devi *newdevi __P((const char *, int, struct devbase *d)); 57 static struct devi *getdevi __P((const char *)); 58 static const char *concat __P((const char *, int)); 59 static int split __P((const char *, size_t, char *, size_t, int *)); 60 static void selectbase __P((struct devbase *)); 61 static int onlist __P((struct nvlist *, void *)); 62 static const char **fixloc __P((const char *, struct attr *, struct nvlist *)); 63 64 void 65 initsem() 66 { 67 68 attrtab = ht_new(); 69 errattr.a_name = "<internal>"; 70 71 allbases = NULL; 72 nextbase = &allbases; 73 74 cfhashtab = ht_new(); 75 allcf = NULL; 76 nextcf = &allcf; 77 78 devitab = ht_new(); 79 alldevi = NULL; 80 nextdevi = &alldevi; 81 errdev.d_name = "<internal>"; 82 83 allpseudo = NULL; 84 nextpseudo = &allpseudo; 85 86 s_generic = intern("generic"); 87 s_qmark = intern("?"); 88 } 89 90 void 91 enddefs(fname) 92 const char *fname; 93 { 94 register struct devbase *dev; 95 96 for (dev = allbases; dev != NULL; dev = dev->d_next) { 97 if (!dev->d_isdef) { 98 (void)fprintf(stderr, 99 "%s: device `%s' used but not defined\n", 100 fname, dev->d_name); 101 errors++; 102 continue; 103 } 104 } 105 if (errors) { 106 (void)fprintf(stderr, "*** Stop.\n"); 107 exit(1); 108 } 109 } 110 111 void 112 setdefmaxusers(min, def, max) 113 int min, def, max; 114 { 115 116 if (min < 1 || min > def || def > max) 117 error("maxusers must have 1 <= min <= default <= max"); 118 else { 119 minmaxusers = min; 120 defmaxusers = def; 121 maxmaxusers = max; 122 } 123 } 124 125 void 126 setmaxusers(n) 127 int n; 128 { 129 130 if (maxusers != 0) { 131 error("duplicate maxusers parameter"); 132 return; 133 } 134 maxusers = n; 135 if (n < minmaxusers) { 136 error("warning: minimum of %d maxusers assumed\n", minmaxusers); 137 errors--; /* take it away */ 138 maxusers = minmaxusers; 139 } else if (n > maxmaxusers) { 140 error("warning: maxusers (%d) > %d", n, maxmaxusers); 141 errors--; 142 } 143 } 144 145 /* 146 * Define an attribute, optionally with an interface (a locator list). 147 * Since an empty locator list is logically different from "no interface", 148 * all locator lists include a dummy head node, which we discard here. 149 */ 150 int 151 defattr(name, locs) 152 const char *name; 153 struct nvlist *locs; 154 { 155 register struct attr *a; 156 register struct nvlist *nv; 157 register int len; 158 159 a = emalloc(sizeof *a); 160 if (ht_insert(attrtab, name, a)) { 161 free(a); 162 error("attribute `%s' already defined", name); 163 nvfreel(locs); 164 return (1); 165 } 166 a->a_name = name; 167 if (locs != NULL) { 168 a->a_iattr = 1; 169 a->a_locs = locs->nv_next; 170 nvfree(locs); 171 } else { 172 a->a_iattr = 0; 173 a->a_locs = NULL; 174 } 175 len = 0; 176 for (nv = a->a_locs; nv != NULL; nv = nv->nv_next) 177 len++; 178 a->a_loclen = len; 179 a->a_devs = NULL; 180 a->a_refs = NULL; 181 return (0); 182 } 183 184 /* 185 * Return true if the given `error object' is embedded in the given 186 * pointer list. 187 */ 188 static int 189 has_errobj(nv, obj) 190 register struct nvlist *nv; 191 register void *obj; 192 { 193 194 for (; nv != NULL; nv = nv->nv_next) 195 if (nv->nv_ptr == obj) 196 return (1); 197 return (0); 198 } 199 200 /* 201 * Add a device base to a list in an attribute (actually, to any list). 202 * Note that this does not check for duplicates, and does reverse the 203 * list order, but no one cares anyway. 204 */ 205 static struct nvlist * 206 addtoattr(l, dev) 207 register struct nvlist *l; 208 register struct devbase *dev; 209 { 210 register struct nvlist *n; 211 212 n = newnv(NULL, NULL, dev, 0); 213 n->nv_next = l; 214 return (n); 215 } 216 217 /* 218 * Device a device, giving its allowable parent attachments, if any. 219 * This may (or may not) also define an interface attribute and/or refer 220 * to existing attributes. There may be a list of vectors. 221 */ 222 void 223 defdev(dev, ispseudo, atlist, vectors, loclist, attrs) 224 register struct devbase *dev; 225 int ispseudo; 226 struct nvlist *atlist, *vectors, *loclist, *attrs; 227 { 228 register struct nvlist *nv; 229 register struct attr *a; 230 231 if (dev == &errdev) 232 goto bad; 233 if (dev->d_isdef) { 234 error("redefinition of `%s'", dev->d_name); 235 goto bad; 236 } 237 dev->d_isdef = 1; 238 if (has_errobj(attrs, &errattr)) 239 goto bad; 240 241 /* 242 * Handle implicit attribute definition from locator list. Do 243 * this before scanning the `at' list so that we can have, e.g.: 244 * device foo at other, foo { slot = -1 } 245 * (where you can plug in a foo-bus extender to a foo-bus). 246 */ 247 if (loclist != NULL) { 248 nv = loclist; 249 loclist = NULL; /* defattr disposes of them for us */ 250 if (defattr(dev->d_name, nv)) 251 goto bad; 252 nv = newnv(dev->d_name, NULL, getattr(dev->d_name), 0); 253 nv->nv_next = attrs; 254 attrs = nv; 255 } 256 257 /* Committed! Set up fields. */ 258 dev->d_ispseudo = ispseudo; 259 dev->d_atlist = atlist; 260 dev->d_vectors = vectors; 261 dev->d_attrs = attrs; 262 263 /* 264 * Turn the `at' list into interface attributes (map each 265 * nv_name to an attribute, or to NULL for root), and add 266 * this device to those attributes, so that children can 267 * be listed at this particular device if they are supported 268 * by that attribute. 269 */ 270 for (nv = atlist; nv != NULL; nv = nv->nv_next) { 271 if (nv->nv_name == NULL) { 272 nv->nv_ptr = NULL; /* at root */ 273 continue; 274 } 275 nv->nv_ptr = a = getattr(nv->nv_name); 276 if (a == &errattr) 277 continue; /* already complained */ 278 if (!a->a_iattr) 279 error("%s cannot be at plain attribute `%s'", 280 dev->d_name, a->a_name); 281 else 282 a->a_devs = addtoattr(a->a_devs, dev); 283 } 284 285 /* 286 * For each interface attribute this device refers to, add this 287 * device to its reference list. This makes, e.g., finding all 288 * "scsi"s easier. 289 */ 290 for (nv = attrs; nv != NULL; nv = nv->nv_next) { 291 a = nv->nv_ptr; 292 if (a->a_iattr) 293 a->a_refs = addtoattr(a->a_refs, dev); 294 } 295 return; 296 bad: 297 nvfreel(atlist); 298 nvfreel(vectors); 299 nvfreel(loclist); 300 nvfreel(attrs); 301 } 302 303 /* 304 * Look up a devbase. Also makes sure it is a reasonable name, 305 * i.e., does not end in a digit or contain special characters. 306 */ 307 struct devbase * 308 getdevbase(name) 309 const char *name; 310 { 311 register u_char *p; 312 register struct devbase *dev; 313 314 p = (u_char *)name; 315 if (!isalpha(*p)) 316 goto badname; 317 while (*++p) { 318 if (!isalnum(*p) && *p != '_') 319 goto badname; 320 } 321 if (isdigit(*--p)) { 322 badname: 323 error("bad device base name `%s'", name); 324 return (&errdev); 325 } 326 dev = ht_lookup(devbasetab, name); 327 if (dev == NULL) { 328 dev = emalloc(sizeof *dev); 329 dev->d_name = name; 330 dev->d_next = NULL; 331 dev->d_isdef = 0; 332 dev->d_major = NODEV; 333 dev->d_atlist = NULL; 334 dev->d_vectors = NULL; 335 dev->d_attrs = NULL; 336 dev->d_ihead = NULL; 337 dev->d_ipp = &dev->d_ihead; 338 dev->d_umax = 0; 339 *nextbase = dev; 340 nextbase = &dev->d_next; 341 if (ht_insert(devbasetab, name, dev)) 342 panic("getdevbase(%s)", name); 343 } 344 return (dev); 345 } 346 347 /* 348 * Look up an attribute. 349 */ 350 struct attr * 351 getattr(name) 352 const char *name; 353 { 354 struct attr *a; 355 356 if ((a = ht_lookup(attrtab, name)) == NULL) { 357 error("undefined attribute `%s'", name); 358 a = &errattr; 359 } 360 return (a); 361 } 362 363 /* 364 * Set the major device number for a device, so that it can be used 365 * as a root/swap/dumps "on" device in a configuration. 366 */ 367 void 368 setmajor(d, n) 369 struct devbase *d; 370 int n; 371 { 372 373 if (d != &errdev && d->d_major != NODEV) 374 error("device `%s' is already major %d", 375 d->d_name, d->d_major); 376 else 377 d->d_major = n; 378 } 379 380 #define ABS(x) ((x) < 0 ? -(x) : (x)) 381 382 static int 383 exclude(nv, name, what) 384 struct nvlist *nv; 385 const char *name, *what; 386 { 387 388 if (nv != NULL) { 389 error("%s: swap generic must not specify %s", name, what); 390 return (1); 391 } 392 return (0); 393 } 394 395 /* 396 * Map things like "ra0b" => makedev(major("ra"), 0*8 + 'b'-'a'). 397 * Handle the case where the device number is given but there is no 398 * corresponding name, and map NULL to the default. 399 */ 400 static int 401 resolve(nvp, name, what, dflt, part) 402 register struct nvlist **nvp; 403 const char *name, *what; 404 struct nvlist *dflt; 405 register int part; 406 { 407 register struct nvlist *nv; 408 register struct devbase *dev; 409 register const char *cp; 410 register int maj, min, l; 411 int unit; 412 char buf[NAMESIZE]; 413 414 if ((u_int)(part -= 'a') >= 7) 415 panic("resolve"); 416 if ((nv = *nvp) == NULL) { 417 /* 418 * Apply default. Easiest to do this by number. 419 */ 420 maj = major(dflt->nv_int); 421 min = (minor(dflt->nv_int) & ~7) | part; 422 *nvp = nv = newnv(NULL, NULL, NULL, makedev(maj, min)); 423 } 424 if (nv->nv_int != NODEV) { 425 /* 426 * By the numbers. Find the appropriate major number 427 * to make a name. 428 */ 429 maj = major(nv->nv_int); 430 min = minor(nv->nv_int); 431 for (dev = allbases; dev != NULL; dev = dev->d_next) 432 if (dev->d_major == maj) 433 break; 434 if (dev == NULL) 435 (void)sprintf(buf, "<%d/%d>", maj, min); 436 else 437 (void)sprintf(buf, "%s%d%c", dev->d_name, 438 min >> 3, (min & 7) + 'a'); 439 nv->nv_str = intern(buf); 440 return (0); 441 } 442 443 /* 444 * The normal case: things like "ra2b". Check for partition 445 * suffix, remove it if there, and split into name ("ra") and 446 * unit (2). 447 */ 448 l = strlen(nv->nv_str); 449 cp = &nv->nv_str[l]; 450 if (l > 1 && *--cp >= 'a' && *cp <= 'h' && isdigit(cp[-1])) { 451 l--; 452 part = *cp - 'a'; 453 } 454 cp = nv->nv_str; 455 if (split(cp, l, buf, sizeof buf, &unit)) { 456 error("%s: invalid %s device name `%s'", name, what, cp); 457 return (1); 458 } 459 dev = ht_lookup(devbasetab, intern(buf)); 460 if (dev == NULL || dev->d_major == NODEV) { 461 error("%s: can't make %s device from `%s'", 462 name, what, nv->nv_str); 463 return (1); 464 } 465 nv->nv_name = dev->d_name; 466 nv->nv_int = makedev(dev->d_major, unit * 8 + part); 467 return (0); 468 } 469 470 static int 471 lresolve(nvp, name, what, dflt, part) 472 register struct nvlist **nvp; 473 const char *name, *what; 474 struct nvlist *dflt; 475 int part; 476 { 477 int err; 478 479 while ((err = resolve(nvp, name, what, dflt, part)) == 0 && 480 (*nvp)->nv_next != NULL) 481 nvp = &(*nvp)->nv_next; 482 return (err); 483 } 484 485 /* 486 * Add a completed configuration to the list. 487 */ 488 void 489 addconf(cf0) 490 register struct config *cf0; 491 { 492 register struct config *cf; 493 register struct nvlist *nv; 494 const char *name; 495 496 name = cf0->cf_name; 497 cf = emalloc(sizeof *cf); 498 if (ht_insert(cfhashtab, name, cf)) { 499 error("configuration `%s' already defined", name); 500 free(cf); 501 goto bad; 502 } 503 *cf = *cf0; 504 505 /* 506 * Look for "swap generic". 507 */ 508 for (nv = cf->cf_swap; nv != NULL; nv = nv->nv_next) 509 if (nv->nv_str == s_generic) 510 break; 511 if (nv != NULL) { 512 /* 513 * Make sure no root or dump device specified, and no 514 * other swap devices. Note single | here (check all). 515 */ 516 nv = cf->cf_swap; 517 if (exclude(cf->cf_root, name, "root device") | 518 exclude(nv->nv_next, name, "additional swap devices") | 519 exclude(cf->cf_dump, name, "dump device")) 520 goto bad; 521 } else { 522 nv = cf->cf_root; 523 if (nv == NULL) { 524 error("%s: no root device specified", name); 525 goto bad; 526 } 527 if (resolve(&cf->cf_root, name, "root", nv, 'a') | 528 lresolve(&cf->cf_swap, name, "swap", nv, 'b') | 529 resolve(&cf->cf_dump, name, "dumps", nv, 'b')) 530 goto bad; 531 } 532 *nextcf = cf; 533 nextcf = &cf->cf_next; 534 return; 535 bad: 536 nvfreel(cf0->cf_root); 537 nvfreel(cf0->cf_swap); 538 nvfreel(cf0->cf_dump); 539 } 540 541 void 542 setconf(npp, what, v) 543 register struct nvlist **npp; 544 const char *what; 545 struct nvlist *v; 546 { 547 548 if (*npp != NULL) { 549 error("duplicate %s specification", what); 550 nvfreel(v); 551 } else 552 *npp = v; 553 } 554 555 static struct devi * 556 newdevi(name, unit, d) 557 const char *name; 558 int unit; 559 struct devbase *d; 560 { 561 register struct devi *i; 562 563 i = emalloc(sizeof *i); 564 i->i_name = name; 565 i->i_unit = unit; 566 i->i_base = d; 567 i->i_next = NULL; 568 i->i_bsame = NULL; 569 i->i_alias = NULL; 570 i->i_at = NULL; 571 i->i_atattr = NULL; 572 i->i_atdev = NULL; 573 i->i_locs = NULL; 574 i->i_cfflags = 0; 575 i->i_lineno = currentline(); 576 if (unit >= d->d_umax) 577 d->d_umax = unit + 1; 578 return (i); 579 } 580 581 /* 582 * Add the named device as attaching to the named attribute (or perhaps 583 * another device instead) plus unit number. 584 */ 585 void 586 adddev(name, at, loclist, flags) 587 const char *name, *at; 588 struct nvlist *loclist; 589 int flags; 590 { 591 register struct devi *i; /* the new instance */ 592 register struct attr *attr; /* attribute that allows attach */ 593 register struct devbase *ib; /* i->i_base */ 594 register struct devbase *ab; /* not NULL => at another dev */ 595 register struct nvlist *nv; 596 const char *cp; 597 int atunit; 598 char atbuf[NAMESIZE]; 599 600 ab = NULL; 601 if (at == NULL) { 602 /* "at root" */ 603 if ((i = getdevi(name)) == NULL) 604 goto bad; 605 /* 606 * Must warn about i_unit > 0 later, after taking care of 607 * the STAR cases (we could do non-star's here but why 608 * bother?). Make sure this device can be at root. 609 */ 610 ib = i->i_base; 611 if (!onlist(ib->d_atlist, NULL)) { 612 error("%s's cannot attach to the root", ib->d_name); 613 goto bad; 614 } 615 attr = &errattr; /* a convenient "empty" attr */ 616 } else { 617 if (split(at, strlen(at), atbuf, sizeof atbuf, &atunit)) { 618 error("invalid attachment name `%s'", at); 619 /* (void)getdevi(name); -- ??? */ 620 goto bad; 621 } 622 if ((i = getdevi(name)) == NULL) 623 goto bad; 624 ib = i->i_base; 625 cp = intern(atbuf); 626 if ((attr = ht_lookup(attrtab, cp)) == NULL) { 627 /* 628 * Have to work a bit harder to see whether we have 629 * something like "tg0 at esp0" (where esp is merely 630 * not an attribute) or "tg0 at nonesuch0" (where 631 * nonesuch is not even a device). 632 */ 633 if ((ab = ht_lookup(devbasetab, cp)) == NULL) { 634 error("%s at %s: `%s' unknown", 635 name, at, atbuf); 636 goto bad; 637 } 638 /* 639 * See if the named parent carries an attribute 640 * that allows it to supervise device ib. 641 */ 642 for (nv = ab->d_attrs; nv != NULL; nv = nv->nv_next) { 643 attr = nv->nv_ptr; 644 if (onlist(attr->a_devs, ib)) 645 goto ok; 646 } 647 attr = &errattr;/* now onlist below will fail */ 648 } 649 if (!onlist(attr->a_devs, ib)) { 650 error("%s's cannot attach to %s's", ib->d_name, atbuf); 651 goto bad; 652 } 653 } 654 ok: 655 if ((i->i_locs = fixloc(name, attr, loclist)) == NULL) 656 goto bad; 657 if (i->i_unit == STAR && ib->d_vectors != NULL) { 658 error("%s's cannot be *'d as they have preset vectors", 659 ib->d_name); 660 goto bad; 661 } 662 i->i_at = at; 663 i->i_atattr = attr; 664 i->i_atdev = ab; 665 i->i_atunit = atunit; 666 i->i_cfflags = flags; 667 selectbase(ib); 668 /* all done, fall into ... */ 669 bad: 670 nvfreel(loclist); 671 return; 672 } 673 674 void 675 addpseudo(name, number) 676 const char *name; 677 int number; 678 { 679 register struct devbase *d; 680 register struct devi *i; 681 682 d = ht_lookup(devbasetab, name); 683 if (d == NULL) { 684 error("undefined pseudo-device %s", name); 685 return; 686 } 687 if (!d->d_ispseudo) { 688 error("%s is a real device, not a pseudo-device", name); 689 return; 690 } 691 if (ht_lookup(devitab, name) != NULL) { 692 error("`%s' already defined", name); 693 return; 694 } 695 i = newdevi(name, number - 1, d); /* foo 16 => "foo0..foo15" */ 696 if (ht_insert(devitab, name, i)) 697 panic("addpseudo(%s)", name); 698 selectbase(d); 699 *nextpseudo = i; 700 nextpseudo = &i->i_next; 701 npseudo++; 702 } 703 704 /* 705 * Define a new instance of a specific device. 706 */ 707 static struct devi * 708 getdevi(name) 709 const char *name; 710 { 711 register struct devi *i, *firsti; 712 register struct devbase *d; 713 int unit; 714 char base[NAMESIZE]; 715 716 if (split(name, strlen(name), base, sizeof base, &unit)) { 717 error("invalid device name `%s'", name); 718 return (NULL); 719 } 720 d = ht_lookup(devbasetab, intern(base)); 721 if (d == NULL) { 722 error("%s: unknown device `%s'", name, base); 723 return (NULL); 724 } 725 if (d->d_ispseudo) { 726 error("%s: %s is a pseudo-device", name, base); 727 return (NULL); 728 } 729 firsti = ht_lookup(devitab, name); 730 i = newdevi(name, unit, d); 731 if (firsti == NULL) { 732 if (ht_insert(devitab, name, i)) 733 panic("getdevi(%s)", name); 734 *d->d_ipp = i; 735 d->d_ipp = &i->i_bsame; 736 } else { 737 while (firsti->i_alias) 738 firsti = firsti->i_alias; 739 firsti->i_alias = i; 740 } 741 *nextdevi = i; 742 nextdevi = &i->i_next; 743 ndevi++; 744 return (i); 745 } 746 747 static const char * 748 concat(name, c) 749 const char *name; 750 int c; 751 { 752 register int len; 753 char buf[NAMESIZE]; 754 755 len = strlen(name); 756 if (len + 2 > sizeof(buf)) { 757 error("device name `%s%c' too long", name, c); 758 len = sizeof(buf) - 2; 759 } 760 bcopy(name, buf, len); 761 buf[len] = c; 762 buf[len + 1] = 0; 763 return (intern(buf)); 764 } 765 766 const char * 767 starref(name) 768 const char *name; 769 { 770 771 return (concat(name, '*')); 772 } 773 774 const char * 775 wildref(name) 776 const char *name; 777 { 778 779 return (concat(name, '?')); 780 } 781 782 /* 783 * Split a name like "foo0" into base name (foo) and unit number (0). 784 * Return 0 on success. To make this useful for names like "foo0a", 785 * the length of the "foo0" part is one of the arguments. 786 */ 787 static int 788 split(name, nlen, base, bsize, aunit) 789 register const char *name; 790 size_t nlen; 791 char *base; 792 size_t bsize; 793 int *aunit; 794 { 795 register const char *cp; 796 register int c, l; 797 798 l = nlen; 799 if (l < 2 || l >= bsize || isdigit(*name)) 800 return (1); 801 c = (u_char)name[--l]; 802 if (!isdigit(c)) { 803 if (c == '*') 804 *aunit = STAR; 805 else if (c == '?') 806 *aunit = WILD; 807 else 808 return (1); 809 } else { 810 cp = &name[l]; 811 while (isdigit(cp[-1])) 812 l--, cp--; 813 *aunit = atoi(cp); 814 } 815 bcopy(name, base, l); 816 base[l] = 0; 817 return (0); 818 } 819 820 /* 821 * We have an instance of the base foo, so select it and all its 822 * attributes for "optional foo". 823 */ 824 static void 825 selectbase(d) 826 register struct devbase *d; 827 { 828 register struct attr *a; 829 register struct nvlist *nv; 830 831 (void)ht_insert(selecttab, d->d_name, (char *)d->d_name); 832 for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) { 833 a = nv->nv_ptr; 834 (void)ht_insert(selecttab, a->a_name, (char *)a->a_name); 835 } 836 } 837 838 /* 839 * Is the given pointer on the given list of pointers? 840 */ 841 static int 842 onlist(nv, ptr) 843 register struct nvlist *nv; 844 register void *ptr; 845 { 846 for (; nv != NULL; nv = nv->nv_next) 847 if (nv->nv_ptr == ptr) 848 return (1); 849 return (0); 850 } 851 852 static char * 853 extend(p, name) 854 register char *p; 855 const char *name; 856 { 857 register int l; 858 859 l = strlen(name); 860 bcopy(name, p, l); 861 p += l; 862 *p++ = ','; 863 *p++ = ' '; 864 return (p); 865 } 866 867 /* 868 * Check that we got all required locators, and default any that are 869 * given as "?" and have defaults. Return 0 on success. 870 */ 871 static const char ** 872 fixloc(name, attr, got) 873 const char *name; 874 register struct attr *attr; 875 register struct nvlist *got; 876 { 877 register struct nvlist *m, *n; 878 register int ord; 879 register const char **lp; 880 int nmissing, nextra, nnodefault; 881 char *mp, *ep, *ndp; 882 char missing[1000], extra[1000], nodefault[1000]; 883 static const char *nullvec[1]; 884 885 /* 886 * Look for all required locators, and number the given ones 887 * according to the required order. While we are numbering, 888 * set default values for defaulted locators. 889 */ 890 if (attr->a_loclen == 0) /* e.g., "at root" */ 891 lp = nullvec; 892 else 893 lp = emalloc((attr->a_loclen + 1) * sizeof(const char *)); 894 for (n = got; n != NULL; n = n->nv_next) 895 n->nv_int = -1; 896 nmissing = 0; 897 mp = missing; 898 /* yes, this is O(mn), but m and n should be small */ 899 for (ord = 0, m = attr->a_locs; m != NULL; m = m->nv_next, ord++) { 900 for (n = got; n != NULL; n = n->nv_next) { 901 if (n->nv_name == m->nv_name) { 902 n->nv_int = ord; 903 break; 904 } 905 } 906 if (n == NULL && m->nv_int == 0) { 907 nmissing++; 908 mp = extend(mp, m->nv_name); 909 } 910 lp[ord] = m->nv_str; 911 } 912 if (ord != attr->a_loclen) 913 panic("fixloc"); 914 lp[ord] = NULL; 915 nextra = 0; 916 ep = extra; 917 nnodefault = 0; 918 ndp = nodefault; 919 for (n = got; n != NULL; n = n->nv_next) { 920 if (n->nv_int >= 0) { 921 if (n->nv_str != NULL) 922 lp[n->nv_int] = n->nv_str; 923 else if (lp[n->nv_int] == NULL) { 924 nnodefault++; 925 ndp = extend(ndp, n->nv_name); 926 } 927 } else { 928 nextra++; 929 ep = extend(ep, n->nv_name); 930 } 931 } 932 if (nextra) { 933 ep[-2] = 0; /* kill ", " */ 934 error("%s: extraneous locator%s: %s", 935 name, nextra > 1 ? "s" : "", extra); 936 } 937 if (nmissing) { 938 mp[-2] = 0; 939 error("%s: must specify %s", name, missing); 940 } 941 if (nnodefault) { 942 ndp[-2] = 0; 943 error("%s: cannot wildcard %s", name, nodefault); 944 } 945 if (nmissing || nnodefault) { 946 free(lp); 947 lp = NULL; 948 } 949 return (lp); 950 } 951