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