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