sem.c revision 1.72 1 /* $NetBSD: sem.c,v 1.72 2015/08/29 07:08:38 uebayasi Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
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.
10 *
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.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
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.
27 *
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
38 * SUCH DAMAGE.
39 *
40 * from: @(#)sem.c 8.1 (Berkeley) 6/6/93
41 */
42
43 #if HAVE_NBTOOL_CONFIG_H
44 #include "nbtool_config.h"
45 #endif
46
47 #include <sys/cdefs.h>
48 __RCSID("$NetBSD: sem.c,v 1.72 2015/08/29 07:08:38 uebayasi Exp $");
49
50 #include <sys/param.h>
51 #include <ctype.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <util.h>
56 #include "defs.h"
57 #include "sem.h"
58
59 /*
60 * config semantics.
61 */
62
63 #define NAMESIZE 100 /* local name buffers */
64
65 const char *s_ifnet; /* magic attribute */
66 const char *s_qmark;
67 const char *s_none;
68
69 static struct hashtab *cfhashtab; /* for config lookup */
70 struct hashtab *devitab; /* etc */
71 struct attr allattr;
72 size_t nattrs;
73
74 static struct attr errattr;
75 static struct devbase errdev;
76 static struct deva errdeva;
77
78 static int has_errobj(struct attrlist *, struct attr *);
79 static struct nvlist *addtoattr(struct nvlist *, struct devbase *);
80 static int resolve(struct nvlist **, const char *, const char *,
81 struct nvlist *, int);
82 static struct pspec *getpspec(struct attr *, struct devbase *, int);
83 static struct devi *newdevi(const char *, int, struct devbase *d);
84 static struct devi *getdevi(const char *);
85 static void remove_devi(struct devi *);
86 static const char *concat(const char *, int);
87 static char *extend(char *, const char *);
88 static int split(const char *, size_t, char *, size_t, int *);
89 static void selectbase(struct devbase *, struct deva *);
90 static const char **fixloc(const char *, struct attr *, struct loclist *);
91 static const char *makedevstr(devmajor_t, devminor_t);
92 static const char *major2name(devmajor_t);
93 static devmajor_t dev2major(struct devbase *);
94
95 extern const char *yyfile;
96 extern int vflag;
97
98 void
99 initsem(void)
100 {
101
102 attrtab = ht_new();
103 attrdeptab = ht_new();
104
105 allattr.a_name = "netbsd";
106 TAILQ_INIT(&allattr.a_files);
107 (void)ht_insert(attrtab, allattr.a_name, &allattr);
108 selectattr(&allattr);
109
110 errattr.a_name = "<internal>";
111
112 TAILQ_INIT(&allbases);
113
114 TAILQ_INIT(&alldevas);
115
116 TAILQ_INIT(&allpspecs);
117
118 cfhashtab = ht_new();
119 TAILQ_INIT(&allcf);
120
121 TAILQ_INIT(&alldevi);
122 errdev.d_name = "<internal>";
123
124 TAILQ_INIT(&allpseudo);
125
126 TAILQ_INIT(&alldevms);
127
128 s_ifnet = intern("ifnet");
129 s_qmark = intern("?");
130 s_none = intern("none");
131 }
132
133 /* Name of include file just ended (set in scan.l) */
134 extern const char *lastfile;
135
136 static struct attr *
137 finddep(struct attr *a, const char *name)
138 {
139 struct attrlist *al;
140
141 for (al = a->a_deps; al != NULL; al = al->al_next) {
142 struct attr *this = al->al_this;
143 if (strcmp(this->a_name, name) == 0)
144 return this;
145 }
146 return NULL;
147 }
148
149 static void
150 mergedeps(const char *dname, const char *name)
151 {
152 struct attr *a, *newa;
153
154 CFGDBG(4, "merging attr `%s' to devbase `%s'", name, dname);
155 a = refattr(dname);
156 if (finddep(a, name) == NULL) {
157 newa = refattr(name);
158 a->a_deps = attrlist_cons(a->a_deps, newa);
159 CFGDBG(3, "attr `%s' merged to attr `%s'", newa->a_name,
160 a->a_name);
161 }
162 }
163
164 static void
165 fixdev(struct devbase *dev)
166 {
167 struct attrlist *al;
168 struct attr *devattr, *a;
169
170 devattr = refattr(dev->d_name);
171 if (devattr->a_devclass)
172 panic("%s: dev %s is devclass!", __func__, devattr->a_name);
173
174 CFGDBG(4, "fixing devbase `%s'", dev->d_name);
175 for (al = dev->d_attrs; al != NULL; al = al->al_next) {
176 a = al->al_this;
177 CFGDBG(4, "fixing devbase `%s' attr `%s'", dev->d_name, a->a_name);
178 if (a->a_iattr) {
179 a->a_refs = addtoattr(a->a_refs, dev);
180 CFGDBG(3, "device `%s' has iattr `%s'", dev->d_name,
181 a->a_name);
182 } else if (a->a_devclass != NULL) {
183 if (dev->d_classattr != NULL && dev->d_classattr != a) {
184 cfgwarn("device `%s' has multiple classes "
185 "(`%s' and `%s')",
186 dev->d_name, dev->d_classattr->a_name,
187 a->a_name);
188 }
189 if (dev->d_classattr == NULL) {
190 dev->d_classattr = a;
191 CFGDBG(3, "device `%s' is devclass `%s'", dev->d_name,
192 a->a_name);
193 }
194 } else {
195 if (strcmp(dev->d_name, a->a_name) != 0) {
196 mergedeps(dev->d_name, a->a_name);
197 }
198 }
199 }
200 }
201
202 void
203 enddefs(void)
204 {
205 struct devbase *dev;
206
207 yyfile = "enddefs";
208
209 TAILQ_FOREACH(dev, &allbases, d_next) {
210 if (!dev->d_isdef) {
211 (void)fprintf(stderr,
212 "%s: device `%s' used but not defined\n",
213 lastfile, dev->d_name);
214 errors++;
215 continue;
216 }
217 fixdev(dev);
218 }
219 if (errors) {
220 (void)fprintf(stderr, "*** Stop.\n");
221 exit(1);
222 }
223 }
224
225 void
226 setdefmaxusers(int min, int def, int max)
227 {
228
229 if (min < 1 || min > def || def > max)
230 cfgerror("maxusers must have 1 <= min (%d) <= default (%d) "
231 "<= max (%d)", min, def, max);
232 else {
233 minmaxusers = min;
234 defmaxusers = def;
235 maxmaxusers = max;
236 }
237 }
238
239 void
240 setmaxusers(int n)
241 {
242 char buf[32];
243
244 if (maxusers == n) {
245 cfgerror("duplicate maxusers parameter");
246 return;
247 }
248 if (vflag && maxusers != 0)
249 cfgwarn("warning: maxusers already defined");
250 maxusers = n;
251 if (n < minmaxusers) {
252 cfgerror("warning: minimum of %d maxusers assumed",
253 minmaxusers);
254 errors--; /* take it away */
255 maxusers = minmaxusers;
256 } else if (n > maxmaxusers) {
257 cfgerror("warning: maxusers (%d) > %d", n, maxmaxusers);
258 errors--;
259 }
260 snprintf(buf, sizeof(buf), "%d", maxusers);
261 addoption("MAXUSERS", buf);
262 }
263
264 void
265 setident(const char *i)
266 {
267
268 if (i)
269 ident = intern(i);
270 else
271 ident = NULL;
272 }
273
274 /*
275 * Define an attribute, optionally with an interface (a locator list)
276 * and a set of attribute-dependencies.
277 *
278 * Attribute dependencies MAY NOT be interface attributes.
279 *
280 * Since an empty locator list is logically different from "no interface",
281 * all locator lists include a dummy head node, which we discard here.
282 */
283 int
284 defattr0(const char *name, struct loclist *locs, struct attrlist *deps,
285 int devclass)
286 {
287
288 if (locs != NULL)
289 return defiattr(name, locs, deps, devclass);
290 else if (devclass)
291 return defdevclass(name, locs, deps, devclass);
292 else
293 return defattr(name, locs, deps, devclass);
294 }
295
296 int
297 defattr(const char *name, struct loclist *locs, struct attrlist *deps,
298 int devclass)
299 {
300 struct attr *a, *dep;
301 struct attrlist *al;
302
303 /*
304 * If this attribute depends on any others, make sure none of
305 * the dependencies are interface attributes.
306 */
307 for (al = deps; al != NULL; al = al->al_next) {
308 dep = al->al_this;
309 if (dep->a_iattr) {
310 cfgerror("`%s' dependency `%s' is an interface "
311 "attribute", name, dep->a_name);
312 return (1);
313 }
314 (void)ht_insert2(attrdeptab, name, dep->a_name, NULL);
315 CFGDBG(2, "attr `%s' depends on attr `%s'", name, dep->a_name);
316 }
317
318 if (getrefattr(name, &a)) {
319 cfgerror("attribute `%s' already defined", name);
320 loclist_destroy(locs);
321 return (1);
322 }
323 if (a == NULL)
324 a = mkattr(name);
325
326 a->a_deps = deps;
327 expandattr(a, NULL);
328 CFGDBG(3, "attr `%s' defined", a->a_name);
329
330 return (0);
331 }
332
333 struct attr *
334 mkattr(const char *name)
335 {
336 struct attr *a;
337
338 a = ecalloc(1, sizeof *a);
339 if (ht_insert(attrtab, name, a)) {
340 free(a);
341 return NULL;
342 }
343 a->a_name = name;
344 TAILQ_INIT(&a->a_files);
345 CFGDBG(3, "attr `%s' allocated", name);
346
347 return a;
348 }
349
350 /* "interface attribute" initialization */
351 int
352 defiattr(const char *name, struct loclist *locs, struct attrlist *deps,
353 int devclass)
354 {
355 struct attr *a;
356 int len;
357 struct loclist *ll;
358
359 if (devclass)
360 panic("defattr(%s): locators and devclass", name);
361
362 if (defattr(name, locs, deps, devclass) != 0)
363 return (1);
364
365 a = getattr(name);
366 a->a_iattr = 1;
367 /* unwrap */
368 a->a_locs = locs->ll_next;
369 locs->ll_next = NULL;
370 loclist_destroy(locs);
371 len = 0;
372 for (ll = a->a_locs; ll != NULL; ll = ll->ll_next)
373 len++;
374 a->a_loclen = len;
375 if (deps)
376 CFGDBG(2, "attr `%s' iface with deps", a->a_name);
377 return (0);
378 }
379
380 /* "device class" initialization */
381 int
382 defdevclass(const char *name, struct loclist *locs, struct attrlist *deps,
383 int devclass)
384 {
385 struct attr *a;
386 char classenum[256], *cp;
387 int errored = 0;
388
389 if (deps)
390 panic("defattr(%s): dependencies and devclass", name);
391
392 if (defattr(name, locs, deps, devclass) != 0)
393 return (1);
394
395 a = getattr(name);
396 (void)snprintf(classenum, sizeof(classenum), "DV_%s", name);
397 for (cp = classenum + 3; *cp; cp++) {
398 if (!errored &&
399 (!isalnum((unsigned char)*cp) ||
400 (isalpha((unsigned char)*cp) && !islower((unsigned char)*cp)))) {
401 cfgerror("device class names must be "
402 "lower-case alphanumeric characters");
403 errored = 1;
404 }
405 *cp = (char)toupper((unsigned char)*cp);
406 }
407 a->a_devclass = intern(classenum);
408
409 return (0);
410 }
411
412 /*
413 * Return true if the given `error object' is embedded in the given
414 * pointer list.
415 */
416 static int
417 has_errobj(struct attrlist *al, struct attr *obj)
418 {
419
420 for (; al != NULL; al = al->al_next)
421 if (al->al_this == obj)
422 return (1);
423 return (0);
424 }
425
426 /*
427 * Return true if the given attribute is embedded in the given
428 * pointer list.
429 */
430 int
431 has_attr(struct attrlist *al, const char *attr)
432 {
433 struct attr *a;
434
435 if ((a = getattr(attr)) == NULL)
436 return (0);
437
438 for (; al != NULL; al = al->al_next)
439 if (al->al_this == a)
440 return (1);
441 return (0);
442 }
443
444 /*
445 * Add a device base to a list in an attribute (actually, to any list).
446 * Note that this does not check for duplicates, and does reverse the
447 * list order, but no one cares anyway.
448 */
449 static struct nvlist *
450 addtoattr(struct nvlist *l, struct devbase *dev)
451 {
452 struct nvlist *n;
453
454 n = newnv(NULL, NULL, dev, 0, l);
455 return (n);
456 }
457
458 /*
459 * Define a device. This may (or may not) also define an interface
460 * attribute and/or refer to existing attributes.
461 */
462 void
463 defdev(struct devbase *dev, struct loclist *loclist, struct attrlist *attrs,
464 int ispseudo)
465 {
466 struct loclist *ll;
467 struct attrlist *al;
468
469 if (dev == &errdev)
470 goto bad;
471 if (dev->d_isdef) {
472 cfgerror("redefinition of `%s'", dev->d_name);
473 goto bad;
474 }
475
476 dev->d_isdef = 1;
477 if (has_errobj(attrs, &errattr))
478 goto bad;
479
480 /*
481 * Handle implicit attribute definition from locator list. Do
482 * this before scanning the `at' list so that we can have, e.g.:
483 * device foo at other, foo { slot = -1 }
484 * (where you can plug in a foo-bus extender to a foo-bus).
485 */
486 if (loclist != NULL) {
487 ll = loclist;
488 loclist = NULL; /* defattr disposes of them for us */
489 if (defiattr(dev->d_name, ll, NULL, 0))
490 goto bad;
491 attrs = attrlist_cons(attrs, getattr(dev->d_name));
492 /* This used to be stored but was never used */
493 /* attrs->al_name = dev->d_name; */
494 }
495
496 /*
497 * Pseudo-devices can have children. Consider them as
498 * attaching at root.
499 */
500 if (ispseudo) {
501 for (al = attrs; al != NULL; al = al->al_next)
502 if (al->al_this->a_iattr)
503 break;
504 if (al != NULL) {
505 if (ispseudo < 2) {
506 if (version >= 20080610)
507 cfgerror("interface attribute on "
508 "non-device pseudo `%s'", dev->d_name);
509 else {
510 ispseudo = 2;
511 }
512 }
513 ht_insert(devroottab, dev->d_name, dev);
514 }
515 }
516
517 /* Committed! Set up fields. */
518 dev->d_ispseudo = ispseudo;
519 dev->d_attrs = attrs;
520 dev->d_classattr = NULL; /* for now */
521 CFGDBG(3, "dev `%s' defined", dev->d_name);
522
523 /*
524 * Implicit attribute definition for device.
525 */
526 refattr(dev->d_name);
527
528 /*
529 * For each interface attribute this device refers to, add this
530 * device to its reference list. This makes, e.g., finding all
531 * "scsi"s easier.
532 *
533 * While looking through the attributes, set up the device
534 * class if any are devclass attributes (and error out if the
535 * device has two classes).
536 */
537 for (al = attrs; al != NULL; al = al->al_next) {
538 /*
539 * Implicit attribute definition for device dependencies.
540 */
541 refattr(al->al_this->a_name);
542 (void)ht_insert2(attrdeptab, dev->d_name, al->al_this->a_name, NULL);
543 CFGDBG(2, "device `%s' depends on attr `%s'", dev->d_name,
544 al->al_this->a_name);
545 }
546 return;
547 bad:
548 loclist_destroy(loclist);
549 attrlist_destroyall(attrs);
550 }
551
552 /*
553 * Look up a devbase. Also makes sure it is a reasonable name,
554 * i.e., does not end in a digit or contain special characters.
555 */
556 struct devbase *
557 getdevbase(const char *name)
558 {
559 const u_char *p;
560 struct devbase *dev;
561
562 p = (const u_char *)name;
563 if (!isalpha(*p))
564 goto badname;
565 while (*++p) {
566 if (!isalnum(*p) && *p != '_')
567 goto badname;
568 }
569 if (isdigit(*--p)) {
570 badname:
571 cfgerror("bad device base name `%s'", name);
572 return (&errdev);
573 }
574 dev = ht_lookup(devbasetab, name);
575 if (dev == NULL) {
576 dev = ecalloc(1, sizeof *dev);
577 dev->d_name = name;
578 dev->d_isdef = 0;
579 dev->d_major = NODEVMAJOR;
580 dev->d_attrs = NULL;
581 dev->d_ihead = NULL;
582 dev->d_ipp = &dev->d_ihead;
583 dev->d_ahead = NULL;
584 dev->d_app = &dev->d_ahead;
585 dev->d_umax = 0;
586 TAILQ_INSERT_TAIL(&allbases, dev, d_next);
587 if (ht_insert(devbasetab, name, dev))
588 panic("getdevbase(%s)", name);
589 CFGDBG(3, "devbase defined `%s'", dev->d_name);
590 }
591 return (dev);
592 }
593
594 /*
595 * Define some of a device's allowable parent attachments.
596 * There may be a list of (plain) attributes.
597 */
598 void
599 defdevattach(struct deva *deva, struct devbase *dev, struct nvlist *atlist,
600 struct attrlist *attrs)
601 {
602 struct nvlist *nv;
603 struct attrlist *al;
604 struct attr *a;
605 struct deva *da;
606
607 if (dev == &errdev)
608 goto bad;
609 if (deva == NULL)
610 deva = getdevattach(dev->d_name);
611 if (deva == &errdeva)
612 goto bad;
613 if (!dev->d_isdef) {
614 cfgerror("attaching undefined device `%s'", dev->d_name);
615 goto bad;
616 }
617 if (deva->d_isdef) {
618 cfgerror("redefinition of `%s'", deva->d_name);
619 goto bad;
620 }
621 if (dev->d_ispseudo) {
622 cfgerror("pseudo-devices can't attach");
623 goto bad;
624 }
625
626 deva->d_isdef = 1;
627 if (has_errobj(attrs, &errattr))
628 goto bad;
629 for (al = attrs; al != NULL; al = al->al_next) {
630 a = al->al_this;
631 if (a == &errattr)
632 continue; /* already complained */
633 if (a->a_iattr || a->a_devclass != NULL)
634 cfgerror("`%s' is not a plain attribute", a->a_name);
635 }
636
637 /* Committed! Set up fields. */
638 deva->d_attrs = attrs;
639 deva->d_atlist = atlist;
640 deva->d_devbase = dev;
641 CFGDBG(3, "deva `%s' defined", deva->d_name);
642
643 /*
644 * Implicit attribute definition for device attachment.
645 */
646 refattr(deva->d_name);
647
648 /*
649 * Turn the `at' list into interface attributes (map each
650 * nv_name to an attribute, or to NULL for root), and add
651 * this device to those attributes, so that children can
652 * be listed at this particular device if they are supported
653 * by that attribute.
654 */
655 for (nv = atlist; nv != NULL; nv = nv->nv_next) {
656 if (nv->nv_name == NULL)
657 nv->nv_ptr = a = NULL; /* at root */
658 else
659 nv->nv_ptr = a = getattr(nv->nv_name);
660 if (a == &errattr)
661 continue; /* already complained */
662
663 /*
664 * Make sure that an attachment spec doesn't
665 * already say how to attach to this attribute.
666 */
667 for (da = dev->d_ahead; da != NULL; da = da->d_bsame)
668 if (onlist(da->d_atlist, a))
669 cfgerror("attach at `%s' already done by `%s'",
670 a ? a->a_name : "root", da->d_name);
671
672 if (a == NULL) {
673 ht_insert(devroottab, dev->d_name, dev);
674 continue; /* at root; don't add */
675 }
676 if (!a->a_iattr)
677 cfgerror("%s cannot be at plain attribute `%s'",
678 dev->d_name, a->a_name);
679 else
680 a->a_devs = addtoattr(a->a_devs, dev);
681 }
682
683 /* attach to parent */
684 *dev->d_app = deva;
685 dev->d_app = &deva->d_bsame;
686 return;
687 bad:
688 nvfreel(atlist);
689 attrlist_destroyall(attrs);
690 }
691
692 /*
693 * Look up a device attachment. Also makes sure it is a reasonable
694 * name, i.e., does not contain digits or special characters.
695 */
696 struct deva *
697 getdevattach(const char *name)
698 {
699 const u_char *p;
700 struct deva *deva;
701
702 p = (const u_char *)name;
703 if (!isalpha(*p))
704 goto badname;
705 while (*++p) {
706 if (!isalnum(*p) && *p != '_')
707 goto badname;
708 }
709 if (isdigit(*--p)) {
710 badname:
711 cfgerror("bad device attachment name `%s'", name);
712 return (&errdeva);
713 }
714 deva = ht_lookup(devatab, name);
715 if (deva == NULL) {
716 deva = ecalloc(1, sizeof *deva);
717 deva->d_name = name;
718 deva->d_bsame = NULL;
719 deva->d_isdef = 0;
720 deva->d_devbase = NULL;
721 deva->d_atlist = NULL;
722 deva->d_attrs = NULL;
723 deva->d_ihead = NULL;
724 deva->d_ipp = &deva->d_ihead;
725 TAILQ_INSERT_TAIL(&alldevas, deva, d_next);
726 if (ht_insert(devatab, name, deva))
727 panic("getdeva(%s)", name);
728 }
729 return (deva);
730 }
731
732 /*
733 * Look up an attribute.
734 */
735 struct attr *
736 getattr(const char *name)
737 {
738 struct attr *a;
739
740 if ((a = ht_lookup(attrtab, name)) == NULL) {
741 cfgerror("undefined attribute `%s'", name);
742 a = &errattr;
743 }
744 return (a);
745 }
746
747 /*
748 * Implicit attribute definition.
749 */
750 struct attr *
751 refattr(const char *name)
752 {
753 struct attr *a;
754
755 if ((a = ht_lookup(attrtab, name)) == NULL)
756 a = mkattr(name);
757 return a;
758 }
759
760 int
761 getrefattr(const char *name, struct attr **ra)
762 {
763 struct attr *a;
764
765 a = ht_lookup(attrtab, name);
766 if (a == NULL) {
767 *ra = NULL;
768 return (0);
769 }
770 /*
771 * Check if the existing attr is only referenced, not really defined.
772 */
773 if (a->a_deps == NULL &&
774 a->a_iattr == 0 &&
775 a->a_devclass == 0) {
776 *ra = a;
777 return (0);
778 }
779 return (1);
780 }
781
782 /*
783 * Recursively expand an attribute and its dependencies, checking for
784 * cycles, and invoking a callback for each attribute found.
785 */
786 void
787 expandattr(struct attr *a, void (*callback)(struct attr *))
788 {
789 struct attrlist *al;
790 struct attr *dep;
791
792 if (a->a_expanding) {
793 cfgerror("circular dependency on attribute `%s'", a->a_name);
794 return;
795 }
796
797 a->a_expanding = 1;
798
799 /* First expand all of this attribute's dependencies. */
800 for (al = a->a_deps; al != NULL; al = al->al_next) {
801 dep = al->al_this;
802 expandattr(dep, callback);
803 }
804
805 /* ...and now invoke the callback for ourself. */
806 if (callback != NULL)
807 (*callback)(a);
808
809 a->a_expanding = 0;
810 }
811
812 /*
813 * Set the major device number for a device, so that it can be used
814 * as a root/dumps "on" device in a configuration.
815 */
816 void
817 setmajor(struct devbase *d, devmajor_t n)
818 {
819
820 if (d != &errdev && d->d_major != NODEVMAJOR)
821 cfgerror("device `%s' is already major %d",
822 d->d_name, d->d_major);
823 else
824 d->d_major = n;
825 }
826
827 const char *
828 major2name(devmajor_t maj)
829 {
830 struct devbase *dev;
831 struct devm *dm;
832
833 if (!do_devsw) {
834 TAILQ_FOREACH(dev, &allbases, d_next) {
835 if (dev->d_major == maj)
836 return (dev->d_name);
837 }
838 } else {
839 TAILQ_FOREACH(dm, &alldevms, dm_next) {
840 if (dm->dm_bmajor == maj)
841 return (dm->dm_name);
842 }
843 }
844 return (NULL);
845 }
846
847 devmajor_t
848 dev2major(struct devbase *dev)
849 {
850 struct devm *dm;
851
852 if (!do_devsw)
853 return (dev->d_major);
854
855 TAILQ_FOREACH(dm, &alldevms, dm_next) {
856 if (strcmp(dm->dm_name, dev->d_name) == 0)
857 return (dm->dm_bmajor);
858 }
859 return (NODEVMAJOR);
860 }
861
862 /*
863 * Make a string description of the device at maj/min.
864 */
865 static const char *
866 makedevstr(devmajor_t maj, devminor_t min)
867 {
868 const char *devicename;
869 char buf[32];
870
871 devicename = major2name(maj);
872 if (devicename == NULL)
873 (void)snprintf(buf, sizeof(buf), "<%d/%d>", maj, min);
874 else
875 (void)snprintf(buf, sizeof(buf), "%s%d%c", devicename,
876 min / maxpartitions, (min % maxpartitions) + 'a');
877
878 return (intern(buf));
879 }
880
881 /*
882 * Map things like "ra0b" => makedev(major("ra"), 0*maxpartitions + 'b'-'a').
883 * Handle the case where the device number is given but there is no
884 * corresponding name, and map NULL to the default.
885 */
886 static int
887 resolve(struct nvlist **nvp, const char *name, const char *what,
888 struct nvlist *dflt, int part)
889 {
890 struct nvlist *nv;
891 struct devbase *dev;
892 const char *cp;
893 devmajor_t maj;
894 devminor_t min;
895 size_t i, l;
896 int unit;
897 char buf[NAMESIZE];
898
899 if ((part -= 'a') >= maxpartitions || part < 0)
900 panic("resolve");
901 if ((nv = *nvp) == NULL) {
902 dev_t d = NODEV;
903 /*
904 * Apply default. Easiest to do this by number.
905 * Make sure to retain NODEVness, if this is dflt's disposition.
906 */
907 if ((dev_t)dflt->nv_num != NODEV) {
908 maj = major(dflt->nv_num);
909 min = ((minor(dflt->nv_num) / maxpartitions) *
910 maxpartitions) + part;
911 d = makedev(maj, min);
912 cp = makedevstr(maj, min);
913 } else
914 cp = NULL;
915 *nvp = nv = newnv(NULL, cp, NULL, (long long)d, NULL);
916 }
917 if ((dev_t)nv->nv_num != NODEV) {
918 /*
919 * By the numbers. Find the appropriate major number
920 * to make a name.
921 */
922 maj = major(nv->nv_num);
923 min = minor(nv->nv_num);
924 nv->nv_str = makedevstr(maj, min);
925 return (0);
926 }
927
928 if (nv->nv_str == NULL || nv->nv_str == s_qmark)
929 /*
930 * Wildcarded or unspecified; leave it as NODEV.
931 */
932 return (0);
933
934 /*
935 * The normal case: things like "ra2b". Check for partition
936 * suffix, remove it if there, and split into name ("ra") and
937 * unit (2).
938 */
939 l = i = strlen(nv->nv_str);
940 cp = &nv->nv_str[l];
941 if (l > 1 && *--cp >= 'a' && *cp < 'a' + maxpartitions &&
942 isdigit((unsigned char)cp[-1])) {
943 l--;
944 part = *cp - 'a';
945 }
946 cp = nv->nv_str;
947 if (split(cp, l, buf, sizeof buf, &unit)) {
948 cfgerror("%s: invalid %s device name `%s'", name, what, cp);
949 return (1);
950 }
951 dev = ht_lookup(devbasetab, intern(buf));
952 if (dev == NULL) {
953 cfgerror("%s: device `%s' does not exist", name, buf);
954 return (1);
955 }
956
957 /*
958 * Check for the magic network interface attribute, and
959 * don't bother making a device number.
960 */
961 if (has_attr(dev->d_attrs, s_ifnet)) {
962 nv->nv_num = (long long)NODEV;
963 nv->nv_ifunit = unit; /* XXX XXX XXX */
964 } else {
965 maj = dev2major(dev);
966 if (maj == NODEVMAJOR) {
967 cfgerror("%s: can't make %s device from `%s'",
968 name, what, nv->nv_str);
969 return (1);
970 }
971 nv->nv_num = (long long)makedev(maj, unit * maxpartitions + part);
972 }
973
974 nv->nv_name = dev->d_name;
975 return (0);
976 }
977
978 /*
979 * Add a completed configuration to the list.
980 */
981 void
982 addconf(struct config *cf0)
983 {
984 struct config *cf;
985 const char *name;
986
987 name = cf0->cf_name;
988 cf = ecalloc(1, sizeof *cf);
989 if (ht_insert(cfhashtab, name, cf)) {
990 cfgerror("configuration `%s' already defined", name);
991 free(cf);
992 goto bad;
993 }
994 *cf = *cf0;
995
996 /*
997 * Resolve the root device.
998 */
999 if (cf->cf_root == NULL) {
1000 cfgerror("%s: no root device specified", name);
1001 goto bad;
1002 }
1003 if (cf->cf_root && cf->cf_root->nv_str != s_qmark) {
1004 struct nvlist *nv;
1005 nv = cf->cf_root;
1006 if (resolve(&cf->cf_root, name, "root", nv, 'a'))
1007 goto bad;
1008 }
1009
1010 /*
1011 * Resolve the dump device.
1012 */
1013 if (cf->cf_dump == NULL || cf->cf_dump->nv_str == s_qmark) {
1014 /*
1015 * Wildcarded dump device is equivalent to unspecified.
1016 */
1017 cf->cf_dump = NULL;
1018 } else if (cf->cf_dump->nv_str == s_none) {
1019 /*
1020 * Operator has requested that no dump device should be
1021 * configured; do nothing.
1022 */
1023 } else {
1024 if (resolve(&cf->cf_dump, name, "dumps", cf->cf_dump, 'b'))
1025 goto bad;
1026 }
1027
1028 /* Wildcarded fstype is `unspecified'. */
1029 if (cf->cf_fstype == s_qmark)
1030 cf->cf_fstype = NULL;
1031
1032 TAILQ_INSERT_TAIL(&allcf, cf, cf_next);
1033 return;
1034 bad:
1035 nvfreel(cf0->cf_root);
1036 nvfreel(cf0->cf_dump);
1037 }
1038
1039 void
1040 setconf(struct nvlist **npp, const char *what, struct nvlist *v)
1041 {
1042
1043 if (*npp != NULL) {
1044 cfgerror("duplicate %s specification", what);
1045 nvfreel(v);
1046 } else
1047 *npp = v;
1048 }
1049
1050 void
1051 delconf(const char *name)
1052 {
1053 struct config *cf;
1054
1055 CFGDBG(5, "deselecting config `%s'", name);
1056 if (ht_lookup(cfhashtab, name) == NULL) {
1057 cfgerror("configuration `%s' undefined", name);
1058 return;
1059 }
1060 (void)ht_remove(cfhashtab, name);
1061
1062 TAILQ_FOREACH(cf, &allcf, cf_next)
1063 if (!strcmp(cf->cf_name, name))
1064 break;
1065 if (cf == NULL)
1066 panic("lost configuration `%s'", name);
1067
1068 TAILQ_REMOVE(&allcf, cf, cf_next);
1069 }
1070
1071 void
1072 setfstype(const char **fstp, const char *v)
1073 {
1074
1075 if (*fstp != NULL) {
1076 cfgerror("multiple fstype specifications");
1077 return;
1078 }
1079
1080 if (v != s_qmark && OPT_FSOPT(v)) {
1081 cfgerror("\"%s\" is not a configured file system", v);
1082 return;
1083 }
1084
1085 *fstp = v;
1086 }
1087
1088 static struct devi *
1089 newdevi(const char *name, int unit, struct devbase *d)
1090 {
1091 struct devi *i;
1092
1093 i = ecalloc(1, sizeof *i);
1094 i->i_name = name;
1095 i->i_unit = unit;
1096 i->i_base = d;
1097 i->i_bsame = NULL;
1098 i->i_asame = NULL;
1099 i->i_alias = NULL;
1100 i->i_at = NULL;
1101 i->i_pspec = NULL;
1102 i->i_atdeva = NULL;
1103 i->i_locs = NULL;
1104 i->i_cfflags = 0;
1105 i->i_lineno = currentline();
1106 i->i_srcfile = yyfile;
1107 i->i_active = DEVI_ORPHAN; /* Proper analysis comes later */
1108 i->i_level = devilevel;
1109 i->i_pseudoroot = 0;
1110 if (unit >= d->d_umax)
1111 d->d_umax = unit + 1;
1112 return (i);
1113 }
1114
1115 /*
1116 * Add the named device as attaching to the named attribute (or perhaps
1117 * another device instead) plus unit number.
1118 */
1119 void
1120 adddev(const char *name, const char *at, struct loclist *loclist, int flags)
1121 {
1122 struct devi *i; /* the new instance */
1123 struct pspec *p; /* and its pspec */
1124 struct attr *attr; /* attribute that allows attach */
1125 struct devbase *ib; /* i->i_base */
1126 struct devbase *ab; /* not NULL => at another dev */
1127 struct attrlist *al;
1128 struct deva *iba; /* devbase attachment used */
1129 const char *cp;
1130 int atunit;
1131 char atbuf[NAMESIZE];
1132 int hit;
1133
1134 ab = NULL;
1135 iba = NULL;
1136 if (at == NULL) {
1137 /* "at root" */
1138 p = NULL;
1139 if ((i = getdevi(name)) == NULL)
1140 goto bad;
1141 /*
1142 * Must warn about i_unit > 0 later, after taking care of
1143 * the STAR cases (we could do non-star's here but why
1144 * bother?). Make sure this device can be at root.
1145 */
1146 ib = i->i_base;
1147 hit = 0;
1148 for (iba = ib->d_ahead; iba != NULL; iba = iba->d_bsame)
1149 if (onlist(iba->d_atlist, NULL)) {
1150 hit = 1;
1151 break;
1152 }
1153 if (!hit) {
1154 cfgerror("`%s' cannot attach to the root", ib->d_name);
1155 i->i_active = DEVI_BROKEN;
1156 goto bad;
1157 }
1158 attr = &errattr; /* a convenient "empty" attr */
1159 } else {
1160 if (split(at, strlen(at), atbuf, sizeof atbuf, &atunit)) {
1161 cfgerror("invalid attachment name `%s'", at);
1162 /* (void)getdevi(name); -- ??? */
1163 goto bad;
1164 }
1165 if ((i = getdevi(name)) == NULL)
1166 goto bad;
1167 ib = i->i_base;
1168
1169 /*
1170 * Devices can attach to two types of things: Attributes,
1171 * and other devices (which have the appropriate attributes
1172 * to allow attachment).
1173 *
1174 * (1) If we're attached to an attribute, then we don't need
1175 * look at the parent base device to see what attributes
1176 * it has, and make sure that we can attach to them.
1177 *
1178 * (2) If we're attached to a real device (i.e. named in
1179 * the config file), we want to remember that so that
1180 * at cross-check time, if the device we're attached to
1181 * is missing but other devices which also provide the
1182 * attribute are present, we don't get a false "OK."
1183 *
1184 * (3) If the thing we're attached to is an attribute
1185 * but is actually named in the config file, we still
1186 * have to remember its devbase.
1187 */
1188 cp = intern(atbuf);
1189
1190 /* Figure out parent's devbase, to satisfy case (3). */
1191 ab = ht_lookup(devbasetab, cp);
1192
1193 /* Find out if it's an attribute. */
1194 attr = ht_lookup(attrtab, cp);
1195
1196 /* Make sure we're _really_ attached to the attr. Case (1). */
1197 if (attr != NULL && onlist(attr->a_devs, ib))
1198 goto findattachment;
1199
1200 /*
1201 * Else a real device, and not just an attribute. Case (2).
1202 *
1203 * Have to work a bit harder to see whether we have
1204 * something like "tg0 at esp0" (where esp is merely
1205 * not an attribute) or "tg0 at nonesuch0" (where
1206 * nonesuch is not even a device).
1207 */
1208 if (ab == NULL) {
1209 cfgerror("%s at %s: `%s' unknown",
1210 name, at, atbuf);
1211 i->i_active = DEVI_BROKEN;
1212 goto bad;
1213 }
1214
1215 /*
1216 * See if the named parent carries an attribute
1217 * that allows it to supervise device ib.
1218 */
1219 for (al = ab->d_attrs; al != NULL; al = al->al_next) {
1220 attr = al->al_this;
1221 if (onlist(attr->a_devs, ib))
1222 goto findattachment;
1223 }
1224 cfgerror("`%s' cannot attach to `%s'", ib->d_name, atbuf);
1225 i->i_active = DEVI_BROKEN;
1226 goto bad;
1227
1228 findattachment:
1229 /*
1230 * Find the parent spec. If a matching one has not yet been
1231 * created, create one.
1232 */
1233 p = getpspec(attr, ab, atunit);
1234 p->p_devs = newnv(NULL, NULL, i, 0, p->p_devs);
1235
1236 /* find out which attachment it uses */
1237 hit = 0;
1238 for (iba = ib->d_ahead; iba != NULL; iba = iba->d_bsame)
1239 if (onlist(iba->d_atlist, attr)) {
1240 hit = 1;
1241 break;
1242 }
1243 if (!hit)
1244 panic("adddev: can't figure out attachment");
1245 }
1246 if ((i->i_locs = fixloc(name, attr, loclist)) == NULL) {
1247 i->i_active = DEVI_BROKEN;
1248 goto bad;
1249 }
1250 i->i_at = at;
1251 i->i_pspec = p;
1252 i->i_atdeva = iba;
1253 i->i_cfflags = flags;
1254 CFGDBG(3, "devi `%s' added", i->i_name);
1255
1256 *iba->d_ipp = i;
1257 iba->d_ipp = &i->i_asame;
1258
1259 /* all done, fall into ... */
1260 bad:
1261 loclist_destroy(loclist);
1262 return;
1263 }
1264
1265 void
1266 deldevi(const char *name, const char *at)
1267 {
1268 struct devi *firsti, *i;
1269 struct devbase *d;
1270 int unit;
1271 char base[NAMESIZE];
1272
1273 CFGDBG(5, "deselecting devi `%s'", name);
1274 if (split(name, strlen(name), base, sizeof base, &unit)) {
1275 cfgerror("invalid device name `%s'", name);
1276 return;
1277 }
1278 d = ht_lookup(devbasetab, intern(base));
1279 if (d == NULL) {
1280 cfgerror("%s: unknown device `%s'", name, base);
1281 return;
1282 }
1283 if (d->d_ispseudo) {
1284 cfgerror("%s: %s is a pseudo-device", name, base);
1285 return;
1286 }
1287 if ((firsti = ht_lookup(devitab, name)) == NULL) {
1288 cfgerror("`%s' not defined", name);
1289 return;
1290 }
1291 if (at == NULL && firsti->i_at == NULL) {
1292 /* 'at root' */
1293 remove_devi(firsti);
1294 return;
1295 } else if (at != NULL)
1296 for (i = firsti; i != NULL; i = i->i_alias)
1297 if (i->i_active != DEVI_BROKEN &&
1298 strcmp(at, i->i_at) == 0) {
1299 remove_devi(i);
1300 return;
1301 }
1302 cfgerror("`%s' at `%s' not found", name, at ? at : "root");
1303 }
1304
1305 static void
1306 remove_devi(struct devi *i)
1307 {
1308 struct devbase *d = i->i_base;
1309 struct devi *f, *j, **ppi;
1310 struct deva *iba;
1311
1312 CFGDBG(5, "removing devi `%s'", i->i_name);
1313 f = ht_lookup(devitab, i->i_name);
1314 if (f == NULL)
1315 panic("remove_devi(): instance %s disappeared from devitab",
1316 i->i_name);
1317
1318 if (i->i_active == DEVI_BROKEN) {
1319 cfgerror("not removing broken instance `%s'", i->i_name);
1320 return;
1321 }
1322
1323 /*
1324 * We have the device instance, i.
1325 * We have to:
1326 * - delete the alias
1327 *
1328 * If the devi was an alias of an already listed devi, all is
1329 * good we don't have to do more.
1330 * If it was the first alias, we have to replace i's entry in
1331 * d's list by its first alias.
1332 * If it was the only entry, we must remove i's entry from d's
1333 * list.
1334 */
1335 if (i != f) {
1336 for (j = f; j->i_alias != i; j = j->i_alias)
1337 continue;
1338 j->i_alias = i->i_alias;
1339 } else {
1340 if (i->i_alias == NULL) {
1341 /* No alias, must unlink the entry from devitab */
1342 ht_remove(devitab, i->i_name);
1343 j = i->i_bsame;
1344 } else {
1345 /* Or have the first alias replace i in d's list */
1346 i->i_alias->i_bsame = i->i_bsame;
1347 j = i->i_alias;
1348 if (i == f)
1349 ht_replace(devitab, i->i_name, i->i_alias);
1350 }
1351
1352 /*
1353 * - remove/replace the instance from the devbase's list
1354 *
1355 * A double-linked list would make this much easier. Oh, well,
1356 * what is done is done.
1357 */
1358 for (ppi = &d->d_ihead;
1359 *ppi != NULL && *ppi != i && (*ppi)->i_bsame != i;
1360 ppi = &(*ppi)->i_bsame)
1361 continue;
1362 if (*ppi == NULL)
1363 panic("deldev: dev (%s) doesn't list the devi"
1364 " (%s at %s)", d->d_name, i->i_name, i->i_at);
1365 f = *ppi;
1366 if (f == i)
1367 /* That implies d->d_ihead == i */
1368 *ppi = j;
1369 else
1370 (*ppi)->i_bsame = j;
1371 if (d->d_ipp == &i->i_bsame) {
1372 if (i->i_alias == NULL) {
1373 if (f == i)
1374 d->d_ipp = &d->d_ihead;
1375 else
1376 d->d_ipp = &f->i_bsame;
1377 } else
1378 d->d_ipp = &i->i_alias->i_bsame;
1379 }
1380 }
1381 /*
1382 * - delete the attachment instance
1383 */
1384 iba = i->i_atdeva;
1385 for (ppi = &iba->d_ihead;
1386 *ppi != NULL && *ppi != i && (*ppi)->i_asame != i;
1387 ppi = &(*ppi)->i_asame)
1388 continue;
1389 if (*ppi == NULL)
1390 panic("deldev: deva (%s) doesn't list the devi (%s)",
1391 iba->d_name, i->i_name);
1392 f = *ppi;
1393 if (f == i)
1394 /* That implies iba->d_ihead == i */
1395 *ppi = i->i_asame;
1396 else
1397 (*ppi)->i_asame = i->i_asame;
1398 if (iba->d_ipp == &i->i_asame) {
1399 if (f == i)
1400 iba->d_ipp = &iba->d_ihead;
1401 else
1402 iba->d_ipp = &f->i_asame;
1403 }
1404 /*
1405 * - delete the pspec
1406 */
1407 if (i->i_pspec) {
1408 struct pspec *p = i->i_pspec;
1409 struct nvlist *nv, *onv;
1410
1411 /* Double-linked nvlist anyone? */
1412 for (nv = p->p_devs; nv->nv_next != NULL; nv = nv->nv_next) {
1413 if (nv->nv_next && nv->nv_next->nv_ptr == i) {
1414 onv = nv->nv_next;
1415 nv->nv_next = onv->nv_next;
1416 nvfree(onv);
1417 break;
1418 }
1419 if (nv->nv_ptr == i) {
1420 /* nv is p->p_devs in that case */
1421 p->p_devs = nv->nv_next;
1422 nvfree(nv);
1423 break;
1424 }
1425 }
1426 if (p->p_devs == NULL)
1427 TAILQ_REMOVE(&allpspecs, p, p_list);
1428 }
1429 /*
1430 * - delete the alldevi entry
1431 */
1432 TAILQ_REMOVE(&alldevi, i, i_next);
1433 ndevi--;
1434 /*
1435 * Put it in deaddevitab
1436 *
1437 * Each time a devi is removed, devilevel is increased so that later on
1438 * it is possible to tell if an instance was added before or after the
1439 * removal of its parent.
1440 *
1441 * For active instances, i_level contains the number of devi removed so
1442 * far, and for dead devis, it contains its index.
1443 */
1444 i->i_level = devilevel++;
1445 i->i_alias = NULL;
1446 f = ht_lookup(deaddevitab, i->i_name);
1447 if (f == NULL) {
1448 if (ht_insert(deaddevitab, i->i_name, i))
1449 panic("remove_devi(%s) - can't add to deaddevitab",
1450 i->i_name);
1451 } else {
1452 for (j = f; j->i_alias != NULL; j = j->i_alias)
1453 continue;
1454 j->i_alias = i;
1455 }
1456 /*
1457 * - reconstruct d->d_umax
1458 */
1459 d->d_umax = 0;
1460 for (i = d->d_ihead; i != NULL; i = i->i_bsame)
1461 if (i->i_unit >= d->d_umax)
1462 d->d_umax = i->i_unit + 1;
1463 }
1464
1465 void
1466 deldeva(const char *at)
1467 {
1468 int unit;
1469 const char *cp;
1470 struct devbase *d, *ad;
1471 struct devi *i, *j;
1472 struct attr *a;
1473 struct pspec *p;
1474 struct nvlist *nv, *stack = NULL;
1475
1476 if (at == NULL) {
1477 TAILQ_FOREACH(i, &alldevi, i_next)
1478 if (i->i_at == NULL)
1479 stack = newnv(NULL, NULL, i, 0, stack);
1480 } else {
1481 size_t l;
1482
1483 CFGDBG(5, "deselecting deva `%s'", at);
1484 if (at[0] == '\0')
1485 goto out;
1486
1487 l = strlen(at) - 1;
1488 if (at[l] == '?' || isdigit((unsigned char)at[l])) {
1489 char base[NAMESIZE];
1490
1491 if (split(at, l+1, base, sizeof base, &unit)) {
1492 out:
1493 cfgerror("invalid attachment name `%s'", at);
1494 return;
1495 }
1496 cp = intern(base);
1497 } else {
1498 cp = intern(at);
1499 unit = STAR;
1500 }
1501
1502 ad = ht_lookup(devbasetab, cp);
1503 a = ht_lookup(attrtab, cp);
1504 if (a == NULL) {
1505 cfgerror("unknown attachment attribute or device `%s'",
1506 cp);
1507 return;
1508 }
1509 if (!a->a_iattr) {
1510 cfgerror("plain attribute `%s' cannot have children",
1511 a->a_name);
1512 return;
1513 }
1514
1515 /*
1516 * remove_devi() makes changes to the devbase's list and the
1517 * alias list, * so the actual deletion of the instances must
1518 * be delayed.
1519 */
1520 for (nv = a->a_devs; nv != NULL; nv = nv->nv_next) {
1521 d = nv->nv_ptr;
1522 for (i = d->d_ihead; i != NULL; i = i->i_bsame)
1523 for (j = i; j != NULL; j = j->i_alias) {
1524 /* Ignore devices at root */
1525 if (j->i_at == NULL)
1526 continue;
1527 p = j->i_pspec;
1528 /*
1529 * There are three cases:
1530 *
1531 * 1. unit is not STAR. Consider 'at'
1532 * to be explicit, even if it
1533 * references an interface
1534 * attribute.
1535 *
1536 * 2. unit is STAR and 'at' references
1537 * a real device. Look for pspec
1538 * that have a matching p_atdev
1539 * field.
1540 *
1541 * 3. unit is STAR and 'at' references
1542 * an interface attribute. Look
1543 * for pspec that have a matching
1544 * p_iattr field.
1545 */
1546 if ((unit != STAR && /* Case */
1547 !strcmp(j->i_at, at)) || /* 1 */
1548 (unit == STAR &&
1549 ((ad != NULL && /* Case */
1550 p->p_atdev == ad) || /* 2 */
1551 (ad == NULL && /* Case */
1552 p->p_iattr == a)))) /* 3 */
1553 stack = newnv(NULL, NULL, j, 0,
1554 stack);
1555 }
1556 }
1557 }
1558
1559 for (nv = stack; nv != NULL; nv = nv->nv_next)
1560 remove_devi(nv->nv_ptr);
1561 nvfreel(stack);
1562 }
1563
1564 void
1565 deldev(const char *name)
1566 {
1567 size_t l;
1568 struct devi *firsti, *i;
1569 struct nvlist *nv, *stack = NULL;
1570
1571 CFGDBG(5, "deselecting dev `%s'", name);
1572 if (name[0] == '\0')
1573 goto out;
1574
1575 l = strlen(name) - 1;
1576 if (name[l] == '*' || isdigit((unsigned char)name[l])) {
1577 /* `no mydev0' or `no mydev*' */
1578 firsti = ht_lookup(devitab, name);
1579 if (firsti == NULL) {
1580 out:
1581 cfgerror("unknown instance %s", name);
1582 return;
1583 }
1584 for (i = firsti; i != NULL; i = i->i_alias)
1585 stack = newnv(NULL, NULL, i, 0, stack);
1586 } else {
1587 struct devbase *d = ht_lookup(devbasetab, name);
1588
1589 if (d == NULL) {
1590 cfgerror("unknown device %s", name);
1591 return;
1592 }
1593 if (d->d_ispseudo) {
1594 cfgerror("%s is a pseudo-device; "
1595 "use \"no pseudo-device %s\" instead", name,
1596 name);
1597 return;
1598 }
1599
1600 for (firsti = d->d_ihead; firsti != NULL;
1601 firsti = firsti->i_bsame)
1602 for (i = firsti; i != NULL; i = i->i_alias)
1603 stack = newnv(NULL, NULL, i, 0, stack);
1604 }
1605
1606 for (nv = stack; nv != NULL; nv = nv->nv_next)
1607 remove_devi(nv->nv_ptr);
1608 nvfreel(stack);
1609 }
1610
1611 /*
1612 * Insert given device "name" into devroottab. In case "name"
1613 * designates a pure interface attribute, create a fake device
1614 * instance for the attribute and insert that into the roottab
1615 * (this scheme avoids mucking around with the orphanage analysis).
1616 */
1617 void
1618 addpseudoroot(const char *name)
1619 {
1620 char buf[NAMESIZE];
1621 int unit;
1622 struct attr *attr;
1623 struct devi *i;
1624 struct deva *iba;
1625 struct devbase *ib;
1626
1627 if (split(name, strlen(name), buf, sizeof(buf), &unit)) {
1628 cfgerror("invalid pseudo-root name `%s'", name);
1629 return;
1630 }
1631
1632 /*
1633 * Prefer device because devices with locators define an
1634 * implicit interface attribute. However, if a device is
1635 * not available, try to attach to the interface attribute.
1636 * This makes sure adddev() doesn't get confused when we
1637 * are really attaching to a device (alternatively we maybe
1638 * could specify a non-NULL atlist to defdevattach() below).
1639 */
1640 ib = ht_lookup(devbasetab, intern(buf));
1641 if (ib == NULL) {
1642 struct devbase *fakedev;
1643 char fakename[NAMESIZE];
1644
1645 attr = ht_lookup(attrtab, intern(buf));
1646 if (!(attr && attr->a_iattr)) {
1647 cfgerror("pseudo-root `%s' not available", name);
1648 return;
1649 }
1650
1651 /*
1652 * here we cheat a bit: create a fake devbase with the
1653 * interface attribute and instantiate it. quick, cheap,
1654 * dirty & bad for you, much like the stuff in the fridge.
1655 * and, it works, since the pseudoroot device is not included
1656 * in ioconf, just used by config to make sure we start from
1657 * the right place.
1658 */
1659 snprintf(fakename, sizeof(fakename), "%s_devattrs", buf);
1660 fakedev = getdevbase(intern(fakename));
1661 fakedev->d_isdef = 1;
1662 fakedev->d_ispseudo = 0;
1663 fakedev->d_attrs = attrlist_cons(NULL, attr);
1664 defdevattach(NULL, fakedev, NULL, NULL);
1665
1666 if (unit == STAR)
1667 snprintf(buf, sizeof(buf), "%s*", fakename);
1668 else
1669 snprintf(buf, sizeof(buf), "%s%d", fakename, unit);
1670 name = buf;
1671 }
1672
1673 /* ok, everything should be set up, so instantiate a fake device */
1674 i = getdevi(name);
1675 if (i == NULL)
1676 panic("device `%s' expected to be present", name);
1677 ib = i->i_base;
1678 iba = ib->d_ahead;
1679
1680 i->i_atdeva = iba;
1681 i->i_cfflags = 0;
1682 i->i_locs = fixloc(name, &errattr, NULL);
1683 i->i_pseudoroot = 1;
1684 i->i_active = DEVI_ORPHAN; /* set active by kill_orphans() */
1685
1686 *iba->d_ipp = i;
1687 iba->d_ipp = &i->i_asame;
1688
1689 ht_insert(devroottab, ib->d_name, ib);
1690 }
1691
1692 void
1693 addpseudo(const char *name, int number)
1694 {
1695 struct devbase *d;
1696 struct devi *i;
1697
1698 d = ht_lookup(devbasetab, name);
1699 if (d == NULL) {
1700 cfgerror("undefined pseudo-device %s", name);
1701 return;
1702 }
1703 if (!d->d_ispseudo) {
1704 cfgerror("%s is a real device, not a pseudo-device", name);
1705 return;
1706 }
1707 if (ht_lookup(devitab, name) != NULL) {
1708 cfgerror("`%s' already defined", name);
1709 return;
1710 }
1711 i = newdevi(name, number - 1, d); /* foo 16 => "foo0..foo15" */
1712 if (ht_insert(devitab, name, i))
1713 panic("addpseudo(%s)", name);
1714 /* Useful to retrieve the instance from the devbase */
1715 d->d_ihead = i;
1716 i->i_active = DEVI_ACTIVE;
1717 TAILQ_INSERT_TAIL(&allpseudo, i, i_next);
1718 }
1719
1720 void
1721 delpseudo(const char *name)
1722 {
1723 struct devbase *d;
1724 struct devi *i;
1725
1726 CFGDBG(5, "deselecting pseudo `%s'", name);
1727 d = ht_lookup(devbasetab, name);
1728 if (d == NULL) {
1729 cfgerror("undefined pseudo-device %s", name);
1730 return;
1731 }
1732 if (!d->d_ispseudo) {
1733 cfgerror("%s is a real device, not a pseudo-device", name);
1734 return;
1735 }
1736 if ((i = ht_lookup(devitab, name)) == NULL) {
1737 cfgerror("`%s' not defined", name);
1738 return;
1739 }
1740 d->d_umax = 0; /* clear neads-count entries */
1741 d->d_ihead = NULL; /* make sure it won't be considered active */
1742 TAILQ_REMOVE(&allpseudo, i, i_next);
1743 if (ht_remove(devitab, name))
1744 panic("delpseudo(%s) - can't remove from devitab", name);
1745 if (ht_insert(deaddevitab, name, i))
1746 panic("delpseudo(%s) - can't add to deaddevitab", name);
1747 }
1748
1749 void
1750 adddevm(const char *name, devmajor_t cmajor, devmajor_t bmajor,
1751 struct condexpr *cond, struct nvlist *nv_nodes)
1752 {
1753 struct devm *dm;
1754
1755 if (cmajor != NODEVMAJOR && (cmajor < 0 || cmajor >= 4096)) {
1756 cfgerror("character major %d is invalid", cmajor);
1757 condexpr_destroy(cond);
1758 nvfreel(nv_nodes);
1759 return;
1760 }
1761
1762 if (bmajor != NODEVMAJOR && (bmajor < 0 || bmajor >= 4096)) {
1763 cfgerror("block major %d is invalid", bmajor);
1764 condexpr_destroy(cond);
1765 nvfreel(nv_nodes);
1766 return;
1767 }
1768 if (cmajor == NODEVMAJOR && bmajor == NODEVMAJOR) {
1769 cfgerror("both character/block majors are not specified");
1770 condexpr_destroy(cond);
1771 nvfreel(nv_nodes);
1772 return;
1773 }
1774
1775 dm = ecalloc(1, sizeof(*dm));
1776 dm->dm_srcfile = yyfile;
1777 dm->dm_srcline = currentline();
1778 dm->dm_name = name;
1779 dm->dm_cmajor = cmajor;
1780 dm->dm_bmajor = bmajor;
1781 dm->dm_opts = cond;
1782 dm->dm_devnodes = nv_nodes;
1783
1784 TAILQ_INSERT_TAIL(&alldevms, dm, dm_next);
1785
1786 maxcdevm = MAX(maxcdevm, dm->dm_cmajor);
1787 maxbdevm = MAX(maxbdevm, dm->dm_bmajor);
1788 }
1789
1790 int
1791 fixdevis(void)
1792 {
1793 struct devi *i;
1794 int error = 0;
1795
1796 TAILQ_FOREACH(i, &alldevi, i_next) {
1797 CFGDBG(3, "fixing devis `%s'", i->i_name);
1798 if (i->i_active == DEVI_ACTIVE)
1799 selectbase(i->i_base, i->i_atdeva);
1800 else if (i->i_active == DEVI_ORPHAN) {
1801 /*
1802 * At this point, we can't have instances for which
1803 * i_at or i_pspec are NULL.
1804 */
1805 ++error;
1806 cfgxerror(i->i_srcfile, i->i_lineno,
1807 "`%s at %s' is orphaned (%s `%s' found)",
1808 i->i_name, i->i_at, i->i_pspec->p_atunit == WILD ?
1809 "nothing matching" : "no", i->i_at);
1810 } else if (vflag && i->i_active == DEVI_IGNORED)
1811 cfgxwarn(i->i_srcfile, i->i_lineno, "ignoring "
1812 "explicitly orphaned instance `%s at %s'",
1813 i->i_name, i->i_at);
1814 }
1815
1816 if (error)
1817 return error;
1818
1819 TAILQ_FOREACH(i, &allpseudo, i_next)
1820 if (i->i_active == DEVI_ACTIVE)
1821 selectbase(i->i_base, NULL);
1822 return 0;
1823 }
1824
1825 /*
1826 * Look up a parent spec, creating a new one if it does not exist.
1827 */
1828 static struct pspec *
1829 getpspec(struct attr *attr, struct devbase *ab, int atunit)
1830 {
1831 struct pspec *p;
1832
1833 TAILQ_FOREACH(p, &allpspecs, p_list) {
1834 if (p->p_iattr == attr &&
1835 p->p_atdev == ab &&
1836 p->p_atunit == atunit)
1837 return (p);
1838 }
1839
1840 p = ecalloc(1, sizeof(*p));
1841
1842 p->p_iattr = attr;
1843 p->p_atdev = ab;
1844 p->p_atunit = atunit;
1845 p->p_inst = npspecs++;
1846 p->p_active = 0;
1847
1848 TAILQ_INSERT_TAIL(&allpspecs, p, p_list);
1849
1850 return (p);
1851 }
1852
1853 /*
1854 * Define a new instance of a specific device.
1855 */
1856 static struct devi *
1857 getdevi(const char *name)
1858 {
1859 struct devi *i, *firsti;
1860 struct devbase *d;
1861 int unit;
1862 char base[NAMESIZE];
1863
1864 if (split(name, strlen(name), base, sizeof base, &unit)) {
1865 cfgerror("invalid device name `%s'", name);
1866 return (NULL);
1867 }
1868 d = ht_lookup(devbasetab, intern(base));
1869 if (d == NULL) {
1870 cfgerror("%s: unknown device `%s'", name, base);
1871 return (NULL);
1872 }
1873 if (d->d_ispseudo) {
1874 cfgerror("%s: %s is a pseudo-device", name, base);
1875 return (NULL);
1876 }
1877 firsti = ht_lookup(devitab, name);
1878 i = newdevi(name, unit, d);
1879 if (firsti == NULL) {
1880 if (ht_insert(devitab, name, i))
1881 panic("getdevi(%s)", name);
1882 *d->d_ipp = i;
1883 d->d_ipp = &i->i_bsame;
1884 } else {
1885 while (firsti->i_alias)
1886 firsti = firsti->i_alias;
1887 firsti->i_alias = i;
1888 }
1889 TAILQ_INSERT_TAIL(&alldevi, i, i_next);
1890 ndevi++;
1891 return (i);
1892 }
1893
1894 static const char *
1895 concat(const char *name, int c)
1896 {
1897 size_t len;
1898 char buf[NAMESIZE];
1899
1900 len = strlen(name);
1901 if (len + 2 > sizeof(buf)) {
1902 cfgerror("device name `%s%c' too long", name, c);
1903 len = sizeof(buf) - 2;
1904 }
1905 memmove(buf, name, len);
1906 buf[len] = (char)c;
1907 buf[len + 1] = '\0';
1908 return (intern(buf));
1909 }
1910
1911 const char *
1912 starref(const char *name)
1913 {
1914
1915 return (concat(name, '*'));
1916 }
1917
1918 const char *
1919 wildref(const char *name)
1920 {
1921
1922 return (concat(name, '?'));
1923 }
1924
1925 /*
1926 * Split a name like "foo0" into base name (foo) and unit number (0).
1927 * Return 0 on success. To make this useful for names like "foo0a",
1928 * the length of the "foo0" part is one of the arguments.
1929 */
1930 static int
1931 split(const char *name, size_t nlen, char *base, size_t bsize, int *aunit)
1932 {
1933 const char *cp;
1934 int c;
1935 size_t l;
1936
1937 l = nlen;
1938 if (l < 2 || l >= bsize || isdigit((unsigned char)*name))
1939 return (1);
1940 c = (u_char)name[--l];
1941 if (!isdigit(c)) {
1942 if (c == '*')
1943 *aunit = STAR;
1944 else if (c == '?')
1945 *aunit = WILD;
1946 else
1947 return (1);
1948 } else {
1949 cp = &name[l];
1950 while (isdigit((unsigned char)cp[-1]))
1951 l--, cp--;
1952 *aunit = atoi(cp);
1953 }
1954 memmove(base, name, l);
1955 base[l] = 0;
1956 return (0);
1957 }
1958
1959 void
1960 addattr(const char *name)
1961 {
1962 struct attr *a;
1963
1964 a = refattr(name);
1965 selectattr(a);
1966 }
1967
1968 void
1969 delattr(const char *name)
1970 {
1971 struct attr *a;
1972
1973 a = refattr(name);
1974 deselectattr(a);
1975 }
1976
1977 void
1978 selectattr(struct attr *a)
1979 {
1980 struct attrlist *al;
1981 struct attr *dep;
1982
1983 CFGDBG(5, "selecting attr `%s'", a->a_name);
1984 for (al = a->a_deps; al != NULL; al = al->al_next) {
1985 dep = al->al_this;
1986 selectattr(dep);
1987 }
1988 if (ht_insert(selecttab, a->a_name, __UNCONST(a->a_name)) == 0)
1989 nattrs++;
1990 CFGDBG(3, "attr selected `%s'", a->a_name);
1991 }
1992
1993 static int
1994 deselectattrcb2(const char *name1, const char *name2, void *v, void *arg)
1995 {
1996 const char *name = arg;
1997
1998 if (strcmp(name, name2) == 0)
1999 delattr(name1);
2000 return 0;
2001 }
2002
2003 void
2004 deselectattr(struct attr *a)
2005 {
2006
2007 CFGDBG(5, "deselecting attr `%s'", a->a_name);
2008 ht_enumerate2(attrdeptab, deselectattrcb2, __UNCONST(a->a_name));
2009 if (ht_remove(selecttab, a->a_name) == 0)
2010 nattrs--;
2011 CFGDBG(3, "attr deselected `%s'", a->a_name);
2012 }
2013
2014 static int
2015 dumpattrdepcb2(const char *name1, const char *name2, void *v, void *arg)
2016 {
2017
2018 CFGDBG(3, "attr `%s' depends on attr `%s'", name1, name2);
2019 return 0;
2020 }
2021
2022 void
2023 dependattrs(void)
2024 {
2025
2026 ht_enumerate2(attrdeptab, dumpattrdepcb2, NULL);
2027 }
2028
2029 /*
2030 * We have an instance of the base foo, so select it and all its
2031 * attributes for "optional foo".
2032 */
2033 static void
2034 selectbase(struct devbase *d, struct deva *da)
2035 {
2036 struct attr *a;
2037 struct attrlist *al;
2038
2039 (void)ht_insert(selecttab, d->d_name, __UNCONST(d->d_name));
2040 CFGDBG(3, "devbase selected `%s'", d->d_name);
2041 CFGDBG(5, "selecting dependencies of devbase `%s'", d->d_name);
2042 for (al = d->d_attrs; al != NULL; al = al->al_next) {
2043 a = al->al_this;
2044 expandattr(a, selectattr);
2045 }
2046
2047 struct attr *devattr;
2048 devattr = refattr(d->d_name);
2049 expandattr(devattr, selectattr);
2050
2051 if (da != NULL) {
2052 (void)ht_insert(selecttab, da->d_name, __UNCONST(da->d_name));
2053 CFGDBG(3, "devattr selected `%s'", da->d_name);
2054 for (al = da->d_attrs; al != NULL; al = al->al_next) {
2055 a = al->al_this;
2056 expandattr(a, selectattr);
2057 }
2058 }
2059
2060 fixdev(d);
2061 }
2062
2063 /*
2064 * Is the given pointer on the given list of pointers?
2065 */
2066 int
2067 onlist(struct nvlist *nv, void *ptr)
2068 {
2069 for (; nv != NULL; nv = nv->nv_next)
2070 if (nv->nv_ptr == ptr)
2071 return (1);
2072 return (0);
2073 }
2074
2075 static char *
2076 extend(char *p, const char *name)
2077 {
2078 size_t l;
2079
2080 l = strlen(name);
2081 memmove(p, name, l);
2082 p += l;
2083 *p++ = ',';
2084 *p++ = ' ';
2085 return (p);
2086 }
2087
2088 /*
2089 * Check that we got all required locators, and default any that are
2090 * given as "?" and have defaults. Return 0 on success.
2091 */
2092 static const char **
2093 fixloc(const char *name, struct attr *attr, struct loclist *got)
2094 {
2095 struct loclist *m, *n;
2096 int ord;
2097 const char **lp;
2098 int nmissing, nextra, nnodefault;
2099 char *mp, *ep, *ndp;
2100 char missing[1000], extra[1000], nodefault[1000];
2101 static const char *nullvec[1];
2102
2103 /*
2104 * Look for all required locators, and number the given ones
2105 * according to the required order. While we are numbering,
2106 * set default values for defaulted locators.
2107 */
2108 if (attr->a_loclen == 0) /* e.g., "at root" */
2109 lp = nullvec;
2110 else
2111 lp = emalloc((size_t)(attr->a_loclen + 1) * sizeof(const char *));
2112 for (n = got; n != NULL; n = n->ll_next)
2113 n->ll_num = -1;
2114 nmissing = 0;
2115 mp = missing;
2116 /* yes, this is O(mn), but m and n should be small */
2117 for (ord = 0, m = attr->a_locs; m != NULL; m = m->ll_next, ord++) {
2118 for (n = got; n != NULL; n = n->ll_next) {
2119 if (n->ll_name == m->ll_name) {
2120 n->ll_num = ord;
2121 break;
2122 }
2123 }
2124 if (n == NULL && m->ll_num == 0) {
2125 nmissing++;
2126 mp = extend(mp, m->ll_name);
2127 }
2128 lp[ord] = m->ll_string;
2129 }
2130 if (ord != attr->a_loclen)
2131 panic("fixloc");
2132 lp[ord] = NULL;
2133 nextra = 0;
2134 ep = extra;
2135 nnodefault = 0;
2136 ndp = nodefault;
2137 for (n = got; n != NULL; n = n->ll_next) {
2138 if (n->ll_num >= 0) {
2139 if (n->ll_string != NULL)
2140 lp[n->ll_num] = n->ll_string;
2141 else if (lp[n->ll_num] == NULL) {
2142 nnodefault++;
2143 ndp = extend(ndp, n->ll_name);
2144 }
2145 } else {
2146 nextra++;
2147 ep = extend(ep, n->ll_name);
2148 }
2149 }
2150 if (nextra) {
2151 ep[-2] = 0; /* kill ", " */
2152 cfgerror("%s: extraneous locator%s: %s",
2153 name, nextra > 1 ? "s" : "", extra);
2154 }
2155 if (nmissing) {
2156 mp[-2] = 0;
2157 cfgerror("%s: must specify %s", name, missing);
2158 }
2159 if (nnodefault) {
2160 ndp[-2] = 0;
2161 cfgerror("%s: cannot wildcard %s", name, nodefault);
2162 }
2163 if (nmissing || nnodefault) {
2164 free(lp);
2165 lp = NULL;
2166 }
2167 return (lp);
2168 }
2169
2170 void
2171 setversion(int newver)
2172 {
2173 if (newver > CONFIG_VERSION)
2174 cfgerror("your sources require a newer version of config(1) "
2175 "-- please rebuild it.");
2176 else if (newver < CONFIG_MINVERSION)
2177 cfgerror("your sources are out of date -- please update.");
2178 else
2179 version = newver;
2180 }
2181