1 /* $NetBSD: sem.c,v 1.32 2009/01/20 18:20:48 drochner Exp $ */
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 * This product includes software developed by the University of
14 * California, Lawrence Berkeley Laboratories.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * from: @(#)sem.c 8.1 (Berkeley) 6/6/93
43 #if HAVE_NBTOOL_CONFIG_H
44 #include "nbtool_config.h"
47 #include <sys/param.h>
60 #define NAMESIZE 100 /* local name buffers */
62 const char *s_ifnet
; /* magic attribute */
66 static struct hashtab
*cfhashtab
; /* for config lookup */
67 struct hashtab
*devitab
; /* etc */
69 static struct attr errattr
;
70 static struct devbase errdev
;
71 static struct deva errdeva
;
73 static int has_errobj(struct nvlist
*, void *);
74 static struct nvlist
*addtoattr(struct nvlist
*, struct devbase
*);
75 static int resolve(struct nvlist
**, const char *, const char *,
76 struct nvlist
*, int);
77 static struct pspec
*getpspec(struct attr
*, struct devbase
*, int);
78 static struct devi
*newdevi(const char *, int, struct devbase
*d
);
79 static struct devi
*getdevi(const char *);
80 static void remove_devi(struct devi
*);
81 static const char *concat(const char *, int);
82 static char *extend(char *, const char *);
83 static int split(const char *, size_t, char *, size_t, int *);
84 static void selectbase(struct devbase
*, struct deva
*);
85 static const char **fixloc(const char *, struct attr
*, struct nvlist
*);
86 static const char *makedevstr(devmajor_t
, devminor_t
);
87 static const char *major2name(devmajor_t
);
88 static devmajor_t
dev2major(struct devbase
*);
90 extern const char *yyfile
;
98 errattr
.a_name
= "<internal>";
100 TAILQ_INIT(&allbases
);
102 TAILQ_INIT(&alldevas
);
104 TAILQ_INIT(&allpspecs
);
106 cfhashtab
= ht_new();
109 TAILQ_INIT(&alldevi
);
110 errdev
.d_name
= "<internal>";
112 TAILQ_INIT(&allpseudo
);
114 TAILQ_INIT(&alldevms
);
116 s_ifnet
= intern("ifnet");
117 s_qmark
= intern("?");
118 s_none
= intern("none");
121 /* Name of include file just ended (set in scan.l) */
122 extern const char *lastfile
;
129 TAILQ_FOREACH(dev
, &allbases
, d_next
) {
131 (void)fprintf(stderr
,
132 "%s: device `%s' used but not defined\n",
133 lastfile
, dev
->d_name
);
139 (void)fprintf(stderr
, "*** Stop.\n");
145 setdefmaxusers(int min
, int def
, int max
)
148 if (min
< 1 || min
> def
|| def
> max
)
149 cfgerror("maxusers must have 1 <= min (%d) <= default (%d) "
150 "<= max (%d)", min
, def
, max
);
163 cfgerror("duplicate maxusers parameter");
166 if (vflag
&& maxusers
!= 0)
167 cfgwarn("warning: maxusers already defined");
169 if (n
< minmaxusers
) {
170 cfgerror("warning: minimum of %d maxusers assumed",
172 errors
--; /* take it away */
173 maxusers
= minmaxusers
;
174 } else if (n
> maxmaxusers
) {
175 cfgerror("warning: maxusers (%d) > %d", n
, maxmaxusers
);
181 setident(const char *i
)
188 * Define an attribute, optionally with an interface (a locator list)
189 * and a set of attribute-dependencies.
191 * Attribute dependencies MAY NOT be interface attributes.
193 * Since an empty locator list is logically different from "no interface",
194 * all locator lists include a dummy head node, which we discard here.
197 defattr(const char *name
, struct nvlist
*locs
, struct nvlist
*deps
,
200 struct attr
*a
, *dep
;
204 if (locs
!= NULL
&& devclass
)
205 panic("defattr(%s): locators and devclass", name
);
207 if (deps
!= NULL
&& devclass
)
208 panic("defattr(%s): dependencies and devclass", name
);
211 * If this attribute depends on any others, make sure none of
212 * the dependencies are interface attributes.
214 for (nv
= deps
; nv
!= NULL
; nv
= nv
->nv_next
) {
217 cfgerror("`%s' dependency `%s' is an interface "
218 "attribute", name
, dep
->a_name
);
223 a
= ecalloc(1, sizeof *a
);
224 if (ht_insert(attrtab
, name
, a
)) {
226 cfgerror("attribute `%s' already defined", name
);
234 a
->a_locs
= locs
->nv_next
;
241 char classenum
[256], *cp
;
244 (void)snprintf(classenum
, sizeof(classenum
), "DV_%s", name
);
245 for (cp
= classenum
+ 3; *cp
; cp
++) {
247 (!isalnum((unsigned char)*cp
) ||
248 (isalpha((unsigned char)*cp
) && !islower((unsigned char)*cp
)))) {
249 cfgerror("device class names must be "
250 "lower-case alphanumeric characters");
253 *cp
= toupper((unsigned char)*cp
);
255 a
->a_devclass
= intern(classenum
);
257 a
->a_devclass
= NULL
;
259 for (nv
= a
->a_locs
; nv
!= NULL
; nv
= nv
->nv_next
)
267 /* Expand the attribute to check for cycles in the graph. */
274 * Return true if the given `error object' is embedded in the given
278 has_errobj(struct nvlist
*nv
, void *obj
)
281 for (; nv
!= NULL
; nv
= nv
->nv_next
)
282 if (nv
->nv_ptr
== obj
)
288 * Return true if the given attribute is embedded in the given
292 has_attr(struct nvlist
*nv
, const char *attr
)
296 if ((a
= getattr(attr
)) == NULL
)
299 for (; nv
!= NULL
; nv
= nv
->nv_next
)
306 * Add a device base to a list in an attribute (actually, to any list).
307 * Note that this does not check for duplicates, and does reverse the
308 * list order, but no one cares anyway.
310 static struct nvlist
*
311 addtoattr(struct nvlist
*l
, struct devbase
*dev
)
315 n
= newnv(NULL
, NULL
, dev
, 0, l
);
320 * Define a device. This may (or may not) also define an interface
321 * attribute and/or refer to existing attributes.
324 defdev(struct devbase
*dev
, struct nvlist
*loclist
, struct nvlist
*attrs
,
333 cfgerror("redefinition of `%s'", dev
->d_name
);
338 if (has_errobj(attrs
, &errattr
))
342 * Handle implicit attribute definition from locator list. Do
343 * this before scanning the `at' list so that we can have, e.g.:
344 * device foo at other, foo { slot = -1 }
345 * (where you can plug in a foo-bus extender to a foo-bus).
347 if (loclist
!= NULL
) {
349 loclist
= NULL
; /* defattr disposes of them for us */
350 if (defattr(dev
->d_name
, nv
, NULL
, 0))
352 attrs
= newnv(dev
->d_name
, NULL
, getattr(dev
->d_name
), 0,
358 * Pseudo-devices can have children. Consider them as
362 for (nv
= attrs
; nv
!= NULL
; nv
= nv
->nv_next
)
363 if (((struct attr
*)(nv
->nv_ptr
))->a_iattr
)
367 if (version
>= 20080610)
368 cfgerror("interface attribute on "
369 "non-device pseudo `%s'", dev
->d_name
);
374 ht_insert(devroottab
, dev
->d_name
, dev
);
378 /* Committed! Set up fields. */
379 dev
->d_ispseudo
= ispseudo
;
380 dev
->d_attrs
= attrs
;
381 dev
->d_classattr
= NULL
; /* for now */
384 * For each interface attribute this device refers to, add this
385 * device to its reference list. This makes, e.g., finding all
388 * While looking through the attributes, set up the device
389 * class if any are devclass attributes (and error out if the
390 * device has two classes).
392 for (nv
= attrs
; nv
!= NULL
; nv
= nv
->nv_next
) {
395 a
->a_refs
= addtoattr(a
->a_refs
, dev
);
396 if (a
->a_devclass
!= NULL
) {
397 if (dev
->d_classattr
!= NULL
) {
398 cfgerror("device `%s' has multiple classes "
400 dev
->d_name
, dev
->d_classattr
->a_name
,
403 dev
->d_classattr
= a
;
413 * Look up a devbase. Also makes sure it is a reasonable name,
414 * i.e., does not end in a digit or contain special characters.
417 getdevbase(const char *name
)
422 p
= (const u_char
*)name
;
426 if (!isalnum(*p
) && *p
!= '_')
431 cfgerror("bad device base name `%s'", name
);
434 dev
= ht_lookup(devbasetab
, name
);
436 dev
= ecalloc(1, sizeof *dev
);
439 dev
->d_major
= NODEVMAJOR
;
442 dev
->d_ipp
= &dev
->d_ihead
;
444 dev
->d_app
= &dev
->d_ahead
;
446 TAILQ_INSERT_TAIL(&allbases
, dev
, d_next
);
447 if (ht_insert(devbasetab
, name
, dev
))
448 panic("getdevbase(%s)", name
);
454 * Define some of a device's allowable parent attachments.
455 * There may be a list of (plain) attributes.
458 defdevattach(struct deva
*deva
, struct devbase
*dev
, struct nvlist
*atlist
,
459 struct nvlist
*attrs
)
468 deva
= getdevattach(dev
->d_name
);
469 if (deva
== &errdeva
)
472 cfgerror("attaching undefined device `%s'", dev
->d_name
);
476 cfgerror("redefinition of `%s'", deva
->d_name
);
479 if (dev
->d_ispseudo
) {
480 cfgerror("pseudo-devices can't attach");
485 if (has_errobj(attrs
, &errattr
))
487 for (nv
= attrs
; nv
!= NULL
; nv
= nv
->nv_next
) {
490 continue; /* already complained */
491 if (a
->a_iattr
|| a
->a_devclass
!= NULL
)
492 cfgerror("`%s' is not a plain attribute", a
->a_name
);
495 /* Committed! Set up fields. */
496 deva
->d_attrs
= attrs
;
497 deva
->d_atlist
= atlist
;
498 deva
->d_devbase
= dev
;
501 * Turn the `at' list into interface attributes (map each
502 * nv_name to an attribute, or to NULL for root), and add
503 * this device to those attributes, so that children can
504 * be listed at this particular device if they are supported
507 for (nv
= atlist
; nv
!= NULL
; nv
= nv
->nv_next
) {
508 if (nv
->nv_name
== NULL
)
509 nv
->nv_ptr
= a
= NULL
; /* at root */
511 nv
->nv_ptr
= a
= getattr(nv
->nv_name
);
513 continue; /* already complained */
516 * Make sure that an attachment spec doesn't
517 * already say how to attach to this attribute.
519 for (da
= dev
->d_ahead
; da
!= NULL
; da
= da
->d_bsame
)
520 if (onlist(da
->d_atlist
, a
))
521 cfgerror("attach at `%s' already done by `%s'",
522 a
? a
->a_name
: "root", da
->d_name
);
525 ht_insert(devroottab
, dev
->d_name
, dev
);
526 continue; /* at root; don't add */
529 cfgerror("%s cannot be at plain attribute `%s'",
530 dev
->d_name
, a
->a_name
);
532 a
->a_devs
= addtoattr(a
->a_devs
, dev
);
535 /* attach to parent */
537 dev
->d_app
= &deva
->d_bsame
;
545 * Look up a device attachment. Also makes sure it is a reasonable
546 * name, i.e., does not contain digits or special characters.
549 getdevattach(const char *name
)
554 p
= (const u_char
*)name
;
558 if (!isalnum(*p
) && *p
!= '_')
563 cfgerror("bad device attachment name `%s'", name
);
566 deva
= ht_lookup(devatab
, name
);
568 deva
= ecalloc(1, sizeof *deva
);
570 deva
->d_bsame
= NULL
;
572 deva
->d_devbase
= NULL
;
573 deva
->d_atlist
= NULL
;
574 deva
->d_attrs
= NULL
;
575 deva
->d_ihead
= NULL
;
576 deva
->d_ipp
= &deva
->d_ihead
;
577 TAILQ_INSERT_TAIL(&alldevas
, deva
, d_next
);
578 if (ht_insert(devatab
, name
, deva
))
579 panic("getdeva(%s)", name
);
585 * Look up an attribute.
588 getattr(const char *name
)
592 if ((a
= ht_lookup(attrtab
, name
)) == NULL
) {
593 cfgerror("undefined attribute `%s'", name
);
600 * Recursively expand an attribute and its dependencies, checking for
601 * cycles, and invoking a callback for each attribute found.
604 expandattr(struct attr
*a
, void (*callback
)(struct attr
*))
609 if (a
->a_expanding
) {
610 cfgerror("circular dependency on attribute `%s'", a
->a_name
);
616 /* First expand all of this attribute's dependencies. */
617 for (nv
= a
->a_deps
; nv
!= NULL
; nv
= nv
->nv_next
) {
619 expandattr(dep
, callback
);
622 /* ...and now invoke the callback for ourself. */
623 if (callback
!= NULL
)
630 * Set the major device number for a device, so that it can be used
631 * as a root/dumps "on" device in a configuration.
634 setmajor(struct devbase
*d
, devmajor_t n
)
637 if (d
!= &errdev
&& d
->d_major
!= NODEVMAJOR
)
638 cfgerror("device `%s' is already major %d",
639 d
->d_name
, d
->d_major
);
645 major2name(devmajor_t maj
)
651 TAILQ_FOREACH(dev
, &allbases
, d_next
) {
652 if (dev
->d_major
== maj
)
653 return (dev
->d_name
);
656 TAILQ_FOREACH(dm
, &alldevms
, dm_next
) {
657 if (dm
->dm_bmajor
== maj
)
658 return (dm
->dm_name
);
665 dev2major(struct devbase
*dev
)
670 return (dev
->d_major
);
672 TAILQ_FOREACH(dm
, &alldevms
, dm_next
) {
673 if (strcmp(dm
->dm_name
, dev
->d_name
) == 0)
674 return (dm
->dm_bmajor
);
680 * Make a string description of the device at maj/min.
683 makedevstr(devmajor_t maj
, devminor_t min
)
685 const char *devicename
;
688 devicename
= major2name(maj
);
689 if (devicename
== NULL
)
690 (void)snprintf(buf
, sizeof(buf
), "<%d/%d>", maj
, min
);
692 (void)snprintf(buf
, sizeof(buf
), "%s%d%c", devicename
,
693 min
/ maxpartitions
, (min
% maxpartitions
) + 'a');
695 return (intern(buf
));
699 * Map things like "ra0b" => makedev(major("ra"), 0*maxpartitions + 'b'-'a').
700 * Handle the case where the device number is given but there is no
701 * corresponding name, and map NULL to the default.
704 resolve(struct nvlist
**nvp
, const char *name
, const char *what
,
705 struct nvlist
*dflt
, int part
)
716 if ((part
-= 'a') >= maxpartitions
|| part
< 0)
718 if ((nv
= *nvp
) == NULL
) {
721 * Apply default. Easiest to do this by number.
722 * Make sure to retain NODEVness, if this is dflt's disposition.
724 if ((dev_t
)dflt
->nv_num
!= NODEV
) {
725 maj
= major(dflt
->nv_num
);
726 min
= ((minor(dflt
->nv_num
) / maxpartitions
) *
727 maxpartitions
) + part
;
728 d
= makedev(maj
, min
);
729 cp
= makedevstr(maj
, min
);
732 *nvp
= nv
= newnv(NULL
, cp
, NULL
, d
, NULL
);
734 if ((dev_t
)nv
->nv_num
!= NODEV
) {
736 * By the numbers. Find the appropriate major number
739 maj
= major(nv
->nv_num
);
740 min
= minor(nv
->nv_num
);
741 nv
->nv_str
= makedevstr(maj
, min
);
745 if (nv
->nv_str
== NULL
|| nv
->nv_str
== s_qmark
)
747 * Wildcarded or unspecified; leave it as NODEV.
752 * The normal case: things like "ra2b". Check for partition
753 * suffix, remove it if there, and split into name ("ra") and
756 l
= i
= strlen(nv
->nv_str
);
758 if (l
> 1 && *--cp
>= 'a' && *cp
< 'a' + maxpartitions
&&
759 isdigit((unsigned char)cp
[-1])) {
764 if (split(cp
, l
, buf
, sizeof buf
, &unit
)) {
765 cfgerror("%s: invalid %s device name `%s'", name
, what
, cp
);
768 dev
= ht_lookup(devbasetab
, intern(buf
));
770 cfgerror("%s: device `%s' does not exist", name
, buf
);
775 * Check for the magic network interface attribute, and
776 * don't bother making a device number.
778 if (has_attr(dev
->d_attrs
, s_ifnet
)) {
780 nv
->nv_ifunit
= unit
; /* XXX XXX XXX */
782 maj
= dev2major(dev
);
783 if (maj
== NODEVMAJOR
) {
784 cfgerror("%s: can't make %s device from `%s'",
785 name
, what
, nv
->nv_str
);
788 nv
->nv_num
= makedev(maj
, unit
* maxpartitions
+ part
);
791 nv
->nv_name
= dev
->d_name
;
796 * Add a completed configuration to the list.
799 addconf(struct config
*cf0
)
805 cf
= ecalloc(1, sizeof *cf
);
806 if (ht_insert(cfhashtab
, name
, cf
)) {
807 cfgerror("configuration `%s' already defined", name
);
814 * Resolve the root device.
816 if (cf
->cf_root
== NULL
) {
817 cfgerror("%s: no root device specified", name
);
820 if (cf
->cf_root
&& cf
->cf_root
->nv_str
!= s_qmark
) {
823 if (resolve(&cf
->cf_root
, name
, "root", nv
, 'a'))
828 * Resolve the dump device.
830 if (cf
->cf_dump
== NULL
|| cf
->cf_dump
->nv_str
== s_qmark
) {
832 * Wildcarded dump device is equivalent to unspecified.
835 } else if (cf
->cf_dump
->nv_str
== s_none
) {
837 * Operator has requested that no dump device should be
838 * configured; do nothing.
841 if (resolve(&cf
->cf_dump
, name
, "dumps", cf
->cf_dump
, 'b'))
845 /* Wildcarded fstype is `unspecified'. */
846 if (cf
->cf_fstype
== s_qmark
)
847 cf
->cf_fstype
= NULL
;
849 TAILQ_INSERT_TAIL(&allcf
, cf
, cf_next
);
852 nvfreel(cf0
->cf_root
);
853 nvfreel(cf0
->cf_dump
);
857 setconf(struct nvlist
**npp
, const char *what
, struct nvlist
*v
)
861 cfgerror("duplicate %s specification", what
);
868 delconf(const char *name
)
872 if (ht_lookup(cfhashtab
, name
) == NULL
) {
873 cfgerror("configuration `%s' undefined", name
);
876 (void)ht_remove(cfhashtab
, name
);
878 TAILQ_FOREACH(cf
, &allcf
, cf_next
)
879 if (!strcmp(cf
->cf_name
, name
))
882 panic("lost configuration `%s'", name
);
884 TAILQ_REMOVE(&allcf
, cf
, cf_next
);
888 setfstype(const char **fstp
, const char *v
)
892 cfgerror("multiple fstype specifications");
896 if (v
!= s_qmark
&& OPT_FSOPT(v
)) {
897 cfgerror("\"%s\" is not a configured file system", v
);
905 newdevi(const char *name
, int unit
, struct devbase
*d
)
909 i
= ecalloc(1, sizeof *i
);
921 i
->i_lineno
= currentline();
922 i
->i_srcfile
= yyfile
;
923 i
->i_active
= DEVI_ORPHAN
; /* Proper analysis comes later */
924 i
->i_level
= devilevel
;
925 if (unit
>= d
->d_umax
)
926 d
->d_umax
= unit
+ 1;
931 * Add the named device as attaching to the named attribute (or perhaps
932 * another device instead) plus unit number.
935 adddev(const char *name
, const char *at
, struct nvlist
*loclist
, int flags
)
937 struct devi
*i
; /* the new instance */
938 struct pspec
*p
; /* and its pspec */
939 struct attr
*attr
; /* attribute that allows attach */
940 struct devbase
*ib
; /* i->i_base */
941 struct devbase
*ab
; /* not NULL => at another dev */
943 struct deva
*iba
; /* devbase attachment used */
946 char atbuf
[NAMESIZE
];
954 if ((i
= getdevi(name
)) == NULL
)
957 * Must warn about i_unit > 0 later, after taking care of
958 * the STAR cases (we could do non-star's here but why
959 * bother?). Make sure this device can be at root.
963 for (iba
= ib
->d_ahead
; iba
!= NULL
; iba
= iba
->d_bsame
)
964 if (onlist(iba
->d_atlist
, NULL
)) {
969 cfgerror("`%s' cannot attach to the root", ib
->d_name
);
970 i
->i_active
= DEVI_BROKEN
;
973 attr
= &errattr
; /* a convenient "empty" attr */
975 if (split(at
, strlen(at
), atbuf
, sizeof atbuf
, &atunit
)) {
976 cfgerror("invalid attachment name `%s'", at
);
977 /* (void)getdevi(name); -- ??? */
980 if ((i
= getdevi(name
)) == NULL
)
985 * Devices can attach to two types of things: Attributes,
986 * and other devices (which have the appropriate attributes
987 * to allow attachment).
989 * (1) If we're attached to an attribute, then we don't need
990 * look at the parent base device to see what attributes
991 * it has, and make sure that we can attach to them.
993 * (2) If we're attached to a real device (i.e. named in
994 * the config file), we want to remember that so that
995 * at cross-check time, if the device we're attached to
996 * is missing but other devices which also provide the
997 * attribute are present, we don't get a false "OK."
999 * (3) If the thing we're attached to is an attribute
1000 * but is actually named in the config file, we still
1001 * have to remember its devbase.
1005 /* Figure out parent's devbase, to satisfy case (3). */
1006 ab
= ht_lookup(devbasetab
, cp
);
1008 /* Find out if it's an attribute. */
1009 attr
= ht_lookup(attrtab
, cp
);
1011 /* Make sure we're _really_ attached to the attr. Case (1). */
1012 if (attr
!= NULL
&& onlist(attr
->a_devs
, ib
))
1013 goto findattachment
;
1016 * Else a real device, and not just an attribute. Case (2).
1018 * Have to work a bit harder to see whether we have
1019 * something like "tg0 at esp0" (where esp is merely
1020 * not an attribute) or "tg0 at nonesuch0" (where
1021 * nonesuch is not even a device).
1024 cfgerror("%s at %s: `%s' unknown",
1026 i
->i_active
= DEVI_BROKEN
;
1031 * See if the named parent carries an attribute
1032 * that allows it to supervise device ib.
1034 for (nv
= ab
->d_attrs
; nv
!= NULL
; nv
= nv
->nv_next
) {
1036 if (onlist(attr
->a_devs
, ib
))
1037 goto findattachment
;
1039 cfgerror("`%s' cannot attach to `%s'", ib
->d_name
, atbuf
);
1040 i
->i_active
= DEVI_BROKEN
;
1045 * Find the parent spec. If a matching one has not yet been
1046 * created, create one.
1048 p
= getpspec(attr
, ab
, atunit
);
1049 p
->p_devs
= newnv(NULL
, NULL
, i
, 0, p
->p_devs
);
1051 /* find out which attachment it uses */
1053 for (iba
= ib
->d_ahead
; iba
!= NULL
; iba
= iba
->d_bsame
)
1054 if (onlist(iba
->d_atlist
, attr
)) {
1059 panic("adddev: can't figure out attachment");
1061 if ((i
->i_locs
= fixloc(name
, attr
, loclist
)) == NULL
) {
1062 i
->i_active
= DEVI_BROKEN
;
1068 i
->i_cfflags
= flags
;
1071 iba
->d_ipp
= &i
->i_asame
;
1073 /* all done, fall into ... */
1080 deldevi(const char *name
, const char *at
)
1082 struct devi
*firsti
, *i
;
1085 char base
[NAMESIZE
];
1087 if (split(name
, strlen(name
), base
, sizeof base
, &unit
)) {
1088 cfgerror("invalid device name `%s'", name
);
1091 d
= ht_lookup(devbasetab
, intern(base
));
1093 cfgerror("%s: unknown device `%s'", name
, base
);
1096 if (d
->d_ispseudo
) {
1097 cfgerror("%s: %s is a pseudo-device", name
, base
);
1100 if ((firsti
= ht_lookup(devitab
, name
)) == NULL
) {
1101 cfgerror("`%s' not defined", name
);
1104 if (at
== NULL
&& firsti
->i_at
== NULL
) {
1106 remove_devi(firsti
);
1108 } else if (at
!= NULL
)
1109 for (i
= firsti
; i
!= NULL
; i
= i
->i_alias
)
1110 if (i
->i_active
!= DEVI_BROKEN
&&
1111 strcmp(at
, i
->i_at
) == 0) {
1115 cfgerror("`%s' at `%s' not found", name
, at
? at
: "root");
1119 remove_devi(struct devi
*i
)
1121 struct devbase
*d
= i
->i_base
;
1122 struct devi
*f
, *j
, **ppi
;
1125 f
= ht_lookup(devitab
, i
->i_name
);
1127 panic("remove_devi(): instance %s disappeared from devitab",
1130 if (i
->i_active
== DEVI_BROKEN
) {
1131 cfgerror("not removing broken instance `%s'", i
->i_name
);
1136 * We have the device instance, i.
1138 * - delete the alias
1140 * If the devi was an alias of an already listed devi, all is
1141 * good we don't have to do more.
1142 * If it was the first alias, we have to replace i's entry in
1143 * d's list by its first alias.
1144 * If it was the only entry, we must remove i's entry from d's
1148 for (j
= f
; j
->i_alias
!= i
; j
= j
->i_alias
);
1149 j
->i_alias
= i
->i_alias
;
1151 if (i
->i_alias
== NULL
) {
1152 /* No alias, must unlink the entry from devitab */
1153 ht_remove(devitab
, i
->i_name
);
1156 /* Or have the first alias replace i in d's list */
1157 i
->i_alias
->i_bsame
= i
->i_bsame
;
1160 ht_replace(devitab
, i
->i_name
, i
->i_alias
);
1164 * - remove/replace the instance from the devbase's list
1166 * A double-linked list would make this much easier. Oh, well,
1167 * what is done is done.
1169 for (ppi
= &d
->d_ihead
;
1170 *ppi
!= NULL
&& *ppi
!= i
&& (*ppi
)->i_bsame
!= i
;
1171 ppi
= &(*ppi
)->i_bsame
);
1173 panic("deldev: dev (%s) doesn't list the devi"
1174 " (%s at %s)", d
->d_name
, i
->i_name
, i
->i_at
);
1177 /* That implies d->d_ihead == i */
1180 (*ppi
)->i_bsame
= j
;
1181 if (d
->d_ipp
== &i
->i_bsame
) {
1182 if (i
->i_alias
== NULL
) {
1184 d
->d_ipp
= &d
->d_ihead
;
1186 d
->d_ipp
= &f
->i_bsame
;
1188 d
->d_ipp
= &i
->i_alias
->i_bsame
;
1192 * - delete the attachment instance
1195 for (ppi
= &iba
->d_ihead
;
1196 *ppi
!= NULL
&& *ppi
!= i
&& (*ppi
)->i_asame
!= i
;
1197 ppi
= &(*ppi
)->i_asame
);
1199 panic("deldev: deva (%s) doesn't list the devi (%s)",
1200 iba
->d_name
, i
->i_name
);
1203 /* That implies iba->d_ihead == i */
1206 (*ppi
)->i_asame
= i
->i_asame
;
1207 if (iba
->d_ipp
== &i
->i_asame
) {
1209 iba
->d_ipp
= &iba
->d_ihead
;
1211 iba
->d_ipp
= &f
->i_asame
;
1214 * - delete the pspec
1217 struct pspec
*p
= i
->i_pspec
;
1218 struct nvlist
*nv
, *onv
;
1220 /* Double-linked nvlist anyone? */
1221 for (nv
= p
->p_devs
; nv
->nv_next
!= NULL
; nv
= nv
->nv_next
) {
1222 if (nv
->nv_next
&& nv
->nv_next
->nv_ptr
== i
) {
1224 nv
->nv_next
= onv
->nv_next
;
1228 if (nv
->nv_ptr
== i
) {
1229 /* nv is p->p_devs in that case */
1230 p
->p_devs
= nv
->nv_next
;
1235 if (p
->p_devs
== NULL
)
1236 TAILQ_REMOVE(&allpspecs
, p
, p_list
);
1239 * - delete the alldevi entry
1241 TAILQ_REMOVE(&alldevi
, i
, i_next
);
1244 * Put it in deaddevitab
1246 * Each time a devi is removed, devilevel is increased so that later on
1247 * it is possible to tell if an instance was added before or after the
1248 * removal of its parent.
1250 * For active instances, i_level contains the number of devi removed so
1251 * far, and for dead devis, it contains its index.
1253 i
->i_level
= devilevel
++;
1255 f
= ht_lookup(deaddevitab
, i
->i_name
);
1257 if (ht_insert(deaddevitab
, i
->i_name
, i
))
1258 panic("remove_devi(%s) - can't add to deaddevitab",
1261 for (j
= f
; j
->i_alias
!= NULL
; j
= j
->i_alias
);
1265 * - reconstruct d->d_umax
1268 for (i
= d
->d_ihead
; i
!= NULL
; i
= i
->i_bsame
)
1269 if (i
->i_unit
>= d
->d_umax
)
1270 d
->d_umax
= i
->i_unit
+ 1;
1274 deldeva(const char *at
)
1278 struct devbase
*d
, *ad
;
1282 struct nvlist
*nv
, *stack
= NULL
;
1285 TAILQ_FOREACH(i
, &alldevi
, i_next
)
1286 if (i
->i_at
== NULL
)
1287 stack
= newnv(NULL
, NULL
, i
, 0, stack
);
1292 if (at
[l
] == '?' || isdigit((unsigned char)at
[l
])) {
1293 char base
[NAMESIZE
];
1295 if (split(at
, l
+1, base
, sizeof base
, &unit
)) {
1296 cfgerror("invalid attachment name `%s'", at
);
1305 ad
= ht_lookup(devbasetab
, cp
);
1306 a
= ht_lookup(attrtab
, cp
);
1308 cfgerror("unknown attachment attribute or device `%s'",
1313 cfgerror("plain attribute `%s' cannot have children",
1319 * remove_devi() makes changes to the devbase's list and the
1320 * alias list, * so the actual deletion of the instances must
1323 for (nv
= a
->a_devs
; nv
!= NULL
; nv
= nv
->nv_next
) {
1325 for (i
= d
->d_ihead
; i
!= NULL
; i
= i
->i_bsame
)
1326 for (j
= i
; j
!= NULL
; j
= j
->i_alias
) {
1327 /* Ignore devices at root */
1328 if (j
->i_at
== NULL
)
1332 * There are three cases:
1334 * 1. unit is not STAR. Consider 'at'
1335 * to be explicit, even if it
1336 * references an interface
1339 * 2. unit is STAR and 'at' references
1340 * a real device. Look for pspec
1341 * that have a matching p_atdev
1344 * 3. unit is STAR and 'at' references
1345 * an interface attribute. Look
1346 * for pspec that have a matching
1349 if ((unit
!= STAR
&& /* Case */
1350 !strcmp(j
->i_at
, at
)) || /* 1 */
1352 ((ad
!= NULL
&& /* Case */
1353 p
->p_atdev
== ad
) || /* 2 */
1354 (ad
== NULL
&& /* Case */
1355 p
->p_iattr
== a
)))) /* 3 */
1356 stack
= newnv(NULL
, NULL
, j
, 0,
1362 for (nv
= stack
; nv
!= NULL
; nv
= nv
->nv_next
)
1363 remove_devi(nv
->nv_ptr
);
1368 deldev(const char *name
)
1371 struct devi
*firsti
, *i
;
1372 struct nvlist
*nv
, *stack
= NULL
;
1374 l
= strlen(name
) - 1;
1375 if (name
[l
] == '*' || isdigit((unsigned char)name
[l
])) {
1376 /* `no mydev0' or `no mydev*' */
1377 firsti
= ht_lookup(devitab
, name
);
1378 if (firsti
== NULL
) {
1379 cfgerror("unknown instance %s", name
);
1382 for (i
= firsti
; i
!= NULL
; i
= i
->i_alias
)
1383 stack
= newnv(NULL
, NULL
, i
, 0, stack
);
1385 struct devbase
*d
= ht_lookup(devbasetab
, name
);
1388 cfgerror("unknown device %s", name
);
1391 if (d
->d_ispseudo
) {
1392 cfgerror("%s is a pseudo-device; "
1393 "use \"no pseudo-device %s\" instead", name
,
1398 for (firsti
= d
->d_ihead
; firsti
!= NULL
;
1399 firsti
= firsti
->i_bsame
)
1400 for (i
= firsti
; i
!= NULL
; i
= i
->i_alias
)
1401 stack
= newnv(NULL
, NULL
, i
, 0, stack
);
1404 for (nv
= stack
; nv
!= NULL
; nv
= nv
->nv_next
)
1405 remove_devi(nv
->nv_ptr
);
1410 addpseudo(const char *name
, int number
)
1415 d
= ht_lookup(devbasetab
, name
);
1417 cfgerror("undefined pseudo-device %s", name
);
1420 if (!d
->d_ispseudo
) {
1421 cfgerror("%s is a real device, not a pseudo-device", name
);
1424 if (ht_lookup(devitab
, name
) != NULL
) {
1425 cfgerror("`%s' already defined", name
);
1428 i
= newdevi(name
, number
- 1, d
); /* foo 16 => "foo0..foo15" */
1429 if (ht_insert(devitab
, name
, i
))
1430 panic("addpseudo(%s)", name
);
1431 /* Useful to retrieve the instance from the devbase */
1433 i
->i_active
= DEVI_ACTIVE
;
1434 TAILQ_INSERT_TAIL(&allpseudo
, i
, i_next
);
1438 delpseudo(const char *name
)
1443 d
= ht_lookup(devbasetab
, name
);
1445 cfgerror("undefined pseudo-device %s", name
);
1448 if (!d
->d_ispseudo
) {
1449 cfgerror("%s is a real device, not a pseudo-device", name
);
1452 if ((i
= ht_lookup(devitab
, name
)) == NULL
) {
1453 cfgerror("`%s' not defined", name
);
1456 d
->d_umax
= 0; /* clear neads-count entries */
1457 d
->d_ihead
= NULL
; /* make sure it won't be considered active */
1458 TAILQ_REMOVE(&allpseudo
, i
, i_next
);
1459 if (ht_remove(devitab
, name
))
1460 panic("delpseudo(%s) - can't remove from devitab", name
);
1461 if (ht_insert(deaddevitab
, name
, i
))
1462 panic("delpseudo(%s) - can't add to deaddevitab", name
);
1466 adddevm(const char *name
, devmajor_t cmajor
, devmajor_t bmajor
,
1471 if (cmajor
!= NODEVMAJOR
&& (cmajor
< 0 || cmajor
>= 4096)) {
1472 cfgerror("character major %d is invalid", cmajor
);
1477 if (bmajor
!= NODEVMAJOR
&& (bmajor
< 0 || bmajor
>= 4096)) {
1478 cfgerror("block major %d is invalid", bmajor
);
1482 if (cmajor
== NODEVMAJOR
&& bmajor
== NODEVMAJOR
) {
1483 cfgerror("both character/block majors are not specified");
1488 dm
= ecalloc(1, sizeof(*dm
));
1489 dm
->dm_srcfile
= yyfile
;
1490 dm
->dm_srcline
= currentline();
1492 dm
->dm_cmajor
= cmajor
;
1493 dm
->dm_bmajor
= bmajor
;
1496 TAILQ_INSERT_TAIL(&alldevms
, dm
, dm_next
);
1498 maxcdevm
= MAX(maxcdevm
, dm
->dm_cmajor
);
1499 maxbdevm
= MAX(maxbdevm
, dm
->dm_bmajor
);
1508 TAILQ_FOREACH(i
, &alldevi
, i_next
)
1509 if (i
->i_active
== DEVI_ACTIVE
)
1510 selectbase(i
->i_base
, i
->i_atdeva
);
1511 else if (i
->i_active
== DEVI_ORPHAN
) {
1513 * At this point, we can't have instances for which
1514 * i_at or i_pspec are NULL.
1517 cfgxerror(i
->i_srcfile
, i
->i_lineno
,
1518 "`%s at %s' is orphaned (%s `%s' found)",
1519 i
->i_name
, i
->i_at
, i
->i_pspec
->p_atunit
== WILD
?
1520 "nothing matching" : "no", i
->i_at
);
1521 } else if (vflag
&& i
->i_active
== DEVI_IGNORED
)
1522 cfgxwarn(i
->i_srcfile
, i
->i_lineno
, "ignoring "
1523 "explicitly orphaned instance `%s at %s'",
1524 i
->i_name
, i
->i_at
);
1529 TAILQ_FOREACH(i
, &allpseudo
, i_next
)
1530 if (i
->i_active
== DEVI_ACTIVE
)
1531 selectbase(i
->i_base
, NULL
);
1536 * Look up a parent spec, creating a new one if it does not exist.
1538 static struct pspec
*
1539 getpspec(struct attr
*attr
, struct devbase
*ab
, int atunit
)
1543 TAILQ_FOREACH(p
, &allpspecs
, p_list
) {
1544 if (p
->p_iattr
== attr
&&
1546 p
->p_atunit
== atunit
)
1550 p
= ecalloc(1, sizeof(*p
));
1554 p
->p_atunit
= atunit
;
1555 p
->p_inst
= npspecs
++;
1558 TAILQ_INSERT_TAIL(&allpspecs
, p
, p_list
);
1564 * Define a new instance of a specific device.
1566 static struct devi
*
1567 getdevi(const char *name
)
1569 struct devi
*i
, *firsti
;
1572 char base
[NAMESIZE
];
1574 if (split(name
, strlen(name
), base
, sizeof base
, &unit
)) {
1575 cfgerror("invalid device name `%s'", name
);
1578 d
= ht_lookup(devbasetab
, intern(base
));
1580 cfgerror("%s: unknown device `%s'", name
, base
);
1583 if (d
->d_ispseudo
) {
1584 cfgerror("%s: %s is a pseudo-device", name
, base
);
1587 firsti
= ht_lookup(devitab
, name
);
1588 i
= newdevi(name
, unit
, d
);
1589 if (firsti
== NULL
) {
1590 if (ht_insert(devitab
, name
, i
))
1591 panic("getdevi(%s)", name
);
1593 d
->d_ipp
= &i
->i_bsame
;
1595 while (firsti
->i_alias
)
1596 firsti
= firsti
->i_alias
;
1597 firsti
->i_alias
= i
;
1599 TAILQ_INSERT_TAIL(&alldevi
, i
, i_next
);
1605 concat(const char *name
, int c
)
1611 if (len
+ 2 > sizeof(buf
)) {
1612 cfgerror("device name `%s%c' too long", name
, c
);
1613 len
= sizeof(buf
) - 2;
1615 memmove(buf
, name
, len
);
1618 return (intern(buf
));
1622 starref(const char *name
)
1625 return (concat(name
, '*'));
1629 wildref(const char *name
)
1632 return (concat(name
, '?'));
1636 * Split a name like "foo0" into base name (foo) and unit number (0).
1637 * Return 0 on success. To make this useful for names like "foo0a",
1638 * the length of the "foo0" part is one of the arguments.
1641 split(const char *name
, size_t nlen
, char *base
, size_t bsize
, int *aunit
)
1648 if (l
< 2 || l
>= bsize
|| isdigit((unsigned char)*name
))
1650 c
= (u_char
)name
[--l
];
1660 while (isdigit((unsigned char)cp
[-1]))
1664 memmove(base
, name
, l
);
1670 selectattr(struct attr
*a
)
1673 (void)ht_insert(selecttab
, a
->a_name
, __UNCONST(a
->a_name
));
1677 * We have an instance of the base foo, so select it and all its
1678 * attributes for "optional foo".
1681 selectbase(struct devbase
*d
, struct deva
*da
)
1686 (void)ht_insert(selecttab
, d
->d_name
, __UNCONST(d
->d_name
));
1687 for (nv
= d
->d_attrs
; nv
!= NULL
; nv
= nv
->nv_next
) {
1689 expandattr(a
, selectattr
);
1692 (void)ht_insert(selecttab
, da
->d_name
, __UNCONST(da
->d_name
));
1693 for (nv
= da
->d_attrs
; nv
!= NULL
; nv
= nv
->nv_next
) {
1695 expandattr(a
, selectattr
);
1701 * Is the given pointer on the given list of pointers?
1704 onlist(struct nvlist
*nv
, void *ptr
)
1706 for (; nv
!= NULL
; nv
= nv
->nv_next
)
1707 if (nv
->nv_ptr
== ptr
)
1713 extend(char *p
, const char *name
)
1718 memmove(p
, name
, l
);
1726 * Check that we got all required locators, and default any that are
1727 * given as "?" and have defaults. Return 0 on success.
1729 static const char **
1730 fixloc(const char *name
, struct attr
*attr
, struct nvlist
*got
)
1732 struct nvlist
*m
, *n
;
1735 int nmissing
, nextra
, nnodefault
;
1736 char *mp
, *ep
, *ndp
;
1737 char missing
[1000], extra
[1000], nodefault
[1000];
1738 static const char *nullvec
[1];
1741 * Look for all required locators, and number the given ones
1742 * according to the required order. While we are numbering,
1743 * set default values for defaulted locators.
1745 if (attr
->a_loclen
== 0) /* e.g., "at root" */
1748 lp
= emalloc((attr
->a_loclen
+ 1) * sizeof(const char *));
1749 for (n
= got
; n
!= NULL
; n
= n
->nv_next
)
1753 /* yes, this is O(mn), but m and n should be small */
1754 for (ord
= 0, m
= attr
->a_locs
; m
!= NULL
; m
= m
->nv_next
, ord
++) {
1755 for (n
= got
; n
!= NULL
; n
= n
->nv_next
) {
1756 if (n
->nv_name
== m
->nv_name
) {
1761 if (n
== NULL
&& m
->nv_num
== 0) {
1763 mp
= extend(mp
, m
->nv_name
);
1765 lp
[ord
] = m
->nv_str
;
1767 if (ord
!= attr
->a_loclen
)
1774 for (n
= got
; n
!= NULL
; n
= n
->nv_next
) {
1775 if (n
->nv_num
>= 0) {
1776 if (n
->nv_str
!= NULL
)
1777 lp
[n
->nv_num
] = n
->nv_str
;
1778 else if (lp
[n
->nv_num
] == NULL
) {
1780 ndp
= extend(ndp
, n
->nv_name
);
1784 ep
= extend(ep
, n
->nv_name
);
1788 ep
[-2] = 0; /* kill ", " */
1789 cfgerror("%s: extraneous locator%s: %s",
1790 name
, nextra
> 1 ? "s" : "", extra
);
1794 cfgerror("%s: must specify %s", name
, missing
);
1798 cfgerror("%s: cannot wildcard %s", name
, nodefault
);
1800 if (nmissing
|| nnodefault
) {
1808 setversion(int newver
)
1810 if (newver
> CONFIG_VERSION
)
1811 cfgerror("your sources require a newer version of config(1) "
1812 "-- please rebuild it.");
1813 else if (newver
< CONFIG_MINVERSION
)
1814 cfgerror("your sources are out of date -- please update.");