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