* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratories.
* %sccs.include.redist.c%
* @(#)sem.c 8.1 (Berkeley) %G%
#define NAMESIZE 100 /* local name buffers */
static const char *s_generic
;
static const char *s_qmark
;
static struct hashtab
*attrtab
; /* for attribute lookup */
static struct hashtab
*cfhashtab
; /* for config lookup */
static struct hashtab
*devitab
; /* etc */
static struct attr errattr
;
static struct devbase errdev
;
static struct devbase
**nextbase
;
static struct config
**nextcf
;
static struct devi
**nextdevi
;
static struct devi
**nextpseudo
;
static int has_errobj
__P((struct nvlist
*, void *));
static struct nvlist
*addtoattr
__P((struct nvlist
*, struct devbase
*));
static int exclude
__P((struct nvlist
*, const char *, const char *));
static int resolve
__P((struct nvlist
**, const char *, const char *,
static int lresolve
__P((struct nvlist
**, const char *, const char *,
static struct devi
*newdevi
__P((const char *, int, struct devbase
*d
));
static struct devi
*getdevi
__P((const char *));
static const char *concat
__P((const char *, int));
static int split
__P((const char *, size_t, char *, size_t, int *));
static void selectbase
__P((struct devbase
*));
static int onlist
__P((struct nvlist
*, void *));
static const char **fixloc
__P((const char *, struct attr
*, struct nvlist
*));
errattr
.a_name
= "<internal>";
errdev
.d_name
= "<internal>";
s_generic
= intern("generic");
register struct devbase
*dev
;
for (dev
= allbases
; dev
!= NULL
; dev
= dev
->d_next
) {
"%s: device `%s' used but not defined\n",
(void)fprintf(stderr
, "*** Stop.\n");
setdefmaxusers(min
, def
, max
)
if (min
< 1 || min
> def
|| def
> max
)
error("maxusers must have 1 <= min <= default <= max");
error("duplicate maxusers parameter");
error("warning: minimum of %d maxusers assumed\n", minmaxusers
);
errors
--; /* take it away */
} else if (n
> maxmaxusers
) {
error("warning: maxusers (%d) > %d", n
, maxmaxusers
);
* Define an attribute, optionally with an interface (a locator list).
* Since an empty locator list is logically different from "no interface",
* all locator lists include a dummy head node, which we discard here.
register struct nvlist
*nv
;
if (ht_insert(attrtab
, name
, a
)) {
error("attribute `%s' already defined", name
);
a
->a_locs
= locs
->nv_next
;
for (nv
= a
->a_locs
; nv
!= NULL
; nv
= nv
->nv_next
)
* Return true if the given `error object' is embedded in the given
register struct nvlist
*nv
;
for (; nv
!= NULL
; nv
= nv
->nv_next
)
* Add a device base to a list in an attribute (actually, to any list).
* Note that this does not check for duplicates, and does reverse the
* list order, but no one cares anyway.
register struct nvlist
*l
;
register struct devbase
*dev
;
register struct nvlist
*n
;
n
= newnv(NULL
, NULL
, dev
, 0);
* Device a device, giving its allowable parent attachments, if any.
* This may (or may not) also define an interface attribute and/or refer
* to existing attributes. There may be a list of vectors.
defdev(dev
, ispseudo
, atlist
, vectors
, loclist
, attrs
)
register struct devbase
*dev
;
struct nvlist
*atlist
, *vectors
, *loclist
, *attrs
;
register struct nvlist
*nv
;
error("redefinition of `%s'", dev
->d_name
);
if (has_errobj(attrs
, &errattr
))
* Handle implicit attribute definition from locator list. Do
* this before scanning the `at' list so that we can have, e.g.:
* device foo at other, foo { slot = -1 }
* (where you can plug in a foo-bus extender to a foo-bus).
loclist
= NULL
; /* defattr disposes of them for us */
if (defattr(dev
->d_name
, nv
))
nv
= newnv(dev
->d_name
, NULL
, getattr(dev
->d_name
), 0);
/* Committed! Set up fields. */
dev
->d_ispseudo
= ispseudo
;
dev
->d_vectors
= vectors
;
* Turn the `at' list into interface attributes (map each
* nv_name to an attribute, or to NULL for root), and add
* this device to those attributes, so that children can
* be listed at this particular device if they are supported
for (nv
= atlist
; nv
!= NULL
; nv
= nv
->nv_next
) {
if (nv
->nv_name
== NULL
) {
nv
->nv_ptr
= NULL
; /* at root */
nv
->nv_ptr
= a
= getattr(nv
->nv_name
);
continue; /* already complained */
error("%s cannot be at plain attribute `%s'",
a
->a_devs
= addtoattr(a
->a_devs
, dev
);
* For each interface attribute this device refers to, add this
* device to its reference list. This makes, e.g., finding all
for (nv
= attrs
; nv
!= NULL
; nv
= nv
->nv_next
) {
a
->a_refs
= addtoattr(a
->a_refs
, dev
);
* Look up a devbase. Also makes sure it is a reasonable name,
* i.e., does not end in a digit or contain special characters.
register struct devbase
*dev
;
if (!isalnum(*p
) && *p
!= '_')
error("bad device base name `%s'", name
);
dev
= ht_lookup(devbasetab
, name
);
dev
= emalloc(sizeof *dev
);
dev
->d_ipp
= &dev
->d_ihead
;
if (ht_insert(devbasetab
, name
, dev
))
panic("getdevbase(%s)", name
);
if ((a
= ht_lookup(attrtab
, name
)) == NULL
) {
error("undefined attribute `%s'", name
);
* Set the major device number for a device, so that it can be used
* as a root/swap/dumps "on" device in a configuration.
if (d
!= &errdev
&& d
->d_major
!= NODEV
)
error("device `%s' is already major %d",
#define ABS(x) ((x) < 0 ? -(x) : (x))
error("%s: swap generic must not specify %s", name
, what
);
* Map things like "ra0b" => makedev(major("ra"), 0*8 + 'b'-'a').
* Handle the case where the device number is given but there is no
* corresponding name, and map NULL to the default.
resolve(nvp
, name
, what
, dflt
, part
)
register struct nvlist
**nvp
;
register struct nvlist
*nv
;
register struct devbase
*dev
;
register int maj
, min
, l
;
if ((u_int
)(part
-= 'a') >= 7)
if ((nv
= *nvp
) == NULL
) {
* Apply default. Easiest to do this by number.
maj
= major(dflt
->nv_int
);
min
= (minor(dflt
->nv_int
) & ~7) | part
;
*nvp
= nv
= newnv(NULL
, NULL
, NULL
, makedev(maj
, min
));
if (nv
->nv_int
!= NODEV
) {
* By the numbers. Find the appropriate major number
for (dev
= allbases
; dev
!= NULL
; dev
= dev
->d_next
)
(void)sprintf(buf
, "<%d/%d>", maj
, min
);
(void)sprintf(buf
, "%s%d%c", dev
->d_name
,
min
>> 3, (min
& 7) + 'a');
nv
->nv_str
= intern(buf
);
* The normal case: things like "ra2b". Check for partition
* suffix, remove it if there, and split into name ("ra") and
if (l
> 1 && *--cp
>= 'a' && *cp
<= 'h' && isdigit(cp
[-1])) {
if (split(cp
, l
, buf
, sizeof buf
, &unit
)) {
error("%s: invalid %s device name `%s'", name
, what
, cp
);
dev
= ht_lookup(devbasetab
, intern(buf
));
if (dev
== NULL
|| dev
->d_major
== NODEV
) {
error("%s: can't make %s device from `%s'",
nv
->nv_name
= dev
->d_name
;
nv
->nv_int
= makedev(dev
->d_major
, unit
* 8 + part
);
lresolve(nvp
, name
, what
, dflt
, part
)
register struct nvlist
**nvp
;
while ((err
= resolve(nvp
, name
, what
, dflt
, part
)) == 0 &&
* Add a completed configuration to the list.
register struct config
*cf0
;
register struct config
*cf
;
register struct nvlist
*nv
;
cf
= emalloc(sizeof *cf
);
if (ht_insert(cfhashtab
, name
, cf
)) {
error("configuration `%s' already defined", name
);
* Look for "swap generic".
for (nv
= cf
->cf_swap
; nv
!= NULL
; nv
= nv
->nv_next
)
if (nv
->nv_str
== s_generic
)
* Make sure no root or dump device specified, and no
* other swap devices. Note single | here (check all).
if (exclude(cf
->cf_root
, name
, "root device") |
exclude(nv
->nv_next
, name
, "additional swap devices") |
exclude(cf
->cf_dump
, name
, "dump device"))
error("%s: no root device specified", name
);
if (resolve(&cf
->cf_root
, name
, "root", nv
, 'a') |
lresolve(&cf
->cf_swap
, name
, "swap", nv
, 'b') |
resolve(&cf
->cf_dump
, name
, "dumps", nv
, 'b'))
register struct nvlist
**npp
;
error("duplicate %s specification", what
);
i
->i_lineno
= currentline();
* Add the named device as attaching to the named attribute (or perhaps
* another device instead) plus unit number.
adddev(name
, at
, loclist
, flags
)
register struct devi
*i
; /* the new instance */
register struct attr
*attr
; /* attribute that allows attach */
register struct devbase
*ib
; /* i->i_base */
register struct devbase
*ab
; /* not NULL => at another dev */
register struct nvlist
*nv
;
if ((i
= getdevi(name
)) == NULL
)
* Must warn about i_unit > 0 later, after taking care of
* the STAR cases (we could do non-star's here but why
* bother?). Make sure this device can be at root.
if (!onlist(ib
->d_atlist
, NULL
)) {
error("%s's cannot attach to the root", ib
->d_name
);
attr
= &errattr
; /* a convenient "empty" attr */
if (split(at
, strlen(at
), atbuf
, sizeof atbuf
, &atunit
)) {
error("invalid attachment name `%s'", at
);
/* (void)getdevi(name); -- ??? */
if ((i
= getdevi(name
)) == NULL
)
if ((attr
= ht_lookup(attrtab
, cp
)) == NULL
) {
* Have to work a bit harder to see whether we have
* something like "tg0 at esp0" (where esp is merely
* not an attribute) or "tg0 at nonesuch0" (where
* nonesuch is not even a device).
if ((ab
= ht_lookup(devbasetab
, cp
)) == NULL
) {
error("%s at %s: `%s' unknown",
* See if the named parent carries an attribute
* that allows it to supervise device ib.
for (nv
= ab
->d_attrs
; nv
!= NULL
; nv
= nv
->nv_next
) {
if (onlist(attr
->a_devs
, ib
))
attr
= &errattr
;/* now onlist below will fail */
if (!onlist(attr
->a_devs
, ib
)) {
error("%s's cannot attach to %s's", ib
->d_name
, atbuf
);
if ((i
->i_locs
= fixloc(name
, attr
, loclist
)) == NULL
)
if (i
->i_unit
== STAR
&& ib
->d_vectors
!= NULL
) {
error("%s's cannot be *'d as they have preset vectors",
/* all done, fall into ... */
register struct devbase
*d
;
d
= ht_lookup(devbasetab
, name
);
error("undefined pseudo-device %s", name
);
error("%s is a real device, not a pseudo-device", name
);
if (ht_lookup(devitab
, name
) != NULL
) {
error("`%s' already defined", name
);
i
= newdevi(name
, number
- 1, d
); /* foo 16 => "foo0..foo15" */
if (ht_insert(devitab
, name
, i
))
panic("addpseudo(%s)", name
);
* Define a new instance of a specific device.
register struct devi
*i
, *firsti
;
register struct devbase
*d
;
if (split(name
, strlen(name
), base
, sizeof base
, &unit
)) {
error("invalid device name `%s'", name
);
d
= ht_lookup(devbasetab
, intern(base
));
error("%s: unknown device `%s'", name
, base
);
error("%s: %s is a pseudo-device", name
, base
);
firsti
= ht_lookup(devitab
, name
);
i
= newdevi(name
, unit
, d
);
if (ht_insert(devitab
, name
, i
))
panic("getdevi(%s)", name
);
firsti
= firsti
->i_alias
;
if (len
+ 2 > sizeof(buf
)) {
error("device name `%s%c' too long", name
, c
);
return (concat(name
, '*'));
return (concat(name
, '?'));
* Split a name like "foo0" into base name (foo) and unit number (0).
* Return 0 on success. To make this useful for names like "foo0a",
* the length of the "foo0" part is one of the arguments.
split(name
, nlen
, base
, bsize
, aunit
)
register const char *name
;
if (l
< 2 || l
>= bsize
|| isdigit(*name
))
* We have an instance of the base foo, so select it and all its
* attributes for "optional foo".
register struct devbase
*d
;
register struct nvlist
*nv
;
(void)ht_insert(selecttab
, d
->d_name
, (char *)d
->d_name
);
for (nv
= d
->d_attrs
; nv
!= NULL
; nv
= nv
->nv_next
) {
(void)ht_insert(selecttab
, a
->a_name
, (char *)a
->a_name
);
* Is the given pointer on the given list of pointers?
register struct nvlist
*nv
;
for (; nv
!= NULL
; nv
= nv
->nv_next
)
* Check that we got all required locators, and default any that are
* given as "?" and have defaults. Return 0 on success.
register struct attr
*attr
;
register struct nvlist
*got
;
register struct nvlist
*m
, *n
;
register const char **lp
;
int nmissing
, nextra
, nnodefault
;
char missing
[1000], extra
[1000], nodefault
[1000];
static const char *nullvec
[1];
* Look for all required locators, and number the given ones
* according to the required order. While we are numbering,
* set default values for defaulted locators.
if (attr
->a_loclen
== 0) /* e.g., "at root" */
lp
= emalloc((attr
->a_loclen
+ 1) * sizeof(const char *));
for (n
= got
; n
!= NULL
; n
= n
->nv_next
)
/* yes, this is O(mn), but m and n should be small */
for (ord
= 0, m
= attr
->a_locs
; m
!= NULL
; m
= m
->nv_next
, ord
++) {
for (n
= got
; n
!= NULL
; n
= n
->nv_next
) {
if (n
->nv_name
== m
->nv_name
) {
if (n
== NULL
&& m
->nv_int
== 0) {
mp
= extend(mp
, m
->nv_name
);
if (ord
!= attr
->a_loclen
)
for (n
= got
; n
!= NULL
; n
= n
->nv_next
) {
lp
[n
->nv_int
] = n
->nv_str
;
else if (lp
[n
->nv_int
] == NULL
) {
ndp
= extend(ndp
, n
->nv_name
);
ep
= extend(ep
, n
->nv_name
);
ep
[-2] = 0; /* kill ", " */
error("%s: extraneous locator%s: %s",
name
, nextra
> 1 ? "s" : "", extra
);
error("%s: must specify %s", name
, missing
);
error("%s: cannot wildcard %s", name
, nodefault
);
if (nmissing
|| nnodefault
) {