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