sem.c revision 1.7 1 /* $NetBSD: sem.c,v 1.7 2005/09/30 22:51:46 cube 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/param.h>
48 #include <ctype.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include "defs.h"
53 #include "sem.h"
54
55 /*
56 * config semantics.
57 */
58
59 #define NAMESIZE 100 /* local name buffers */
60
61 const char *s_ifnet; /* magic attribute */
62 const char *s_qmark;
63 const char *s_none;
64
65 static struct hashtab *cfhashtab; /* for config lookup */
66 struct hashtab *devitab; /* etc */
67
68 static struct attr errattr;
69 static struct devbase errdev;
70 static struct deva errdeva;
71
72 static int has_errobj(struct nvlist *, void *);
73 static struct nvlist *addtoattr(struct nvlist *, struct devbase *);
74 static int resolve(struct nvlist **, const char *, const char *,
75 struct nvlist *, int);
76 static struct pspec *getpspec(struct attr *, struct devbase *, int);
77 static struct devi *newdevi(const char *, int, struct devbase *d);
78 static struct devi *getdevi(const char *);
79 static void remove_devi(struct devi *);
80 static const char *concat(const char *, int);
81 static char *extend(char *, const char *);
82 static int split(const char *, size_t, char *, size_t, int *);
83 static void selectbase(struct devbase *, struct deva *);
84 static int onlist(struct nvlist *, void *);
85 static const char **fixloc(const char *, struct attr *, struct nvlist *);
86 static const char *makedevstr(int, int);
87 static const char *major2name(int);
88 static int dev2major(struct devbase *);
89
90 extern const char *yyfile;
91
92 void
93 initsem(void)
94 {
95
96 attrtab = ht_new();
97 errattr.a_name = "<internal>";
98
99 TAILQ_INIT(&allbases);
100
101 TAILQ_INIT(&alldevas);
102
103 TAILQ_INIT(&allpspecs);
104
105 cfhashtab = ht_new();
106 TAILQ_INIT(&allcf);
107
108 TAILQ_INIT(&alldevi);
109 errdev.d_name = "<internal>";
110
111 TAILQ_INIT(&allpseudo);
112
113 TAILQ_INIT(&alldevms);
114
115 s_ifnet = intern("ifnet");
116 s_qmark = intern("?");
117 s_none = intern("none");
118 }
119
120 /* Name of include file just ended (set in scan.l) */
121 extern const char *lastfile;
122
123 void
124 enddefs(void)
125 {
126 struct devbase *dev;
127
128 TAILQ_FOREACH(dev, &allbases, d_next) {
129 if (!dev->d_isdef) {
130 (void)fprintf(stderr,
131 "%s: device `%s' used but not defined\n",
132 lastfile, dev->d_name);
133 errors++;
134 continue;
135 }
136 }
137 if (errors) {
138 (void)fprintf(stderr, "*** Stop.\n");
139 exit(1);
140 }
141 }
142
143 void
144 setdefmaxusers(int min, int def, int max)
145 {
146
147 if (min < 1 || min > def || def > max)
148 error("maxusers must have 1 <= min (%d) <= default (%d) <= max (%d)", min, def, max);
149 else {
150 minmaxusers = min;
151 defmaxusers = def;
152 maxmaxusers = max;
153 }
154 }
155
156 void
157 setmaxusers(int n)
158 {
159
160 if (maxusers != 0) {
161 error("duplicate maxusers parameter");
162 return;
163 }
164 maxusers = n;
165 if (n < minmaxusers) {
166 error("warning: minimum of %d maxusers assumed", minmaxusers);
167 errors--; /* take it away */
168 maxusers = minmaxusers;
169 } else if (n > maxmaxusers) {
170 error("warning: maxusers (%d) > %d", n, maxmaxusers);
171 errors--;
172 }
173 }
174
175 void
176 setident(const char *i)
177 {
178
179 ident = intern(i);
180 }
181
182 /*
183 * Define an attribute, optionally with an interface (a locator list)
184 * and a set of attribute-dependencies.
185 *
186 * Attribute dependencies MAY NOT be interface attributes.
187 *
188 * Since an empty locator list is logically different from "no interface",
189 * all locator lists include a dummy head node, which we discard here.
190 */
191 int
192 defattr(const char *name, struct nvlist *locs, struct nvlist *deps,
193 int devclass)
194 {
195 struct attr *a, *dep;
196 struct nvlist *nv;
197 int len;
198
199 if (locs != NULL && devclass)
200 panic("defattr(%s): locators and devclass", name);
201
202 if (deps != NULL && devclass)
203 panic("defattr(%s): dependencies and devclass", name);
204
205 /*
206 * If this attribute depends on any others, make sure none of
207 * the dependencies are interface attributes.
208 */
209 for (nv = deps; nv != NULL; nv = nv->nv_next) {
210 dep = nv->nv_ptr;
211 if (dep->a_iattr) {
212 error("`%s' dependency `%s' is an interface attribute",
213 name, dep->a_name);
214 return (1);
215 }
216 }
217
218 a = ecalloc(1, sizeof *a);
219 if (ht_insert(attrtab, name, a)) {
220 free(a);
221 error("attribute `%s' already defined", name);
222 nvfreel(locs);
223 return (1);
224 }
225
226 a->a_name = name;
227 if (locs != NULL) {
228 a->a_iattr = 1;
229 a->a_locs = locs->nv_next;
230 nvfree(locs);
231 } else {
232 a->a_iattr = 0;
233 a->a_locs = NULL;
234 }
235 if (devclass) {
236 size_t l = strlen(name) + 4;
237 char *classenum = alloca(l), *cp;
238 int errored = 0;
239
240 strlcpy(classenum, "DV_", l);
241 strlcat(classenum, name, l);
242 for (cp = classenum + 3; *cp; cp++) {
243 if (!errored &&
244 (!isalnum((unsigned char)*cp) ||
245 (isalpha((unsigned char)*cp) && !islower((unsigned char)*cp)))) {
246 error("device class names must be lower-case alphanumeric characters");
247 errored = 1;
248 }
249 *cp = toupper((unsigned char)*cp);
250 }
251 a->a_devclass = intern(classenum);
252 } else
253 a->a_devclass = NULL;
254 len = 0;
255 for (nv = a->a_locs; nv != NULL; nv = nv->nv_next)
256 len++;
257 a->a_loclen = len;
258 a->a_devs = NULL;
259 a->a_refs = NULL;
260 a->a_deps = deps;
261 a->a_expanding = 0;
262
263 /* Expand the attribute to check for cycles in the graph. */
264 expandattr(a, NULL);
265
266 return (0);
267 }
268
269 /*
270 * Return true if the given `error object' is embedded in the given
271 * pointer list.
272 */
273 static int
274 has_errobj(struct nvlist *nv, void *obj)
275 {
276
277 for (; nv != NULL; nv = nv->nv_next)
278 if (nv->nv_ptr == obj)
279 return (1);
280 return (0);
281 }
282
283 /*
284 * Return true if the given attribute is embedded in the given
285 * pointer list.
286 */
287 int
288 has_attr(struct nvlist *nv, const char *attr)
289 {
290 struct attr *a;
291
292 if ((a = getattr(attr)) == NULL)
293 return (0);
294
295 for (; nv != NULL; nv = nv->nv_next)
296 if (nv->nv_ptr == a)
297 return (1);
298 return (0);
299 }
300
301 /*
302 * Add a device base to a list in an attribute (actually, to any list).
303 * Note that this does not check for duplicates, and does reverse the
304 * list order, but no one cares anyway.
305 */
306 static struct nvlist *
307 addtoattr(struct nvlist *l, struct devbase *dev)
308 {
309 struct nvlist *n;
310
311 n = newnv(NULL, NULL, dev, 0, l);
312 return (n);
313 }
314
315 /*
316 * Define a device. This may (or may not) also define an interface
317 * attribute and/or refer to existing attributes.
318 */
319 void
320 defdev(struct devbase *dev, struct nvlist *loclist, struct nvlist *attrs,
321 int ispseudo)
322 {
323 struct nvlist *nv;
324 struct attr *a;
325
326 if (dev == &errdev)
327 goto bad;
328 if (dev->d_isdef) {
329 error("redefinition of `%s'", dev->d_name);
330 goto bad;
331 }
332
333 dev->d_isdef = 1;
334 if (has_errobj(attrs, &errattr))
335 goto bad;
336
337 /*
338 * Handle implicit attribute definition from locator list. Do
339 * this before scanning the `at' list so that we can have, e.g.:
340 * device foo at other, foo { slot = -1 }
341 * (where you can plug in a foo-bus extender to a foo-bus).
342 */
343 if (loclist != NULL) {
344 nv = loclist;
345 loclist = NULL; /* defattr disposes of them for us */
346 if (defattr(dev->d_name, nv, NULL, 0))
347 goto bad;
348 attrs = newnv(dev->d_name, NULL, getattr(dev->d_name), 0,
349 attrs);
350
351 /*
352 * Pseudo-devices can have children. Consider them as
353 * attaching at root.
354 */
355 if (ispseudo)
356 ht_insert(devroottab, dev->d_name, dev);
357 }
358
359 /* Committed! Set up fields. */
360 dev->d_ispseudo = ispseudo;
361 dev->d_attrs = attrs;
362 dev->d_classattr = NULL; /* for now */
363
364 /*
365 * For each interface attribute this device refers to, add this
366 * device to its reference list. This makes, e.g., finding all
367 * "scsi"s easier.
368 *
369 * While looking through the attributes, set up the device
370 * class if any are devclass attributes (and error out if the
371 * device has two classes).
372 */
373 for (nv = attrs; nv != NULL; nv = nv->nv_next) {
374 a = nv->nv_ptr;
375 if (a->a_iattr)
376 a->a_refs = addtoattr(a->a_refs, dev);
377 if (a->a_devclass != NULL) {
378 if (dev->d_classattr != NULL) {
379 error("device `%s' has multiple classes (`%s' and `%s')",
380 dev->d_name, dev->d_classattr->a_name,
381 a->a_name);
382 }
383 dev->d_classattr = a;
384 }
385 }
386 return;
387 bad:
388 nvfreel(loclist);
389 nvfreel(attrs);
390 }
391
392 /*
393 * Look up a devbase. Also makes sure it is a reasonable name,
394 * i.e., does not end in a digit or contain special characters.
395 */
396 struct devbase *
397 getdevbase(const char *name)
398 {
399 u_char *p;
400 struct devbase *dev;
401
402 p = (u_char *)name;
403 if (!isalpha(*p))
404 goto badname;
405 while (*++p) {
406 if (!isalnum(*p) && *p != '_')
407 goto badname;
408 }
409 if (isdigit(*--p)) {
410 badname:
411 error("bad device base name `%s'", name);
412 return (&errdev);
413 }
414 dev = ht_lookup(devbasetab, name);
415 if (dev == NULL) {
416 dev = ecalloc(1, sizeof *dev);
417 dev->d_name = name;
418 dev->d_isdef = 0;
419 dev->d_major = NODEV;
420 dev->d_attrs = NULL;
421 dev->d_ihead = NULL;
422 dev->d_ipp = &dev->d_ihead;
423 dev->d_ahead = NULL;
424 dev->d_app = &dev->d_ahead;
425 dev->d_umax = 0;
426 TAILQ_INSERT_TAIL(&allbases, dev, d_next);
427 if (ht_insert(devbasetab, name, dev))
428 panic("getdevbase(%s)", name);
429 }
430 return (dev);
431 }
432
433 /*
434 * Define some of a device's allowable parent attachments.
435 * There may be a list of (plain) attributes.
436 */
437 void
438 defdevattach(struct deva *deva, struct devbase *dev, struct nvlist *atlist,
439 struct nvlist *attrs)
440 {
441 struct nvlist *nv;
442 struct attr *a;
443 struct deva *da;
444
445 if (dev == &errdev)
446 goto bad;
447 if (deva == NULL)
448 deva = getdevattach(dev->d_name);
449 if (deva == &errdeva)
450 goto bad;
451 if (!dev->d_isdef) {
452 error("attaching undefined device `%s'", dev->d_name);
453 goto bad;
454 }
455 if (deva->d_isdef) {
456 error("redefinition of `%s'", deva->d_name);
457 goto bad;
458 }
459 if (dev->d_ispseudo) {
460 error("pseudo-devices can't attach");
461 goto bad;
462 }
463
464 deva->d_isdef = 1;
465 if (has_errobj(attrs, &errattr))
466 goto bad;
467 for (nv = attrs; nv != NULL; nv = nv->nv_next) {
468 a = nv->nv_ptr;
469 if (a == &errattr)
470 continue; /* already complained */
471 if (a->a_iattr || a->a_devclass != NULL)
472 error("`%s' is not a plain attribute", a->a_name);
473 }
474
475 /* Committed! Set up fields. */
476 deva->d_attrs = attrs;
477 deva->d_atlist = atlist;
478 deva->d_devbase = dev;
479
480 /*
481 * Turn the `at' list into interface attributes (map each
482 * nv_name to an attribute, or to NULL for root), and add
483 * this device to those attributes, so that children can
484 * be listed at this particular device if they are supported
485 * by that attribute.
486 */
487 for (nv = atlist; nv != NULL; nv = nv->nv_next) {
488 if (nv->nv_name == NULL)
489 nv->nv_ptr = a = NULL; /* at root */
490 else
491 nv->nv_ptr = a = getattr(nv->nv_name);
492 if (a == &errattr)
493 continue; /* already complained */
494
495 /*
496 * Make sure that an attachment spec doesn't
497 * already say how to attach to this attribute.
498 */
499 for (da = dev->d_ahead; da != NULL; da = da->d_bsame)
500 if (onlist(da->d_atlist, a))
501 error("attach at `%s' already done by `%s'",
502 a ? a->a_name : "root", da->d_name);
503
504 if (a == NULL) {
505 ht_insert(devroottab, dev->d_name, dev);
506 continue; /* at root; don't add */
507 }
508 if (!a->a_iattr)
509 error("%s cannot be at plain attribute `%s'",
510 dev->d_name, a->a_name);
511 else
512 a->a_devs = addtoattr(a->a_devs, dev);
513 }
514
515 /* attach to parent */
516 *dev->d_app = deva;
517 dev->d_app = &deva->d_bsame;
518 return;
519 bad:
520 nvfreel(atlist);
521 nvfreel(attrs);
522 }
523
524 /*
525 * Look up a device attachment. Also makes sure it is a reasonable
526 * name, i.e., does not contain digits or special characters.
527 */
528 struct deva *
529 getdevattach(const char *name)
530 {
531 u_char *p;
532 struct deva *deva;
533
534 p = (u_char *)name;
535 if (!isalpha(*p))
536 goto badname;
537 while (*++p) {
538 if (!isalnum(*p) && *p != '_')
539 goto badname;
540 }
541 if (isdigit(*--p)) {
542 badname:
543 error("bad device attachment name `%s'", name);
544 return (&errdeva);
545 }
546 deva = ht_lookup(devatab, name);
547 if (deva == NULL) {
548 deva = ecalloc(1, sizeof *deva);
549 deva->d_name = name;
550 deva->d_bsame = NULL;
551 deva->d_isdef = 0;
552 deva->d_devbase = NULL;
553 deva->d_atlist = NULL;
554 deva->d_attrs = NULL;
555 deva->d_ihead = NULL;
556 deva->d_ipp = &deva->d_ihead;
557 TAILQ_INSERT_TAIL(&alldevas, deva, d_next);
558 if (ht_insert(devatab, name, deva))
559 panic("getdeva(%s)", name);
560 }
561 return (deva);
562 }
563
564 /*
565 * Look up an attribute.
566 */
567 struct attr *
568 getattr(const char *name)
569 {
570 struct attr *a;
571
572 if ((a = ht_lookup(attrtab, name)) == NULL) {
573 error("undefined attribute `%s'", name);
574 a = &errattr;
575 }
576 return (a);
577 }
578
579 /*
580 * Recursively expand an attribute and its dependencies, checking for
581 * cycles, and invoking a callback for each attribute found.
582 */
583 void
584 expandattr(struct attr *a, void (*callback)(struct attr *))
585 {
586 struct nvlist *nv;
587 struct attr *dep;
588
589 if (a->a_expanding) {
590 error("circular dependency on attribute `%s'", a->a_name);
591 return;
592 }
593
594 a->a_expanding = 1;
595
596 /* First expand all of this attribute's dependencies. */
597 for (nv = a->a_deps; nv != NULL; nv = nv->nv_next) {
598 dep = nv->nv_ptr;
599 expandattr(dep, callback);
600 }
601
602 /* ...and now invoke the callback for ourself. */
603 if (callback != NULL)
604 (*callback)(a);
605
606 a->a_expanding = 0;
607 }
608
609 /*
610 * Set the major device number for a device, so that it can be used
611 * as a root/dumps "on" device in a configuration.
612 */
613 void
614 setmajor(struct devbase *d, int n)
615 {
616
617 if (d != &errdev && d->d_major != NODEV)
618 error("device `%s' is already major %d",
619 d->d_name, d->d_major);
620 else
621 d->d_major = n;
622 }
623
624 const char *
625 major2name(int maj)
626 {
627 struct devbase *dev;
628 struct devm *dm;
629
630 if (!do_devsw) {
631 TAILQ_FOREACH(dev, &allbases, d_next) {
632 if (dev->d_major == maj)
633 return (dev->d_name);
634 }
635 } else {
636 TAILQ_FOREACH(dm, &alldevms, dm_next) {
637 if (dm->dm_bmajor == maj)
638 return (dm->dm_name);
639 }
640 }
641 return (NULL);
642 }
643
644 int
645 dev2major(struct devbase *dev)
646 {
647 struct devm *dm;
648
649 if (!do_devsw)
650 return (dev->d_major);
651
652 TAILQ_FOREACH(dm, &alldevms, dm_next) {
653 if (strcmp(dm->dm_name, dev->d_name) == 0)
654 return (dm->dm_bmajor);
655 }
656 return (NODEV);
657 }
658
659 /*
660 * Make a string description of the device at maj/min.
661 */
662 static const char *
663 makedevstr(int maj, int min)
664 {
665 const char *devname;
666 char buf[32];
667
668 devname = major2name(maj);
669 if (devname == NULL)
670 (void)snprintf(buf, sizeof(buf), "<%d/%d>", maj, min);
671 else
672 (void)snprintf(buf, sizeof(buf), "%s%d%c", devname,
673 min / maxpartitions, (min % maxpartitions) + 'a');
674
675 return (intern(buf));
676 }
677
678 /*
679 * Map things like "ra0b" => makedev(major("ra"), 0*maxpartitions + 'b'-'a').
680 * Handle the case where the device number is given but there is no
681 * corresponding name, and map NULL to the default.
682 */
683 static int
684 resolve(struct nvlist **nvp, const char *name, const char *what,
685 struct nvlist *dflt, int part)
686 {
687 struct nvlist *nv;
688 struct devbase *dev;
689 const char *cp;
690 int maj, min, i, l;
691 int unit;
692 char buf[NAMESIZE];
693
694 if ((u_int)(part -= 'a') >= maxpartitions)
695 panic("resolve");
696 if ((nv = *nvp) == NULL) {
697 dev_t d = NODEV;
698 /*
699 * Apply default. Easiest to do this by number.
700 * Make sure to retain NODEVness, if this is dflt's disposition.
701 */
702 if (dflt->nv_int != NODEV) {
703 maj = major(dflt->nv_int);
704 min = ((minor(dflt->nv_int) / maxpartitions) *
705 maxpartitions) + part;
706 d = makedev(maj, min);
707 cp = makedevstr(maj, min);
708 } else
709 cp = NULL;
710 *nvp = nv = newnv(NULL, cp, NULL, d, NULL);
711 }
712 if (nv->nv_int != NODEV) {
713 /*
714 * By the numbers. Find the appropriate major number
715 * to make a name.
716 */
717 maj = major(nv->nv_int);
718 min = minor(nv->nv_int);
719 nv->nv_str = makedevstr(maj, min);
720 return (0);
721 }
722
723 if (nv->nv_str == NULL || nv->nv_str == s_qmark)
724 /*
725 * Wildcarded or unspecified; leave it as NODEV.
726 */
727 return (0);
728
729 /*
730 * The normal case: things like "ra2b". Check for partition
731 * suffix, remove it if there, and split into name ("ra") and
732 * unit (2).
733 */
734 l = i = strlen(nv->nv_str);
735 cp = &nv->nv_str[l];
736 if (l > 1 && *--cp >= 'a' && *cp < 'a' + maxpartitions &&
737 isdigit((unsigned char)cp[-1])) {
738 l--;
739 part = *cp - 'a';
740 }
741 cp = nv->nv_str;
742 if (split(cp, l, buf, sizeof buf, &unit)) {
743 error("%s: invalid %s device name `%s'", name, what, cp);
744 return (1);
745 }
746 dev = ht_lookup(devbasetab, intern(buf));
747 if (dev == NULL) {
748 error("%s: device `%s' does not exist", name, buf);
749 return (1);
750 }
751
752 /*
753 * Check for the magic network interface attribute, and
754 * don't bother making a device number.
755 */
756 if (has_attr(dev->d_attrs, s_ifnet)) {
757 nv->nv_int = NODEV;
758 nv->nv_ifunit = unit; /* XXX XXX XXX */
759 } else {
760 maj = dev2major(dev);
761 if (maj == NODEV) {
762 error("%s: can't make %s device from `%s'",
763 name, what, nv->nv_str);
764 return (1);
765 }
766 nv->nv_int = makedev(maj, unit * maxpartitions + part);
767 }
768
769 nv->nv_name = dev->d_name;
770 return (0);
771 }
772
773 /*
774 * Add a completed configuration to the list.
775 */
776 void
777 addconf(struct config *cf0)
778 {
779 struct config *cf;
780 struct nvlist *nv;
781 const char *name;
782
783 name = cf0->cf_name;
784 cf = ecalloc(1, sizeof *cf);
785 if (ht_insert(cfhashtab, name, cf)) {
786 error("configuration `%s' already defined", name);
787 free(cf);
788 goto bad;
789 }
790 *cf = *cf0;
791
792 /*
793 * Resolve the root device.
794 */
795 if (cf->cf_root->nv_str != s_qmark) {
796 nv = cf->cf_root;
797 if (nv == NULL) {
798 error("%s: no root device specified", name);
799 goto bad;
800 }
801 if (resolve(&cf->cf_root, name, "root", nv, 'a'))
802 goto bad;
803 }
804
805 /*
806 * Resolve the dump device.
807 */
808 if (cf->cf_dump == NULL || cf->cf_dump->nv_str == s_qmark) {
809 /*
810 * Wildcarded dump device is equivalent to unspecified.
811 */
812 cf->cf_dump = NULL;
813 } else if (cf->cf_dump->nv_str == s_none) {
814 /*
815 * Operator has requested that no dump device should be
816 * configured; do nothing.
817 */
818 } else {
819 if (resolve(&cf->cf_dump, name, "dumps", cf->cf_dump, 'b'))
820 goto bad;
821 }
822
823 /* Wildcarded fstype is `unspecified'. */
824 if (cf->cf_fstype == s_qmark)
825 cf->cf_fstype = NULL;
826
827 TAILQ_INSERT_TAIL(&allcf, cf, cf_next);
828 return;
829 bad:
830 nvfreel(cf0->cf_root);
831 nvfreel(cf0->cf_dump);
832 }
833
834 void
835 setconf(struct nvlist **npp, const char *what, struct nvlist *v)
836 {
837
838 if (*npp != NULL) {
839 error("duplicate %s specification", what);
840 nvfreel(v);
841 } else
842 *npp = v;
843 }
844
845 void
846 setfstype(const char **fstp, const char *v)
847 {
848
849 if (*fstp != NULL) {
850 error("multiple fstype specifications");
851 return;
852 }
853
854 if (v != s_qmark && OPT_FSOPT(v)) {
855 error("\"%s\" is not a configured file system", v);
856 return;
857 }
858
859 *fstp = v;
860 }
861
862 static struct devi *
863 newdevi(const char *name, int unit, struct devbase *d)
864 {
865 struct devi *i;
866
867 i = ecalloc(1, sizeof *i);
868 i->i_name = name;
869 i->i_unit = unit;
870 i->i_base = d;
871 i->i_bsame = NULL;
872 i->i_asame = NULL;
873 i->i_alias = NULL;
874 i->i_at = NULL;
875 i->i_pspec = NULL;
876 i->i_atdeva = NULL;
877 i->i_locs = NULL;
878 i->i_cfflags = 0;
879 i->i_lineno = currentline();
880 i->i_active = 0;
881 if (unit >= d->d_umax)
882 d->d_umax = unit + 1;
883 return (i);
884 }
885
886 /*
887 * Add the named device as attaching to the named attribute (or perhaps
888 * another device instead) plus unit number.
889 */
890 void
891 adddev(const char *name, const char *at, struct nvlist *loclist, int flags)
892 {
893 struct devi *i; /* the new instance */
894 struct pspec *p; /* and its pspec */
895 struct attr *attr; /* attribute that allows attach */
896 struct devbase *ib; /* i->i_base */
897 struct devbase *ab; /* not NULL => at another dev */
898 struct nvlist *nv;
899 struct deva *iba; /* devbase attachment used */
900 const char *cp;
901 int atunit;
902 char atbuf[NAMESIZE];
903 int hit;
904
905 ab = NULL;
906 iba = NULL;
907 if (at == NULL) {
908 /* "at root" */
909 p = NULL;
910 if ((i = getdevi(name)) == NULL)
911 goto bad;
912 /*
913 * Must warn about i_unit > 0 later, after taking care of
914 * the STAR cases (we could do non-star's here but why
915 * bother?). Make sure this device can be at root.
916 */
917 ib = i->i_base;
918 hit = 0;
919 for (iba = ib->d_ahead; iba != NULL; iba = iba->d_bsame)
920 if (onlist(iba->d_atlist, NULL)) {
921 hit = 1;
922 break;
923 }
924 if (!hit) {
925 error("`%s' cannot attach to the root", ib->d_name);
926 goto bad;
927 }
928 attr = &errattr; /* a convenient "empty" attr */
929 } else {
930 if (split(at, strlen(at), atbuf, sizeof atbuf, &atunit)) {
931 error("invalid attachment name `%s'", at);
932 /* (void)getdevi(name); -- ??? */
933 goto bad;
934 }
935 if ((i = getdevi(name)) == NULL)
936 goto bad;
937 ib = i->i_base;
938
939 /*
940 * Devices can attach to two types of things: Attributes,
941 * and other devices (which have the appropriate attributes
942 * to allow attachment).
943 *
944 * (1) If we're attached to an attribute, then we don't need
945 * look at the parent base device to see what attributes
946 * it has, and make sure that we can attach to them.
947 *
948 * (2) If we're attached to a real device (i.e. named in
949 * the config file), we want to remember that so that
950 * at cross-check time, if the device we're attached to
951 * is missing but other devices which also provide the
952 * attribute are present, we don't get a false "OK."
953 *
954 * (3) If the thing we're attached to is an attribute
955 * but is actually named in the config file, we still
956 * have to remember its devbase.
957 */
958 cp = intern(atbuf);
959
960 /* Figure out parent's devbase, to satisfy case (3). */
961 ab = ht_lookup(devbasetab, cp);
962
963 /* Find out if it's an attribute. */
964 attr = ht_lookup(attrtab, cp);
965
966 /* Make sure we're _really_ attached to the attr. Case (1). */
967 if (attr != NULL && onlist(attr->a_devs, ib))
968 goto findattachment;
969
970 /*
971 * Else a real device, and not just an attribute. Case (2).
972 *
973 * Have to work a bit harder to see whether we have
974 * something like "tg0 at esp0" (where esp is merely
975 * not an attribute) or "tg0 at nonesuch0" (where
976 * nonesuch is not even a device).
977 */
978 if (ab == NULL) {
979 error("%s at %s: `%s' unknown",
980 name, at, atbuf);
981 goto bad;
982 }
983
984 /*
985 * See if the named parent carries an attribute
986 * that allows it to supervise device ib.
987 */
988 for (nv = ab->d_attrs; nv != NULL; nv = nv->nv_next) {
989 attr = nv->nv_ptr;
990 if (onlist(attr->a_devs, ib))
991 goto findattachment;
992 }
993 error("`%s' cannot attach to `%s'", ib->d_name, atbuf);
994 goto bad;
995
996 findattachment:
997 /*
998 * Find the parent spec. If a matching one has not yet been
999 * created, create one.
1000 */
1001 p = getpspec(attr, ab, atunit);
1002 p->p_devs = newnv(NULL, NULL, i, 0, p->p_devs);
1003
1004 /* find out which attachment it uses */
1005 hit = 0;
1006 for (iba = ib->d_ahead; iba != NULL; iba = iba->d_bsame)
1007 if (onlist(iba->d_atlist, attr)) {
1008 hit = 1;
1009 break;
1010 }
1011 if (!hit)
1012 panic("adddev: can't figure out attachment");
1013 }
1014 if ((i->i_locs = fixloc(name, attr, loclist)) == NULL)
1015 goto bad;
1016 i->i_at = at;
1017 i->i_pspec = p;
1018 i->i_atdeva = iba;
1019 i->i_cfflags = flags;
1020
1021 *iba->d_ipp = i;
1022 iba->d_ipp = &i->i_asame;
1023
1024 /* all done, fall into ... */
1025 bad:
1026 nvfreel(loclist);
1027 return;
1028 }
1029
1030 void
1031 deldevi(const char *name, const char *at)
1032 {
1033 struct devi *firsti, *i;
1034 struct devbase *d;
1035 int unit;
1036 char base[NAMESIZE];
1037
1038 if (split(name, strlen(name), base, sizeof base, &unit)) {
1039 error("invalid device name `%s'", name);
1040 return;
1041 }
1042 d = ht_lookup(devbasetab, intern(base));
1043 if (d == NULL) {
1044 error("%s: unknown device `%s'", name, base);
1045 return;
1046 }
1047 if (d->d_ispseudo) {
1048 error("%s: %s is a pseudo-device", name, base);
1049 return;
1050 }
1051 if ((firsti = ht_lookup(devitab, name)) == NULL) {
1052 error("`%s' not defined", name);
1053 return;
1054 }
1055 if (at == NULL && firsti->i_at == NULL) {
1056 /* 'at root' */
1057 remove_devi(firsti);
1058 return;
1059 } else if (at != NULL)
1060 for (i = firsti; i != NULL; i = i->i_alias)
1061 if (strcmp(at, i->i_at) == 0) {
1062 remove_devi(i);
1063 return;
1064 }
1065 error("`%s' at `%s' not found", name, at ? at : "root");
1066 }
1067
1068 static void
1069 remove_devi(struct devi *i)
1070 {
1071 struct devbase *d = i->i_base;
1072 struct devi *f, *j, **ppi;
1073 struct deva *iba;
1074
1075 f = ht_lookup(devitab, i->i_name);
1076
1077 /*
1078 * We have the device instance, i.
1079 * We have to:
1080 * - delete the alias
1081 *
1082 * If the devi was an alias of an already listed devi, all is
1083 * good we don't have to do more.
1084 * If it was the first alias, we have to replace i's entry in
1085 * d's list by its first alias.
1086 * If it was the only entry, we must remove i's entry from d's
1087 * list.
1088 */
1089 if (i != f) {
1090 for (j = f; j->i_alias != i; j = j->i_alias);
1091 j->i_alias = i->i_alias;
1092 } else {
1093 if (i->i_alias == NULL) {
1094 /* No alias, must unlink the entry from devitab */
1095 ht_remove(devitab, i->i_name);
1096 j = i->i_bsame;
1097 } else {
1098 /* Or have the first alias replace i in d's list */
1099 i->i_alias->i_bsame = i->i_bsame;
1100 j = i->i_alias;
1101 if (i == f)
1102 ht_replace(devitab, i->i_name, i->i_alias);
1103 }
1104
1105 /*
1106 * - remove/replace the instance from the devbase's list
1107 *
1108 * A double-linked list would make this much easier. Oh, well,
1109 * what is done is done.
1110 */
1111 for (ppi = &d->d_ihead;
1112 *ppi != NULL && *ppi != i && (*ppi)->i_bsame != i;
1113 ppi = &(*ppi)->i_bsame);
1114 if (*ppi == NULL)
1115 panic("deldev: dev (%s) doesn't list the devi"
1116 " (%s at %s)", d->d_name, i->i_name, i->i_at);
1117 f = *ppi;
1118 if (f == i)
1119 /* That implies d->d_ihead == i */
1120 *ppi = j;
1121 else
1122 (*ppi)->i_bsame = j;
1123 if (d->d_ipp == &i->i_bsame) {
1124 if (i->i_alias == NULL) {
1125 if (f == i)
1126 d->d_ipp = &d->d_ihead;
1127 else
1128 d->d_ipp = &f->i_bsame;
1129 } else
1130 d->d_ipp = &i->i_alias->i_bsame;
1131 }
1132 }
1133 /*
1134 * - delete the attachment instance
1135 */
1136 iba = i->i_atdeva;
1137 for (ppi = &iba->d_ihead;
1138 *ppi != NULL && *ppi != i && (*ppi)->i_asame != i;
1139 ppi = &(*ppi)->i_asame);
1140 if (*ppi == NULL)
1141 panic("deldev: deva (%s) doesn't list the devi (%s)",
1142 iba->d_name, i->i_name);
1143 f = *ppi;
1144 if (f == i)
1145 /* That implies iba->d_ihead == i */
1146 *ppi = i->i_asame;
1147 else
1148 (*ppi)->i_asame = i->i_asame;
1149 if (iba->d_ipp == &i->i_asame) {
1150 if (f == i)
1151 iba->d_ipp = &iba->d_ihead;
1152 else
1153 iba->d_ipp = &f->i_asame;
1154 }
1155 /*
1156 * - delete the pspec
1157 */
1158 if (i->i_pspec) {
1159 struct pspec *p = i->i_pspec;
1160 struct nvlist *nv, *onv;
1161
1162 /* Double-linked nvlist anyone? */
1163 for (nv = p->p_devs; nv->nv_ptr != NULL; nv = nv->nv_next) {
1164 if (nv->nv_next && nv->nv_next->nv_ptr == i) {
1165 onv = nv->nv_next;
1166 nv->nv_next = onv->nv_next;
1167 nvfree(onv);
1168 break;
1169 } if (nv->nv_ptr == i) {
1170 /* nv is p->p_devs in that case */
1171 p->p_devs = nv->nv_next;
1172 nvfree(nv);
1173 break;
1174 }
1175 }
1176 if (p->p_devs == NULL)
1177 TAILQ_REMOVE(&allpspecs, p, p_list);
1178 }
1179 /*
1180 * - delete the alldevi entry
1181 */
1182 TAILQ_REMOVE(&alldevi, i, i_next);
1183 ndevi--;
1184 free(i);
1185 /*
1186 * - reconstuct d->d_umax
1187 */
1188 d->d_umax = 0;
1189 for (i = d->d_ihead; i != NULL; i = i->i_bsame)
1190 if (i->i_unit >= d->d_umax)
1191 d->d_umax = i->i_unit + 1;
1192 }
1193
1194 void
1195 deldeva(const char *at)
1196 {
1197 int unit;
1198 const char *cp;
1199 struct devbase *d, *ad;
1200 struct devi *i, *j;
1201 struct attr *a;
1202 struct pspec *p;
1203 struct nvlist *nv, *stack = NULL;
1204
1205 if (at == NULL) {
1206 TAILQ_FOREACH(i, &alldevi, i_next)
1207 if (i->i_at == NULL)
1208 stack = newnv(NULL, NULL, i, 0, stack);
1209 } else {
1210 int l;
1211
1212 l = strlen(at) - 1;
1213 if (at[l] == '?' || isdigit((unsigned char)at[l])) {
1214 char base[NAMESIZE];
1215
1216 if (split(at, l+1, base, sizeof base, &unit)) {
1217 error("invalid attachment name `%s'", at);
1218 return;
1219 }
1220 cp = intern(base);
1221 } else {
1222 cp = intern(at);
1223 unit = STAR;
1224 }
1225
1226 ad = ht_lookup(devbasetab, cp);
1227 a = ht_lookup(attrtab, cp);
1228 if (a == NULL) {
1229 error("unknown attachment attribute or device `%s'",
1230 cp);
1231 return;
1232 }
1233 if (!a->a_iattr) {
1234 error("plain attribute `%s' cannot have children",
1235 a->a_name);
1236 return;
1237 }
1238
1239 /*
1240 * remove_devi() makes changes to the devbase's list and the
1241 * alias list, * so the actual deletion of the instances must
1242 * be delayed.
1243 */
1244 for (nv = a->a_devs; nv != NULL; nv = nv->nv_next) {
1245 d = nv->nv_ptr;
1246 for (i = d->d_ihead; i != NULL; i = i->i_bsame)
1247 for (j = i; j != NULL; j = j->i_alias) {
1248 /* Ignore devices at root */
1249 if (j->i_at == NULL)
1250 continue;
1251 p = j->i_pspec;
1252 /*
1253 * There are three cases:
1254 *
1255 * 1. unit is not STAR. Consider 'at'
1256 * to be explicit, even if it
1257 * references an interface
1258 * attribute.
1259 *
1260 * 2. unit is STAR and 'at' references
1261 * a real device. Look for pspec
1262 * that have a matching p_atdev
1263 * field.
1264 *
1265 * 3. unit is STAR and 'at' references
1266 * an interface attribute. Look
1267 * for pspec that have a matching
1268 * p_iattr field.
1269 */
1270 if ((unit != STAR && /* Case */
1271 !strcmp(j->i_at, at)) || /* 1 */
1272 (unit == STAR &&
1273 ((ad != NULL && /* Case */
1274 p->p_atdev == ad) || /* 2 */
1275 (ad == NULL && /* Case */
1276 p->p_iattr == a)))) /* 3 */
1277 stack = newnv(NULL, NULL, j, 0,
1278 stack);
1279 }
1280 }
1281 }
1282
1283 for (nv = stack; nv != NULL; nv = nv->nv_next)
1284 remove_devi(nv->nv_ptr);
1285 }
1286
1287 void
1288 deldev(const char *name)
1289 {
1290 int l;
1291 struct devi *firsti, *i;
1292 struct nvlist *nv, *stack = NULL;
1293
1294 l = strlen(name) - 1;
1295 if (name[l] == '*' || isdigit((unsigned char)name[l])) {
1296 /* `no mydev0' or `no mydev*' */
1297 firsti = ht_lookup(devitab, name);
1298 if (firsti == NULL) {
1299 error("unknown instance %s", name);
1300 return;
1301 }
1302 for (i = firsti; i != NULL; i = i->i_alias)
1303 stack = newnv(NULL, NULL, i, 0, stack);
1304 } else {
1305 struct devbase *d = ht_lookup(devbasetab, name);
1306
1307 if (d == NULL) {
1308 error("unknown device %s", name);
1309 return;
1310 }
1311
1312 for (firsti = d->d_ihead; firsti != NULL;
1313 firsti = firsti->i_bsame)
1314 for (i = firsti; i != NULL; i = i->i_alias)
1315 stack = newnv(NULL, NULL, i, 0, stack);
1316 }
1317
1318 for (nv = stack; nv != NULL; nv = nv->nv_next)
1319 remove_devi(nv->nv_ptr);
1320 }
1321
1322 void
1323 addpseudo(const char *name, int number)
1324 {
1325 struct devbase *d;
1326 struct devi *i;
1327
1328 d = ht_lookup(devbasetab, name);
1329 if (d == NULL) {
1330 error("undefined pseudo-device %s", name);
1331 return;
1332 }
1333 if (!d->d_ispseudo) {
1334 error("%s is a real device, not a pseudo-device", name);
1335 return;
1336 }
1337 if (ht_lookup(devitab, name) != NULL) {
1338 error("`%s' already defined", name);
1339 return;
1340 }
1341 i = newdevi(name, number - 1, d); /* foo 16 => "foo0..foo15" */
1342 if (ht_insert(devitab, name, i))
1343 panic("addpseudo(%s)", name);
1344 /* Useful to retrieve the instance from the devbase */
1345 d->d_ihead = i;
1346 i->i_active = 1;
1347 TAILQ_INSERT_TAIL(&allpseudo, i, i_next);
1348 }
1349
1350 void
1351 delpseudo(const char *name)
1352 {
1353 struct devbase *d;
1354 struct devi *i;
1355
1356 d = ht_lookup(devbasetab, name);
1357 if (d == NULL) {
1358 error("undefined pseudo-device %s", name);
1359 return;
1360 }
1361 if (!d->d_ispseudo) {
1362 error("%s is a real device, not a pseudo-device", name);
1363 return;
1364 }
1365 if ((i = ht_lookup(devitab, name)) == NULL) {
1366 error("`%s' not defined", name);
1367 return;
1368 }
1369 d->d_umax = 0; /* clear neads-count entries */
1370 TAILQ_REMOVE(&allpseudo, i, i_next);
1371 if (ht_remove(devitab, name))
1372 panic("delpseudo(%s) - can't remove from devitab", name);
1373 }
1374
1375 void
1376 adddevm(const char *name, int cmajor, int bmajor, struct nvlist *options)
1377 {
1378 struct devm *dm;
1379
1380 if (cmajor < -1 || cmajor >= 4096) {
1381 error("character major %d is invalid", cmajor);
1382 nvfreel(options);
1383 return;
1384 }
1385
1386 if (bmajor < -1 || bmajor >= 4096) {
1387 error("block major %d is invalid", bmajor);
1388 nvfreel(options);
1389 return;
1390 }
1391 if (cmajor == -1 && bmajor == -1) {
1392 error("both character/block majors are not specified");
1393 nvfreel(options);
1394 return;
1395 }
1396
1397 dm = ecalloc(1, sizeof(*dm));
1398 dm->dm_srcfile = yyfile;
1399 dm->dm_srcline = currentline();
1400 dm->dm_name = name;
1401 dm->dm_cmajor = cmajor;
1402 dm->dm_bmajor = bmajor;
1403 dm->dm_opts = options;
1404
1405 TAILQ_INSERT_TAIL(&alldevms, dm, dm_next);
1406
1407 maxcdevm = MAX(maxcdevm, dm->dm_cmajor);
1408 maxbdevm = MAX(maxbdevm, dm->dm_bmajor);
1409 }
1410
1411 void
1412 fixdevis(void)
1413 {
1414 struct devi *i;
1415
1416 TAILQ_FOREACH(i, &alldevi, i_next)
1417 if (i->i_active)
1418 selectbase(i->i_base, i->i_atdeva);
1419 else
1420 /*
1421 * At this point, we can't have instances for which
1422 * i_at or i_pspec are NULL.
1423 */
1424 (void)fprintf(stderr,
1425 "%s:%d: `%s at %s' is orphaned"
1426 " (%s `%s' found)\n", conffile, i->i_lineno,
1427 i->i_name, i->i_at, i->i_pspec->p_atunit == WILD ?
1428 "nothing matching" : "no", i->i_at);
1429
1430 TAILQ_FOREACH(i, &allpseudo, i_next)
1431 if (i->i_active)
1432 selectbase(i->i_base, NULL);
1433 }
1434
1435 /*
1436 * Look up a parent spec, creating a new one if it does not exist.
1437 */
1438 static struct pspec *
1439 getpspec(struct attr *attr, struct devbase *ab, int atunit)
1440 {
1441 struct pspec *p;
1442
1443 TAILQ_FOREACH(p, &allpspecs, p_list) {
1444 if (p->p_iattr == attr &&
1445 p->p_atdev == ab &&
1446 p->p_atunit == atunit)
1447 return (p);
1448 }
1449
1450 p = ecalloc(1, sizeof(*p));
1451
1452 p->p_iattr = attr;
1453 p->p_atdev = ab;
1454 p->p_atunit = atunit;
1455 p->p_inst = npspecs++;
1456 p->p_active = 0;
1457
1458 TAILQ_INSERT_TAIL(&allpspecs, p, p_list);
1459
1460 return (p);
1461 }
1462
1463 /*
1464 * Define a new instance of a specific device.
1465 */
1466 static struct devi *
1467 getdevi(const char *name)
1468 {
1469 struct devi *i, *firsti;
1470 struct devbase *d;
1471 int unit;
1472 char base[NAMESIZE];
1473
1474 if (split(name, strlen(name), base, sizeof base, &unit)) {
1475 error("invalid device name `%s'", name);
1476 return (NULL);
1477 }
1478 d = ht_lookup(devbasetab, intern(base));
1479 if (d == NULL) {
1480 error("%s: unknown device `%s'", name, base);
1481 return (NULL);
1482 }
1483 if (d->d_ispseudo) {
1484 error("%s: %s is a pseudo-device", name, base);
1485 return (NULL);
1486 }
1487 firsti = ht_lookup(devitab, name);
1488 i = newdevi(name, unit, d);
1489 if (firsti == NULL) {
1490 if (ht_insert(devitab, name, i))
1491 panic("getdevi(%s)", name);
1492 *d->d_ipp = i;
1493 d->d_ipp = &i->i_bsame;
1494 } else {
1495 while (firsti->i_alias)
1496 firsti = firsti->i_alias;
1497 firsti->i_alias = i;
1498 }
1499 TAILQ_INSERT_TAIL(&alldevi, i, i_next);
1500 ndevi++;
1501 return (i);
1502 }
1503
1504 static const char *
1505 concat(const char *name, int c)
1506 {
1507 int len;
1508 char buf[NAMESIZE];
1509
1510 len = strlen(name);
1511 if (len + 2 > sizeof(buf)) {
1512 error("device name `%s%c' too long", name, c);
1513 len = sizeof(buf) - 2;
1514 }
1515 memmove(buf, name, len);
1516 buf[len] = c;
1517 buf[len + 1] = 0;
1518 return (intern(buf));
1519 }
1520
1521 const char *
1522 starref(const char *name)
1523 {
1524
1525 return (concat(name, '*'));
1526 }
1527
1528 const char *
1529 wildref(const char *name)
1530 {
1531
1532 return (concat(name, '?'));
1533 }
1534
1535 /*
1536 * Split a name like "foo0" into base name (foo) and unit number (0).
1537 * Return 0 on success. To make this useful for names like "foo0a",
1538 * the length of the "foo0" part is one of the arguments.
1539 */
1540 static int
1541 split(const char *name, size_t nlen, char *base, size_t bsize, int *aunit)
1542 {
1543 const char *cp;
1544 int c, l;
1545
1546 l = nlen;
1547 if (l < 2 || l >= bsize || isdigit((unsigned char)*name))
1548 return (1);
1549 c = (u_char)name[--l];
1550 if (!isdigit(c)) {
1551 if (c == '*')
1552 *aunit = STAR;
1553 else if (c == '?')
1554 *aunit = WILD;
1555 else
1556 return (1);
1557 } else {
1558 cp = &name[l];
1559 while (isdigit((unsigned char)cp[-1]))
1560 l--, cp--;
1561 *aunit = atoi(cp);
1562 }
1563 memmove(base, name, l);
1564 base[l] = 0;
1565 return (0);
1566 }
1567
1568 void
1569 selectattr(struct attr *a)
1570 {
1571
1572 (void)ht_insert(selecttab, a->a_name, (char *)a->a_name);
1573 }
1574
1575 /*
1576 * We have an instance of the base foo, so select it and all its
1577 * attributes for "optional foo".
1578 */
1579 static void
1580 selectbase(struct devbase *d, struct deva *da)
1581 {
1582 struct attr *a;
1583 struct nvlist *nv;
1584
1585 (void)ht_insert(selecttab, d->d_name, (char *)d->d_name);
1586 for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) {
1587 a = nv->nv_ptr;
1588 expandattr(a, selectattr);
1589 }
1590 if (da != NULL) {
1591 (void)ht_insert(selecttab, da->d_name, (char *)da->d_name);
1592 for (nv = da->d_attrs; nv != NULL; nv = nv->nv_next) {
1593 a = nv->nv_ptr;
1594 expandattr(a, selectattr);
1595 }
1596 }
1597 }
1598
1599 /*
1600 * Is the given pointer on the given list of pointers?
1601 */
1602 static int
1603 onlist(struct nvlist *nv, void *ptr)
1604 {
1605 for (; nv != NULL; nv = nv->nv_next)
1606 if (nv->nv_ptr == ptr)
1607 return (1);
1608 return (0);
1609 }
1610
1611 static char *
1612 extend(char *p, const char *name)
1613 {
1614 int l;
1615
1616 l = strlen(name);
1617 memmove(p, name, l);
1618 p += l;
1619 *p++ = ',';
1620 *p++ = ' ';
1621 return (p);
1622 }
1623
1624 /*
1625 * Check that we got all required locators, and default any that are
1626 * given as "?" and have defaults. Return 0 on success.
1627 */
1628 static const char **
1629 fixloc(const char *name, struct attr *attr, struct nvlist *got)
1630 {
1631 struct nvlist *m, *n;
1632 int ord;
1633 const char **lp;
1634 int nmissing, nextra, nnodefault;
1635 char *mp, *ep, *ndp;
1636 char missing[1000], extra[1000], nodefault[1000];
1637 static const char *nullvec[1];
1638
1639 /*
1640 * Look for all required locators, and number the given ones
1641 * according to the required order. While we are numbering,
1642 * set default values for defaulted locators.
1643 */
1644 if (attr->a_loclen == 0) /* e.g., "at root" */
1645 lp = nullvec;
1646 else
1647 lp = emalloc((attr->a_loclen + 1) * sizeof(const char *));
1648 for (n = got; n != NULL; n = n->nv_next)
1649 n->nv_int = -1;
1650 nmissing = 0;
1651 mp = missing;
1652 /* yes, this is O(mn), but m and n should be small */
1653 for (ord = 0, m = attr->a_locs; m != NULL; m = m->nv_next, ord++) {
1654 for (n = got; n != NULL; n = n->nv_next) {
1655 if (n->nv_name == m->nv_name) {
1656 n->nv_int = ord;
1657 break;
1658 }
1659 }
1660 if (n == NULL && m->nv_int == 0) {
1661 nmissing++;
1662 mp = extend(mp, m->nv_name);
1663 }
1664 lp[ord] = m->nv_str;
1665 }
1666 if (ord != attr->a_loclen)
1667 panic("fixloc");
1668 lp[ord] = NULL;
1669 nextra = 0;
1670 ep = extra;
1671 nnodefault = 0;
1672 ndp = nodefault;
1673 for (n = got; n != NULL; n = n->nv_next) {
1674 if (n->nv_int >= 0) {
1675 if (n->nv_str != NULL)
1676 lp[n->nv_int] = n->nv_str;
1677 else if (lp[n->nv_int] == NULL) {
1678 nnodefault++;
1679 ndp = extend(ndp, n->nv_name);
1680 }
1681 } else {
1682 nextra++;
1683 ep = extend(ep, n->nv_name);
1684 }
1685 }
1686 if (nextra) {
1687 ep[-2] = 0; /* kill ", " */
1688 error("%s: extraneous locator%s: %s",
1689 name, nextra > 1 ? "s" : "", extra);
1690 }
1691 if (nmissing) {
1692 mp[-2] = 0;
1693 error("%s: must specify %s", name, missing);
1694 }
1695 if (nnodefault) {
1696 ndp[-2] = 0;
1697 error("%s: cannot wildcard %s", name, nodefault);
1698 }
1699 if (nmissing || nnodefault) {
1700 free(lp);
1701 lp = NULL;
1702 }
1703 return (lp);
1704 }
1705