157495Storek /*
2*61818Sbostic * Copyright (c) 1992, 1993
3*61818Sbostic * The Regents of the University of California. All rights reserved.
457495Storek *
557495Storek * This software was developed by the Computer Systems Engineering group
657495Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
757495Storek * contributed to Berkeley.
857495Storek *
957495Storek * All advertising materials mentioning features or use of this software
1057495Storek * must display the following acknowledgement:
1157495Storek * This product includes software developed by the University of
1257495Storek * California, Lawrence Berkeley Laboratories.
1357495Storek *
1457495Storek * %sccs.include.redist.c%
1557495Storek *
16*61818Sbostic * @(#)sem.c 8.1 (Berkeley) 06/06/93
1757495Storek */
1857495Storek
1957495Storek #include <sys/param.h>
2057495Storek #include <ctype.h>
2157495Storek #include <stdio.h>
2257495Storek #include <stdlib.h>
2357495Storek #include <string.h>
2457495Storek #include "config.h"
2557495Storek #include "sem.h"
2657495Storek
2757495Storek /*
2857495Storek * config semantics.
2957495Storek */
3057495Storek
3157495Storek #define NAMESIZE 100 /* local name buffers */
3257495Storek
3357495Storek static const char *s_generic;
3457495Storek static const char *s_qmark;
3557495Storek
3657495Storek static struct hashtab *attrtab; /* for attribute lookup */
3757495Storek static struct hashtab *cfhashtab; /* for config lookup */
3857495Storek static struct hashtab *devitab; /* etc */
3957495Storek
4057495Storek static struct attr errattr;
4157495Storek static struct devbase errdev;
4257495Storek static struct devbase **nextbase;
4357495Storek static struct config **nextcf;
4457495Storek static struct devi **nextdevi;
4557495Storek static struct devi **nextpseudo;
4657495Storek
4757495Storek static int has_errobj __P((struct nvlist *, void *));
4857495Storek static struct nvlist *addtoattr __P((struct nvlist *, struct devbase *));
4957495Storek static int exclude __P((struct nvlist *, const char *, const char *));
5057495Storek static int resolve __P((struct nvlist **, const char *, const char *,
5157495Storek struct nvlist *, int));
5257495Storek static int lresolve __P((struct nvlist **, const char *, const char *,
5357495Storek struct nvlist *, int));
5457495Storek static struct devi *newdevi __P((const char *, int, struct devbase *d));
5557495Storek static struct devi *getdevi __P((const char *));
5657495Storek static const char *concat __P((const char *, int));
5757495Storek static int split __P((const char *, size_t, char *, size_t, int *));
5857495Storek static void selectbase __P((struct devbase *));
5957495Storek static int onlist __P((struct nvlist *, void *));
6057495Storek static const char **fixloc __P((const char *, struct attr *, struct nvlist *));
6157495Storek
6257495Storek void
initsem()6357495Storek initsem()
6457495Storek {
6557495Storek
6657495Storek attrtab = ht_new();
6757495Storek errattr.a_name = "<internal>";
6857495Storek
6957495Storek allbases = NULL;
7057495Storek nextbase = &allbases;
7157495Storek
7257495Storek cfhashtab = ht_new();
7357495Storek allcf = NULL;
7457495Storek nextcf = &allcf;
7557495Storek
7657495Storek devitab = ht_new();
7757495Storek alldevi = NULL;
7857495Storek nextdevi = &alldevi;
7957495Storek errdev.d_name = "<internal>";
8057495Storek
8157495Storek allpseudo = NULL;
8257495Storek nextpseudo = &allpseudo;
8357495Storek
8457495Storek s_generic = intern("generic");
8557495Storek s_qmark = intern("?");
8657495Storek }
8757495Storek
8857495Storek void
enddefs(fname)8957495Storek enddefs(fname)
9057495Storek const char *fname;
9157495Storek {
9257495Storek register struct devbase *dev;
9357495Storek
9457495Storek for (dev = allbases; dev != NULL; dev = dev->d_next) {
9557495Storek if (!dev->d_isdef) {
9657495Storek (void)fprintf(stderr,
9757495Storek "%s: device `%s' used but not defined\n",
9857495Storek fname, dev->d_name);
9957495Storek errors++;
10057495Storek continue;
10157495Storek }
10257495Storek }
10357495Storek if (errors) {
10457495Storek (void)fprintf(stderr, "*** Stop.\n");
10557495Storek exit(1);
10657495Storek }
10757495Storek }
10857495Storek
10957495Storek void
setdefmaxusers(min,def,max)11057495Storek setdefmaxusers(min, def, max)
11157495Storek int min, def, max;
11257495Storek {
11357495Storek
11457495Storek if (min < 1 || min > def || def > max)
11557495Storek error("maxusers must have 1 <= min <= default <= max");
11657495Storek else {
11757495Storek minmaxusers = min;
11857495Storek defmaxusers = def;
11957495Storek maxmaxusers = max;
12057495Storek }
12157495Storek }
12257495Storek
12357495Storek void
setmaxusers(n)12457495Storek setmaxusers(n)
12557495Storek int n;
12657495Storek {
12757495Storek
12857495Storek if (maxusers != 0) {
12957495Storek error("duplicate maxusers parameter");
13057495Storek return;
13157495Storek }
13257495Storek maxusers = n;
13357495Storek if (n < minmaxusers) {
13457495Storek error("warning: minimum of %d maxusers assumed\n", minmaxusers);
13557495Storek errors--; /* take it away */
13657495Storek maxusers = minmaxusers;
13757495Storek } else if (n > maxmaxusers) {
13857495Storek error("warning: maxusers (%d) > %d", n, maxmaxusers);
13957495Storek errors--;
14057495Storek }
14157495Storek }
14257495Storek
14357495Storek /*
14457495Storek * Define an attribute, optionally with an interface (a locator list).
14557495Storek * Since an empty locator list is logically different from "no interface",
14657495Storek * all locator lists include a dummy head node, which we discard here.
14757495Storek */
14857495Storek int
defattr(name,locs)14957495Storek defattr(name, locs)
15057495Storek const char *name;
15157495Storek struct nvlist *locs;
15257495Storek {
15357495Storek register struct attr *a;
15457495Storek register struct nvlist *nv;
15557495Storek register int len;
15657495Storek
15757495Storek a = emalloc(sizeof *a);
15857495Storek if (ht_insert(attrtab, name, a)) {
15957495Storek free(a);
16057495Storek error("attribute `%s' already defined", name);
16157495Storek nvfreel(locs);
16257495Storek return (1);
16357495Storek }
16457495Storek a->a_name = name;
16557495Storek if (locs != NULL) {
16657495Storek a->a_iattr = 1;
16757495Storek a->a_locs = locs->nv_next;
16857495Storek nvfree(locs);
16957495Storek } else {
17057495Storek a->a_iattr = 0;
17157495Storek a->a_locs = NULL;
17257495Storek }
17357495Storek len = 0;
17457495Storek for (nv = a->a_locs; nv != NULL; nv = nv->nv_next)
17557495Storek len++;
17657495Storek a->a_loclen = len;
17757495Storek a->a_devs = NULL;
17857495Storek a->a_refs = NULL;
17957495Storek return (0);
18057495Storek }
18157495Storek
18257495Storek /*
18357495Storek * Return true if the given `error object' is embedded in the given
18457495Storek * pointer list.
18557495Storek */
18657495Storek static int
has_errobj(nv,obj)18757495Storek has_errobj(nv, obj)
18857495Storek register struct nvlist *nv;
18957495Storek register void *obj;
19057495Storek {
19157495Storek
19257495Storek for (; nv != NULL; nv = nv->nv_next)
19357495Storek if (nv->nv_ptr == obj)
19457495Storek return (1);
19557495Storek return (0);
19657495Storek }
19757495Storek
19857495Storek /*
19957495Storek * Add a device base to a list in an attribute (actually, to any list).
20057495Storek * Note that this does not check for duplicates, and does reverse the
20157495Storek * list order, but no one cares anyway.
20257495Storek */
20357495Storek static struct nvlist *
addtoattr(l,dev)20457495Storek addtoattr(l, dev)
20557495Storek register struct nvlist *l;
20657495Storek register struct devbase *dev;
20757495Storek {
20857495Storek register struct nvlist *n;
20957495Storek
21057495Storek n = newnv(NULL, NULL, dev, 0);
21157495Storek n->nv_next = l;
21257495Storek return (n);
21357495Storek }
21457495Storek
21557495Storek /*
21657495Storek * Device a device, giving its allowable parent attachments, if any.
21757495Storek * This may (or may not) also define an interface attribute and/or refer
21857495Storek * to existing attributes. There may be a list of vectors.
21957495Storek */
22057495Storek void
defdev(dev,ispseudo,atlist,vectors,loclist,attrs)22157495Storek defdev(dev, ispseudo, atlist, vectors, loclist, attrs)
22257495Storek register struct devbase *dev;
22357495Storek int ispseudo;
22457495Storek struct nvlist *atlist, *vectors, *loclist, *attrs;
22557495Storek {
22657495Storek register struct nvlist *nv;
22757495Storek register struct attr *a;
22857495Storek
22957495Storek if (dev == &errdev)
23057495Storek goto bad;
23157495Storek if (dev->d_isdef) {
23257495Storek error("redefinition of `%s'", dev->d_name);
23357495Storek goto bad;
23457495Storek }
23557495Storek dev->d_isdef = 1;
23657495Storek if (has_errobj(attrs, &errattr))
23757495Storek goto bad;
23857495Storek
23957495Storek /*
24057495Storek * Handle implicit attribute definition from locator list. Do
24157495Storek * this before scanning the `at' list so that we can have, e.g.:
24257495Storek * device foo at other, foo { slot = -1 }
24357495Storek * (where you can plug in a foo-bus extender to a foo-bus).
24457495Storek */
24557495Storek if (loclist != NULL) {
24657495Storek nv = loclist;
24757495Storek loclist = NULL; /* defattr disposes of them for us */
24857495Storek if (defattr(dev->d_name, nv))
24957495Storek goto bad;
25057495Storek nv = newnv(dev->d_name, NULL, getattr(dev->d_name), 0);
25157495Storek nv->nv_next = attrs;
25257495Storek attrs = nv;
25357495Storek }
25457495Storek
25557495Storek /* Committed! Set up fields. */
25657495Storek dev->d_ispseudo = ispseudo;
25757495Storek dev->d_atlist = atlist;
25857495Storek dev->d_vectors = vectors;
25957495Storek dev->d_attrs = attrs;
26057495Storek
26157495Storek /*
26257495Storek * Turn the `at' list into interface attributes (map each
26357495Storek * nv_name to an attribute, or to NULL for root), and add
26457495Storek * this device to those attributes, so that children can
26557495Storek * be listed at this particular device if they are supported
26657495Storek * by that attribute.
26757495Storek */
26857495Storek for (nv = atlist; nv != NULL; nv = nv->nv_next) {
26957495Storek if (nv->nv_name == NULL) {
27057495Storek nv->nv_ptr = NULL; /* at root */
27157495Storek continue;
27257495Storek }
27357495Storek nv->nv_ptr = a = getattr(nv->nv_name);
27457495Storek if (a == &errattr)
27557495Storek continue; /* already complained */
27657495Storek if (!a->a_iattr)
27757495Storek error("%s cannot be at plain attribute `%s'",
27857495Storek dev->d_name, a->a_name);
27957495Storek else
28057495Storek a->a_devs = addtoattr(a->a_devs, dev);
28157495Storek }
28257495Storek
28357495Storek /*
28457495Storek * For each interface attribute this device refers to, add this
28557495Storek * device to its reference list. This makes, e.g., finding all
28657495Storek * "scsi"s easier.
28757495Storek */
28857495Storek for (nv = attrs; nv != NULL; nv = nv->nv_next) {
28957495Storek a = nv->nv_ptr;
29057495Storek if (a->a_iattr)
29157495Storek a->a_refs = addtoattr(a->a_refs, dev);
29257495Storek }
29357495Storek return;
29457495Storek bad:
29557495Storek nvfreel(atlist);
29657495Storek nvfreel(vectors);
29757495Storek nvfreel(loclist);
29857495Storek nvfreel(attrs);
29957495Storek }
30057495Storek
30157495Storek /*
30257495Storek * Look up a devbase. Also makes sure it is a reasonable name,
30357495Storek * i.e., does not end in a digit or contain special characters.
30457495Storek */
30557495Storek struct devbase *
getdevbase(name)30657495Storek getdevbase(name)
30757495Storek const char *name;
30857495Storek {
30957495Storek register u_char *p;
31057495Storek register struct devbase *dev;
31157495Storek
31257495Storek p = (u_char *)name;
31357495Storek if (!isalpha(*p))
31457495Storek goto badname;
31557495Storek while (*++p) {
31657495Storek if (!isalnum(*p) && *p != '_')
31757495Storek goto badname;
31857495Storek }
31957495Storek if (isdigit(*--p)) {
32057495Storek badname:
32157495Storek error("bad device base name `%s'", name);
32257495Storek return (&errdev);
32357495Storek }
32457495Storek dev = ht_lookup(devbasetab, name);
32557495Storek if (dev == NULL) {
32657495Storek dev = emalloc(sizeof *dev);
32757495Storek dev->d_name = name;
32857495Storek dev->d_next = NULL;
32957495Storek dev->d_isdef = 0;
33057495Storek dev->d_major = NODEV;
33157495Storek dev->d_atlist = NULL;
33257495Storek dev->d_vectors = NULL;
33357495Storek dev->d_attrs = NULL;
33457495Storek dev->d_ihead = NULL;
33557495Storek dev->d_ipp = &dev->d_ihead;
33657495Storek dev->d_umax = 0;
33757495Storek *nextbase = dev;
33857495Storek nextbase = &dev->d_next;
33957495Storek if (ht_insert(devbasetab, name, dev))
34057495Storek panic("getdevbase(%s)", name);
34157495Storek }
34257495Storek return (dev);
34357495Storek }
34457495Storek
34557495Storek /*
34657495Storek * Look up an attribute.
34757495Storek */
34857495Storek struct attr *
getattr(name)34957495Storek getattr(name)
35057495Storek const char *name;
35157495Storek {
35257495Storek struct attr *a;
35357495Storek
35457495Storek if ((a = ht_lookup(attrtab, name)) == NULL) {
35557495Storek error("undefined attribute `%s'", name);
35657495Storek a = &errattr;
35757495Storek }
35857495Storek return (a);
35957495Storek }
36057495Storek
36157495Storek /*
36257495Storek * Set the major device number for a device, so that it can be used
36357495Storek * as a root/swap/dumps "on" device in a configuration.
36457495Storek */
36557495Storek void
setmajor(d,n)36657495Storek setmajor(d, n)
36757495Storek struct devbase *d;
36857495Storek int n;
36957495Storek {
37057495Storek
37157495Storek if (d != &errdev && d->d_major != NODEV)
37257495Storek error("device `%s' is already major %d",
37357495Storek d->d_name, d->d_major);
37457495Storek else
37557495Storek d->d_major = n;
37657495Storek }
37757495Storek
37857495Storek #define ABS(x) ((x) < 0 ? -(x) : (x))
37957495Storek
38057495Storek static int
exclude(nv,name,what)38157495Storek exclude(nv, name, what)
38257495Storek struct nvlist *nv;
38357495Storek const char *name, *what;
38457495Storek {
38557495Storek
38657495Storek if (nv != NULL) {
38757495Storek error("%s: swap generic must not specify %s", name, what);
38857495Storek return (1);
38957495Storek }
39057495Storek return (0);
39157495Storek }
39257495Storek
39357495Storek /*
39457495Storek * Map things like "ra0b" => makedev(major("ra"), 0*8 + 'b'-'a').
39557495Storek * Handle the case where the device number is given but there is no
39657495Storek * corresponding name, and map NULL to the default.
39757495Storek */
39857495Storek static int
resolve(nvp,name,what,dflt,part)39957495Storek resolve(nvp, name, what, dflt, part)
40057495Storek register struct nvlist **nvp;
40157495Storek const char *name, *what;
40257495Storek struct nvlist *dflt;
40357495Storek register int part;
40457495Storek {
40557495Storek register struct nvlist *nv;
40657495Storek register struct devbase *dev;
40757495Storek register const char *cp;
40857495Storek register int maj, min, l;
40957495Storek int unit;
41057495Storek char buf[NAMESIZE];
41157495Storek
41257495Storek if ((u_int)(part -= 'a') >= 7)
41357495Storek panic("resolve");
41457495Storek if ((nv = *nvp) == NULL) {
41557495Storek /*
41657495Storek * Apply default. Easiest to do this by number.
41757495Storek */
41857495Storek maj = major(dflt->nv_int);
41957495Storek min = (minor(dflt->nv_int) & ~7) | part;
42057495Storek *nvp = nv = newnv(NULL, NULL, NULL, makedev(maj, min));
42157495Storek }
42257495Storek if (nv->nv_int != NODEV) {
42357495Storek /*
42457495Storek * By the numbers. Find the appropriate major number
42557495Storek * to make a name.
42657495Storek */
42757495Storek maj = major(nv->nv_int);
42857495Storek min = minor(nv->nv_int);
42957495Storek for (dev = allbases; dev != NULL; dev = dev->d_next)
43057495Storek if (dev->d_major == maj)
43157495Storek break;
43257495Storek if (dev == NULL)
43357495Storek (void)sprintf(buf, "<%d/%d>", maj, min);
43457495Storek else
43557495Storek (void)sprintf(buf, "%s%d%c", dev->d_name,
43657495Storek min >> 3, (min & 7) + 'a');
43757495Storek nv->nv_str = intern(buf);
43857495Storek return (0);
43957495Storek }
44057495Storek
44157495Storek /*
44257495Storek * The normal case: things like "ra2b". Check for partition
44357495Storek * suffix, remove it if there, and split into name ("ra") and
44457495Storek * unit (2).
44557495Storek */
44657495Storek l = strlen(nv->nv_str);
44757495Storek cp = &nv->nv_str[l];
44857495Storek if (l > 1 && *--cp >= 'a' && *cp <= 'h' && isdigit(cp[-1])) {
44957495Storek l--;
45057495Storek part = *cp - 'a';
45157495Storek }
45257495Storek cp = nv->nv_str;
45357495Storek if (split(cp, l, buf, sizeof buf, &unit)) {
45457495Storek error("%s: invalid %s device name `%s'", name, what, cp);
45557495Storek return (1);
45657495Storek }
45757495Storek dev = ht_lookup(devbasetab, intern(buf));
45857495Storek if (dev == NULL || dev->d_major == NODEV) {
45957495Storek error("%s: can't make %s device from `%s'",
46057495Storek name, what, nv->nv_str);
46157495Storek return (1);
46257495Storek }
46357495Storek nv->nv_name = dev->d_name;
46457495Storek nv->nv_int = makedev(dev->d_major, unit * 8 + part);
46557495Storek return (0);
46657495Storek }
46757495Storek
46857495Storek static int
lresolve(nvp,name,what,dflt,part)46957495Storek lresolve(nvp, name, what, dflt, part)
47057495Storek register struct nvlist **nvp;
47157495Storek const char *name, *what;
47257495Storek struct nvlist *dflt;
47357495Storek int part;
47457495Storek {
47557495Storek int err;
47657495Storek
47757495Storek while ((err = resolve(nvp, name, what, dflt, part)) == 0 &&
47857495Storek (*nvp)->nv_next != NULL)
47957495Storek nvp = &(*nvp)->nv_next;
48057495Storek return (err);
48157495Storek }
48257495Storek
48357495Storek /*
48457495Storek * Add a completed configuration to the list.
48557495Storek */
48657495Storek void
addconf(cf0)48757495Storek addconf(cf0)
48857495Storek register struct config *cf0;
48957495Storek {
49057495Storek register struct config *cf;
49157495Storek register struct nvlist *nv;
49257495Storek const char *name;
49357495Storek
49457495Storek name = cf0->cf_name;
49557495Storek cf = emalloc(sizeof *cf);
49657495Storek if (ht_insert(cfhashtab, name, cf)) {
49757495Storek error("configuration `%s' already defined", name);
49857495Storek free(cf);
49957495Storek goto bad;
50057495Storek }
50157495Storek *cf = *cf0;
50257495Storek
50357495Storek /*
50457495Storek * Look for "swap generic".
50557495Storek */
50657495Storek for (nv = cf->cf_swap; nv != NULL; nv = nv->nv_next)
50757495Storek if (nv->nv_str == s_generic)
50857495Storek break;
50957495Storek if (nv != NULL) {
51057495Storek /*
51157495Storek * Make sure no root or dump device specified, and no
51257495Storek * other swap devices. Note single | here (check all).
51357495Storek */
51457495Storek nv = cf->cf_swap;
51557495Storek if (exclude(cf->cf_root, name, "root device") |
51657495Storek exclude(nv->nv_next, name, "additional swap devices") |
51757495Storek exclude(cf->cf_dump, name, "dump device"))
51857495Storek goto bad;
51957495Storek } else {
52057495Storek nv = cf->cf_root;
52157495Storek if (nv == NULL) {
52257495Storek error("%s: no root device specified", name);
52357495Storek goto bad;
52457495Storek }
52557495Storek if (resolve(&cf->cf_root, name, "root", nv, 'a') |
52657495Storek lresolve(&cf->cf_swap, name, "swap", nv, 'b') |
52757495Storek resolve(&cf->cf_dump, name, "dumps", nv, 'b'))
52857495Storek goto bad;
52957495Storek }
53057495Storek *nextcf = cf;
53157495Storek nextcf = &cf->cf_next;
53257495Storek return;
53357495Storek bad:
53457495Storek nvfreel(cf0->cf_root);
53557495Storek nvfreel(cf0->cf_swap);
53657495Storek nvfreel(cf0->cf_dump);
53757495Storek }
53857495Storek
53957495Storek void
setconf(npp,what,v)54057495Storek setconf(npp, what, v)
54157495Storek register struct nvlist **npp;
54257495Storek const char *what;
54357495Storek struct nvlist *v;
54457495Storek {
54557495Storek
54657495Storek if (*npp != NULL) {
54757495Storek error("duplicate %s specification", what);
54857495Storek nvfreel(v);
54957495Storek } else
55057495Storek *npp = v;
55157495Storek }
55257495Storek
55357495Storek static struct devi *
newdevi(name,unit,d)55457495Storek newdevi(name, unit, d)
55557495Storek const char *name;
55657495Storek int unit;
55757495Storek struct devbase *d;
55857495Storek {
55957495Storek register struct devi *i;
56057495Storek
56157495Storek i = emalloc(sizeof *i);
56257495Storek i->i_name = name;
56357495Storek i->i_unit = unit;
56457495Storek i->i_base = d;
56557495Storek i->i_next = NULL;
56657495Storek i->i_bsame = NULL;
56757495Storek i->i_alias = NULL;
56857495Storek i->i_at = NULL;
56957495Storek i->i_atattr = NULL;
57057495Storek i->i_atdev = NULL;
57157495Storek i->i_locs = NULL;
57257495Storek i->i_cfflags = 0;
57357495Storek i->i_lineno = currentline();
57457495Storek if (unit >= d->d_umax)
57557495Storek d->d_umax = unit + 1;
57657495Storek return (i);
57757495Storek }
57857495Storek
57957495Storek /*
58057495Storek * Add the named device as attaching to the named attribute (or perhaps
58157495Storek * another device instead) plus unit number.
58257495Storek */
58357495Storek void
adddev(name,at,loclist,flags)58457495Storek adddev(name, at, loclist, flags)
58557495Storek const char *name, *at;
58657495Storek struct nvlist *loclist;
58757495Storek int flags;
58857495Storek {
58957495Storek register struct devi *i; /* the new instance */
59057495Storek register struct attr *attr; /* attribute that allows attach */
59157495Storek register struct devbase *ib; /* i->i_base */
59257495Storek register struct devbase *ab; /* not NULL => at another dev */
59357495Storek register struct nvlist *nv;
59457495Storek const char *cp;
59557495Storek int atunit;
59657495Storek char atbuf[NAMESIZE];
59757495Storek
59857495Storek ab = NULL;
59957495Storek if (at == NULL) {
60057495Storek /* "at root" */
60157495Storek if ((i = getdevi(name)) == NULL)
60257495Storek goto bad;
60357495Storek /*
60457495Storek * Must warn about i_unit > 0 later, after taking care of
60557495Storek * the STAR cases (we could do non-star's here but why
60657495Storek * bother?). Make sure this device can be at root.
60757495Storek */
60857495Storek ib = i->i_base;
60957495Storek if (!onlist(ib->d_atlist, NULL)) {
61057495Storek error("%s's cannot attach to the root", ib->d_name);
61157495Storek goto bad;
61257495Storek }
61357495Storek attr = &errattr; /* a convenient "empty" attr */
61457495Storek } else {
61557495Storek if (split(at, strlen(at), atbuf, sizeof atbuf, &atunit)) {
61657495Storek error("invalid attachment name `%s'", at);
61757495Storek /* (void)getdevi(name); -- ??? */
61857495Storek goto bad;
61957495Storek }
62057495Storek if ((i = getdevi(name)) == NULL)
62157495Storek goto bad;
62257495Storek ib = i->i_base;
62357495Storek cp = intern(atbuf);
62457495Storek if ((attr = ht_lookup(attrtab, cp)) == NULL) {
62557495Storek /*
62657495Storek * Have to work a bit harder to see whether we have
62757495Storek * something like "tg0 at esp0" (where esp is merely
62857495Storek * not an attribute) or "tg0 at nonesuch0" (where
62957495Storek * nonesuch is not even a device).
63057495Storek */
63157495Storek if ((ab = ht_lookup(devbasetab, cp)) == NULL) {
63257495Storek error("%s at %s: `%s' unknown",
63357495Storek name, at, atbuf);
63457495Storek goto bad;
63557495Storek }
63657495Storek /*
63757495Storek * See if the named parent carries an attribute
63857495Storek * that allows it to supervise device ib.
63957495Storek */
64057495Storek for (nv = ab->d_attrs; nv != NULL; nv = nv->nv_next) {
64157495Storek attr = nv->nv_ptr;
64257495Storek if (onlist(attr->a_devs, ib))
64357495Storek goto ok;
64457495Storek }
64557495Storek attr = &errattr;/* now onlist below will fail */
64657495Storek }
64757495Storek if (!onlist(attr->a_devs, ib)) {
64857495Storek error("%s's cannot attach to %s's", ib->d_name, atbuf);
64957495Storek goto bad;
65057495Storek }
65157495Storek }
65257495Storek ok:
65357495Storek if ((i->i_locs = fixloc(name, attr, loclist)) == NULL)
65457495Storek goto bad;
65557495Storek if (i->i_unit == STAR && ib->d_vectors != NULL) {
65657495Storek error("%s's cannot be *'d as they have preset vectors",
65757495Storek ib->d_name);
65857495Storek goto bad;
65957495Storek }
66057495Storek i->i_at = at;
66157495Storek i->i_atattr = attr;
66257495Storek i->i_atdev = ab;
66357495Storek i->i_atunit = atunit;
66457495Storek i->i_cfflags = flags;
66557495Storek selectbase(ib);
66657495Storek /* all done, fall into ... */
66757495Storek bad:
66857495Storek nvfreel(loclist);
66957495Storek return;
67057495Storek }
67157495Storek
67257495Storek void
addpseudo(name,number)67357495Storek addpseudo(name, number)
67457495Storek const char *name;
67557495Storek int number;
67657495Storek {
67757495Storek register struct devbase *d;
67857495Storek register struct devi *i;
67957495Storek
68057495Storek d = ht_lookup(devbasetab, name);
68157495Storek if (d == NULL) {
68257495Storek error("undefined pseudo-device %s", name);
68357495Storek return;
68457495Storek }
68557495Storek if (!d->d_ispseudo) {
68657495Storek error("%s is a real device, not a pseudo-device", name);
68757495Storek return;
68857495Storek }
68957495Storek if (ht_lookup(devitab, name) != NULL) {
69057495Storek error("`%s' already defined", name);
69157495Storek return;
69257495Storek }
69357495Storek i = newdevi(name, number - 1, d); /* foo 16 => "foo0..foo15" */
69457495Storek if (ht_insert(devitab, name, i))
69557495Storek panic("addpseudo(%s)", name);
69657495Storek selectbase(d);
69757495Storek *nextpseudo = i;
69857495Storek nextpseudo = &i->i_next;
69957495Storek npseudo++;
70057495Storek }
70157495Storek
70257495Storek /*
70357495Storek * Define a new instance of a specific device.
70457495Storek */
70557495Storek static struct devi *
getdevi(name)70657495Storek getdevi(name)
70757495Storek const char *name;
70857495Storek {
70957495Storek register struct devi *i, *firsti;
71057495Storek register struct devbase *d;
71157495Storek int unit;
71257495Storek char base[NAMESIZE];
71357495Storek
71457495Storek if (split(name, strlen(name), base, sizeof base, &unit)) {
71557495Storek error("invalid device name `%s'", name);
71657495Storek return (NULL);
71757495Storek }
71857495Storek d = ht_lookup(devbasetab, intern(base));
71957495Storek if (d == NULL) {
72057495Storek error("%s: unknown device `%s'", name, base);
72157495Storek return (NULL);
72257495Storek }
72357495Storek if (d->d_ispseudo) {
72457495Storek error("%s: %s is a pseudo-device", name, base);
72557495Storek return (NULL);
72657495Storek }
72757495Storek firsti = ht_lookup(devitab, name);
72857495Storek i = newdevi(name, unit, d);
72957495Storek if (firsti == NULL) {
73057495Storek if (ht_insert(devitab, name, i))
73157495Storek panic("getdevi(%s)", name);
73257495Storek *d->d_ipp = i;
73357495Storek d->d_ipp = &i->i_bsame;
73457495Storek } else {
73557495Storek while (firsti->i_alias)
73657495Storek firsti = firsti->i_alias;
73757495Storek firsti->i_alias = i;
73857495Storek }
73957495Storek *nextdevi = i;
74057495Storek nextdevi = &i->i_next;
74157495Storek ndevi++;
74257495Storek return (i);
74357495Storek }
74457495Storek
74557495Storek static const char *
concat(name,c)74657495Storek concat(name, c)
74757495Storek const char *name;
74857495Storek int c;
74957495Storek {
75057495Storek register int len;
75157495Storek char buf[NAMESIZE];
75257495Storek
75357495Storek len = strlen(name);
75457495Storek if (len + 2 > sizeof(buf)) {
75557495Storek error("device name `%s%c' too long", name, c);
75657495Storek len = sizeof(buf) - 2;
75757495Storek }
75857495Storek bcopy(name, buf, len);
75957495Storek buf[len] = c;
76057495Storek buf[len + 1] = 0;
76157495Storek return (intern(buf));
76257495Storek }
76357495Storek
76457495Storek const char *
starref(name)76557495Storek starref(name)
76657495Storek const char *name;
76757495Storek {
76857495Storek
76957495Storek return (concat(name, '*'));
77057495Storek }
77157495Storek
77257495Storek const char *
wildref(name)77357495Storek wildref(name)
77457495Storek const char *name;
77557495Storek {
77657495Storek
77757495Storek return (concat(name, '?'));
77857495Storek }
77957495Storek
78057495Storek /*
78157495Storek * Split a name like "foo0" into base name (foo) and unit number (0).
78257495Storek * Return 0 on success. To make this useful for names like "foo0a",
78357495Storek * the length of the "foo0" part is one of the arguments.
78457495Storek */
78557495Storek static int
split(name,nlen,base,bsize,aunit)78657495Storek split(name, nlen, base, bsize, aunit)
78757495Storek register const char *name;
78857495Storek size_t nlen;
78957495Storek char *base;
79057495Storek size_t bsize;
79157495Storek int *aunit;
79257495Storek {
79357495Storek register const char *cp;
79457495Storek register int c, l;
79557495Storek
79657495Storek l = nlen;
79757495Storek if (l < 2 || l >= bsize || isdigit(*name))
79857495Storek return (1);
79957495Storek c = (u_char)name[--l];
80057495Storek if (!isdigit(c)) {
80157495Storek if (c == '*')
80257495Storek *aunit = STAR;
80357495Storek else if (c == '?')
80457495Storek *aunit = WILD;
80557495Storek else
80657495Storek return (1);
80757495Storek } else {
80857495Storek cp = &name[l];
80957495Storek while (isdigit(cp[-1]))
81057495Storek l--, cp--;
81157495Storek *aunit = atoi(cp);
81257495Storek }
81357495Storek bcopy(name, base, l);
81457495Storek base[l] = 0;
81557495Storek return (0);
81657495Storek }
81757495Storek
81857495Storek /*
81957495Storek * We have an instance of the base foo, so select it and all its
82057495Storek * attributes for "optional foo".
82157495Storek */
82257495Storek static void
selectbase(d)82357495Storek selectbase(d)
82457495Storek register struct devbase *d;
82557495Storek {
82657495Storek register struct attr *a;
82757495Storek register struct nvlist *nv;
82857495Storek
82957495Storek (void)ht_insert(selecttab, d->d_name, (char *)d->d_name);
83057495Storek for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) {
83157495Storek a = nv->nv_ptr;
83257495Storek (void)ht_insert(selecttab, a->a_name, (char *)a->a_name);
83357495Storek }
83457495Storek }
83557495Storek
83657495Storek /*
83757495Storek * Is the given pointer on the given list of pointers?
83857495Storek */
83957495Storek static int
onlist(nv,ptr)84057495Storek onlist(nv, ptr)
84157495Storek register struct nvlist *nv;
84257495Storek register void *ptr;
84357495Storek {
84457495Storek for (; nv != NULL; nv = nv->nv_next)
84557495Storek if (nv->nv_ptr == ptr)
84657495Storek return (1);
84757495Storek return (0);
84857495Storek }
84957495Storek
85057495Storek static char *
extend(p,name)85157495Storek extend(p, name)
85257495Storek register char *p;
85357495Storek const char *name;
85457495Storek {
85557495Storek register int l;
85657495Storek
85757495Storek l = strlen(name);
85857495Storek bcopy(name, p, l);
85957495Storek p += l;
86057495Storek *p++ = ',';
86157495Storek *p++ = ' ';
86257495Storek return (p);
86357495Storek }
86457495Storek
86557495Storek /*
86657495Storek * Check that we got all required locators, and default any that are
86757495Storek * given as "?" and have defaults. Return 0 on success.
86857495Storek */
86957495Storek static const char **
fixloc(name,attr,got)87057495Storek fixloc(name, attr, got)
87157495Storek const char *name;
87257495Storek register struct attr *attr;
87357495Storek register struct nvlist *got;
87457495Storek {
87557495Storek register struct nvlist *m, *n;
87657495Storek register int ord;
87757495Storek register const char **lp;
87857495Storek int nmissing, nextra, nnodefault;
87957495Storek char *mp, *ep, *ndp;
88057495Storek char missing[1000], extra[1000], nodefault[1000];
88157495Storek static const char *nullvec[1];
88257495Storek
88357495Storek /*
88457495Storek * Look for all required locators, and number the given ones
88557495Storek * according to the required order. While we are numbering,
88657495Storek * set default values for defaulted locators.
88757495Storek */
88857495Storek if (attr->a_loclen == 0) /* e.g., "at root" */
88957495Storek lp = nullvec;
89057495Storek else
89157495Storek lp = emalloc((attr->a_loclen + 1) * sizeof(const char *));
89257495Storek for (n = got; n != NULL; n = n->nv_next)
89357495Storek n->nv_int = -1;
89457495Storek nmissing = 0;
89557495Storek mp = missing;
89657495Storek /* yes, this is O(mn), but m and n should be small */
89757495Storek for (ord = 0, m = attr->a_locs; m != NULL; m = m->nv_next, ord++) {
89857495Storek for (n = got; n != NULL; n = n->nv_next) {
89957495Storek if (n->nv_name == m->nv_name) {
90057495Storek n->nv_int = ord;
90157495Storek break;
90257495Storek }
90357495Storek }
90457495Storek if (n == NULL && m->nv_int == 0) {
90557495Storek nmissing++;
90657495Storek mp = extend(mp, m->nv_name);
90757495Storek }
90857495Storek lp[ord] = m->nv_str;
90957495Storek }
91057495Storek if (ord != attr->a_loclen)
91157495Storek panic("fixloc");
91257495Storek lp[ord] = NULL;
91357495Storek nextra = 0;
91457495Storek ep = extra;
91557495Storek nnodefault = 0;
91657495Storek ndp = nodefault;
91757495Storek for (n = got; n != NULL; n = n->nv_next) {
91857495Storek if (n->nv_int >= 0) {
91957495Storek if (n->nv_str != NULL)
92057495Storek lp[n->nv_int] = n->nv_str;
92157495Storek else if (lp[n->nv_int] == NULL) {
92257495Storek nnodefault++;
92357495Storek ndp = extend(ndp, n->nv_name);
92457495Storek }
92557495Storek } else {
92657495Storek nextra++;
92757495Storek ep = extend(ep, n->nv_name);
92857495Storek }
92957495Storek }
93057495Storek if (nextra) {
93157495Storek ep[-2] = 0; /* kill ", " */
93257495Storek error("%s: extraneous locator%s: %s",
93357495Storek name, nextra > 1 ? "s" : "", extra);
93457495Storek }
93557495Storek if (nmissing) {
93657495Storek mp[-2] = 0;
93757495Storek error("%s: must specify %s", name, missing);
93857495Storek }
93957495Storek if (nnodefault) {
94057495Storek ndp[-2] = 0;
94157495Storek error("%s: cannot wildcard %s", name, nodefault);
94257495Storek }
94357495Storek if (nmissing || nnodefault) {
94457495Storek free(lp);
94557495Storek lp = NULL;
94657495Storek }
94757495Storek return (lp);
94857495Storek }
949