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