xref: /csrg-svn/usr.sbin/config.new/sem.c (revision 57495)
1*57495Storek /*
2*57495Storek  * Copyright (c) 1992 The Regents of the University of California.
3*57495Storek  * All rights reserved.
4*57495Storek  *
5*57495Storek  * This software was developed by the Computer Systems Engineering group
6*57495Storek  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7*57495Storek  * contributed to Berkeley.
8*57495Storek  *
9*57495Storek  * All advertising materials mentioning features or use of this software
10*57495Storek  * must display the following acknowledgement:
11*57495Storek  *	This product includes software developed by the University of
12*57495Storek  *	California, Lawrence Berkeley Laboratories.
13*57495Storek  *
14*57495Storek  * %sccs.include.redist.c%
15*57495Storek  *
16*57495Storek  *	@(#)sem.c	5.1 (Berkeley) 01/12/93
17*57495Storek  *
18*57495Storek  * from: $Header: sem.c,v 1.5 93/01/12 03:57:11 torek Exp $
19*57495Storek  */
20*57495Storek 
21*57495Storek #include <sys/param.h>
22*57495Storek #include <ctype.h>
23*57495Storek #include <stdio.h>
24*57495Storek #include <stdlib.h>
25*57495Storek #include <string.h>
26*57495Storek #include "config.h"
27*57495Storek #include "sem.h"
28*57495Storek 
29*57495Storek /*
30*57495Storek  * config semantics.
31*57495Storek  */
32*57495Storek 
33*57495Storek #define	NAMESIZE	100	/* local name buffers */
34*57495Storek 
35*57495Storek static const char *s_generic;
36*57495Storek static const char *s_qmark;
37*57495Storek 
38*57495Storek static struct hashtab *attrtab;		/* for attribute lookup */
39*57495Storek static struct hashtab *cfhashtab;	/* for config lookup */
40*57495Storek static struct hashtab *devitab;		/* etc */
41*57495Storek 
42*57495Storek static struct attr errattr;
43*57495Storek static struct devbase errdev;
44*57495Storek static struct devbase **nextbase;
45*57495Storek static struct config **nextcf;
46*57495Storek static struct devi **nextdevi;
47*57495Storek static struct devi **nextpseudo;
48*57495Storek 
49*57495Storek static int has_errobj __P((struct nvlist *, void *));
50*57495Storek static struct nvlist *addtoattr __P((struct nvlist *, struct devbase *));
51*57495Storek static int exclude __P((struct nvlist *, const char *, const char *));
52*57495Storek static int resolve __P((struct nvlist **, const char *, const char *,
53*57495Storek 			struct nvlist *, int));
54*57495Storek static int lresolve __P((struct nvlist **, const char *, const char *,
55*57495Storek 			struct nvlist *, int));
56*57495Storek static struct devi *newdevi __P((const char *, int, struct devbase *d));
57*57495Storek static struct devi *getdevi __P((const char *));
58*57495Storek static const char *concat __P((const char *, int));
59*57495Storek static int split __P((const char *, size_t, char *, size_t, int *));
60*57495Storek static void selectbase __P((struct devbase *));
61*57495Storek static int onlist __P((struct nvlist *, void *));
62*57495Storek static const char **fixloc __P((const char *, struct attr *, struct nvlist *));
63*57495Storek 
64*57495Storek void
65*57495Storek initsem()
66*57495Storek {
67*57495Storek 
68*57495Storek 	attrtab = ht_new();
69*57495Storek 	errattr.a_name = "<internal>";
70*57495Storek 
71*57495Storek 	allbases = NULL;
72*57495Storek 	nextbase = &allbases;
73*57495Storek 
74*57495Storek 	cfhashtab = ht_new();
75*57495Storek 	allcf = NULL;
76*57495Storek 	nextcf = &allcf;
77*57495Storek 
78*57495Storek 	devitab = ht_new();
79*57495Storek 	alldevi = NULL;
80*57495Storek 	nextdevi = &alldevi;
81*57495Storek 	errdev.d_name = "<internal>";
82*57495Storek 
83*57495Storek 	allpseudo = NULL;
84*57495Storek 	nextpseudo = &allpseudo;
85*57495Storek 
86*57495Storek 	s_generic = intern("generic");
87*57495Storek 	s_qmark = intern("?");
88*57495Storek }
89*57495Storek 
90*57495Storek void
91*57495Storek enddefs(fname)
92*57495Storek 	const char *fname;
93*57495Storek {
94*57495Storek 	register struct devbase *dev;
95*57495Storek 
96*57495Storek 	for (dev = allbases; dev != NULL; dev = dev->d_next) {
97*57495Storek 		if (!dev->d_isdef) {
98*57495Storek 			(void)fprintf(stderr,
99*57495Storek 			    "%s: device `%s' used but not defined\n",
100*57495Storek 			    fname, dev->d_name);
101*57495Storek 			errors++;
102*57495Storek 			continue;
103*57495Storek 		}
104*57495Storek 	}
105*57495Storek 	if (errors) {
106*57495Storek 		(void)fprintf(stderr, "*** Stop.\n");
107*57495Storek 		exit(1);
108*57495Storek 	}
109*57495Storek }
110*57495Storek 
111*57495Storek void
112*57495Storek setdefmaxusers(min, def, max)
113*57495Storek 	int min, def, max;
114*57495Storek {
115*57495Storek 
116*57495Storek 	if (min < 1 || min > def || def > max)
117*57495Storek 		error("maxusers must have 1 <= min <= default <= max");
118*57495Storek 	else {
119*57495Storek 		minmaxusers = min;
120*57495Storek 		defmaxusers = def;
121*57495Storek 		maxmaxusers = max;
122*57495Storek 	}
123*57495Storek }
124*57495Storek 
125*57495Storek void
126*57495Storek setmaxusers(n)
127*57495Storek 	int n;
128*57495Storek {
129*57495Storek 
130*57495Storek 	if (maxusers != 0) {
131*57495Storek 		error("duplicate maxusers parameter");
132*57495Storek 		return;
133*57495Storek 	}
134*57495Storek 	maxusers = n;
135*57495Storek 	if (n < minmaxusers) {
136*57495Storek 		error("warning: minimum of %d maxusers assumed\n", minmaxusers);
137*57495Storek 		errors--;	/* take it away */
138*57495Storek 		maxusers = minmaxusers;
139*57495Storek 	} else if (n > maxmaxusers) {
140*57495Storek 		error("warning: maxusers (%d) > %d", n, maxmaxusers);
141*57495Storek 		errors--;
142*57495Storek 	}
143*57495Storek }
144*57495Storek 
145*57495Storek /*
146*57495Storek  * Define an attribute, optionally with an interface (a locator list).
147*57495Storek  * Since an empty locator list is logically different from "no interface",
148*57495Storek  * all locator lists include a dummy head node, which we discard here.
149*57495Storek  */
150*57495Storek int
151*57495Storek defattr(name, locs)
152*57495Storek 	const char *name;
153*57495Storek 	struct nvlist *locs;
154*57495Storek {
155*57495Storek 	register struct attr *a;
156*57495Storek 	register struct nvlist *nv;
157*57495Storek 	register int len;
158*57495Storek 
159*57495Storek 	a = emalloc(sizeof *a);
160*57495Storek 	if (ht_insert(attrtab, name, a)) {
161*57495Storek 		free(a);
162*57495Storek 		error("attribute `%s' already defined", name);
163*57495Storek 		nvfreel(locs);
164*57495Storek 		return (1);
165*57495Storek 	}
166*57495Storek 	a->a_name = name;
167*57495Storek 	if (locs != NULL) {
168*57495Storek 		a->a_iattr = 1;
169*57495Storek 		a->a_locs = locs->nv_next;
170*57495Storek 		nvfree(locs);
171*57495Storek 	} else {
172*57495Storek 		a->a_iattr = 0;
173*57495Storek 		a->a_locs = NULL;
174*57495Storek 	}
175*57495Storek 	len = 0;
176*57495Storek 	for (nv = a->a_locs; nv != NULL; nv = nv->nv_next)
177*57495Storek 		len++;
178*57495Storek 	a->a_loclen = len;
179*57495Storek 	a->a_devs = NULL;
180*57495Storek 	a->a_refs = NULL;
181*57495Storek 	return (0);
182*57495Storek }
183*57495Storek 
184*57495Storek /*
185*57495Storek  * Return true if the given `error object' is embedded in the given
186*57495Storek  * pointer list.
187*57495Storek  */
188*57495Storek static int
189*57495Storek has_errobj(nv, obj)
190*57495Storek 	register struct nvlist *nv;
191*57495Storek 	register void *obj;
192*57495Storek {
193*57495Storek 
194*57495Storek 	for (; nv != NULL; nv = nv->nv_next)
195*57495Storek 		if (nv->nv_ptr == obj)
196*57495Storek 			return (1);
197*57495Storek 	return (0);
198*57495Storek }
199*57495Storek 
200*57495Storek /*
201*57495Storek  * Add a device base to a list in an attribute (actually, to any list).
202*57495Storek  * Note that this does not check for duplicates, and does reverse the
203*57495Storek  * list order, but no one cares anyway.
204*57495Storek  */
205*57495Storek static struct nvlist *
206*57495Storek addtoattr(l, dev)
207*57495Storek 	register struct nvlist *l;
208*57495Storek 	register struct devbase *dev;
209*57495Storek {
210*57495Storek 	register struct nvlist *n;
211*57495Storek 
212*57495Storek 	n = newnv(NULL, NULL, dev, 0);
213*57495Storek 	n->nv_next = l;
214*57495Storek 	return (n);
215*57495Storek }
216*57495Storek 
217*57495Storek /*
218*57495Storek  * Device a device, giving its allowable parent attachments, if any.
219*57495Storek  * This may (or may not) also define an interface attribute and/or refer
220*57495Storek  * to existing attributes.  There may be a list of vectors.
221*57495Storek  */
222*57495Storek void
223*57495Storek defdev(dev, ispseudo, atlist, vectors, loclist, attrs)
224*57495Storek 	register struct devbase *dev;
225*57495Storek 	int ispseudo;
226*57495Storek 	struct nvlist *atlist, *vectors, *loclist, *attrs;
227*57495Storek {
228*57495Storek 	register struct nvlist *nv;
229*57495Storek 	register struct attr *a;
230*57495Storek 
231*57495Storek 	if (dev == &errdev)
232*57495Storek 		goto bad;
233*57495Storek 	if (dev->d_isdef) {
234*57495Storek 		error("redefinition of `%s'", dev->d_name);
235*57495Storek 		goto bad;
236*57495Storek 	}
237*57495Storek 	dev->d_isdef = 1;
238*57495Storek 	if (has_errobj(attrs, &errattr))
239*57495Storek 		goto bad;
240*57495Storek 
241*57495Storek 	/*
242*57495Storek 	 * Handle implicit attribute definition from locator list.  Do
243*57495Storek 	 * this before scanning the `at' list so that we can have, e.g.:
244*57495Storek 	 *	device foo at other, foo { slot = -1 }
245*57495Storek 	 * (where you can plug in a foo-bus extender to a foo-bus).
246*57495Storek 	 */
247*57495Storek 	if (loclist != NULL) {
248*57495Storek 		nv = loclist;
249*57495Storek 		loclist = NULL;	/* defattr disposes of them for us */
250*57495Storek 		if (defattr(dev->d_name, nv))
251*57495Storek 			goto bad;
252*57495Storek 		nv = newnv(dev->d_name, NULL, getattr(dev->d_name), 0);
253*57495Storek 		nv->nv_next = attrs;
254*57495Storek 		attrs = nv;
255*57495Storek 	}
256*57495Storek 
257*57495Storek 	/* Committed!  Set up fields. */
258*57495Storek 	dev->d_ispseudo = ispseudo;
259*57495Storek 	dev->d_atlist = atlist;
260*57495Storek 	dev->d_vectors = vectors;
261*57495Storek 	dev->d_attrs = attrs;
262*57495Storek 
263*57495Storek 	/*
264*57495Storek 	 * Turn the `at' list into interface attributes (map each
265*57495Storek 	 * nv_name to an attribute, or to NULL for root), and add
266*57495Storek 	 * this device to those attributes, so that children can
267*57495Storek 	 * be listed at this particular device if they are supported
268*57495Storek 	 * by that attribute.
269*57495Storek 	 */
270*57495Storek 	for (nv = atlist; nv != NULL; nv = nv->nv_next) {
271*57495Storek 		if (nv->nv_name == NULL) {
272*57495Storek 			nv->nv_ptr = NULL;	/* at root */
273*57495Storek 			continue;
274*57495Storek 		}
275*57495Storek 		nv->nv_ptr = a = getattr(nv->nv_name);
276*57495Storek 		if (a == &errattr)
277*57495Storek 			continue;		/* already complained */
278*57495Storek 		if (!a->a_iattr)
279*57495Storek 			error("%s cannot be at plain attribute `%s'",
280*57495Storek 			    dev->d_name, a->a_name);
281*57495Storek 		else
282*57495Storek 			a->a_devs = addtoattr(a->a_devs, dev);
283*57495Storek 	}
284*57495Storek 
285*57495Storek 	/*
286*57495Storek 	 * For each interface attribute this device refers to, add this
287*57495Storek 	 * device to its reference list.  This makes, e.g., finding all
288*57495Storek 	 * "scsi"s easier.
289*57495Storek 	 */
290*57495Storek 	for (nv = attrs; nv != NULL; nv = nv->nv_next) {
291*57495Storek 		a = nv->nv_ptr;
292*57495Storek 		if (a->a_iattr)
293*57495Storek 			a->a_refs = addtoattr(a->a_refs, dev);
294*57495Storek 	}
295*57495Storek 	return;
296*57495Storek bad:
297*57495Storek 	nvfreel(atlist);
298*57495Storek 	nvfreel(vectors);
299*57495Storek 	nvfreel(loclist);
300*57495Storek 	nvfreel(attrs);
301*57495Storek }
302*57495Storek 
303*57495Storek /*
304*57495Storek  * Look up a devbase.  Also makes sure it is a reasonable name,
305*57495Storek  * i.e., does not end in a digit or contain special characters.
306*57495Storek  */
307*57495Storek struct devbase *
308*57495Storek getdevbase(name)
309*57495Storek 	const char *name;
310*57495Storek {
311*57495Storek 	register u_char *p;
312*57495Storek 	register struct devbase *dev;
313*57495Storek 
314*57495Storek 	p = (u_char *)name;
315*57495Storek 	if (!isalpha(*p))
316*57495Storek 		goto badname;
317*57495Storek 	while (*++p) {
318*57495Storek 		if (!isalnum(*p) && *p != '_')
319*57495Storek 			goto badname;
320*57495Storek 	}
321*57495Storek 	if (isdigit(*--p)) {
322*57495Storek badname:
323*57495Storek 		error("bad device base name `%s'", name);
324*57495Storek 		return (&errdev);
325*57495Storek 	}
326*57495Storek 	dev = ht_lookup(devbasetab, name);
327*57495Storek 	if (dev == NULL) {
328*57495Storek 		dev = emalloc(sizeof *dev);
329*57495Storek 		dev->d_name = name;
330*57495Storek 		dev->d_next = NULL;
331*57495Storek 		dev->d_isdef = 0;
332*57495Storek 		dev->d_major = NODEV;
333*57495Storek 		dev->d_atlist = NULL;
334*57495Storek 		dev->d_vectors = NULL;
335*57495Storek 		dev->d_attrs = NULL;
336*57495Storek 		dev->d_ihead = NULL;
337*57495Storek 		dev->d_ipp = &dev->d_ihead;
338*57495Storek 		dev->d_umax = 0;
339*57495Storek 		*nextbase = dev;
340*57495Storek 		nextbase = &dev->d_next;
341*57495Storek 		if (ht_insert(devbasetab, name, dev))
342*57495Storek 			panic("getdevbase(%s)", name);
343*57495Storek 	}
344*57495Storek 	return (dev);
345*57495Storek }
346*57495Storek 
347*57495Storek /*
348*57495Storek  * Look up an attribute.
349*57495Storek  */
350*57495Storek struct attr *
351*57495Storek getattr(name)
352*57495Storek 	const char *name;
353*57495Storek {
354*57495Storek 	struct attr *a;
355*57495Storek 
356*57495Storek 	if ((a = ht_lookup(attrtab, name)) == NULL) {
357*57495Storek 		error("undefined attribute `%s'", name);
358*57495Storek 		a = &errattr;
359*57495Storek 	}
360*57495Storek 	return (a);
361*57495Storek }
362*57495Storek 
363*57495Storek /*
364*57495Storek  * Set the major device number for a device, so that it can be used
365*57495Storek  * as a root/swap/dumps "on" device in a configuration.
366*57495Storek  */
367*57495Storek void
368*57495Storek setmajor(d, n)
369*57495Storek 	struct devbase *d;
370*57495Storek 	int n;
371*57495Storek {
372*57495Storek 
373*57495Storek 	if (d != &errdev && d->d_major != NODEV)
374*57495Storek 		error("device `%s' is already major %d",
375*57495Storek 		    d->d_name, d->d_major);
376*57495Storek 	else
377*57495Storek 		d->d_major = n;
378*57495Storek }
379*57495Storek 
380*57495Storek #define ABS(x) ((x) < 0 ? -(x) : (x))
381*57495Storek 
382*57495Storek static int
383*57495Storek exclude(nv, name, what)
384*57495Storek 	struct nvlist *nv;
385*57495Storek 	const char *name, *what;
386*57495Storek {
387*57495Storek 
388*57495Storek 	if (nv != NULL) {
389*57495Storek 		error("%s: swap generic must not specify %s", name, what);
390*57495Storek 		return (1);
391*57495Storek 	}
392*57495Storek 	return (0);
393*57495Storek }
394*57495Storek 
395*57495Storek /*
396*57495Storek  * Map things like "ra0b" => makedev(major("ra"), 0*8 + 'b'-'a').
397*57495Storek  * Handle the case where the device number is given but there is no
398*57495Storek  * corresponding name, and map NULL to the default.
399*57495Storek  */
400*57495Storek static int
401*57495Storek resolve(nvp, name, what, dflt, part)
402*57495Storek 	register struct nvlist **nvp;
403*57495Storek 	const char *name, *what;
404*57495Storek 	struct nvlist *dflt;
405*57495Storek 	register int part;
406*57495Storek {
407*57495Storek 	register struct nvlist *nv;
408*57495Storek 	register struct devbase *dev;
409*57495Storek 	register const char *cp;
410*57495Storek 	register int maj, min, l;
411*57495Storek 	int unit;
412*57495Storek 	char buf[NAMESIZE];
413*57495Storek 
414*57495Storek 	if ((u_int)(part -= 'a') >= 7)
415*57495Storek 		panic("resolve");
416*57495Storek 	if ((nv = *nvp) == NULL) {
417*57495Storek 		/*
418*57495Storek 		 * Apply default.  Easiest to do this by number.
419*57495Storek 		 */
420*57495Storek 		maj = major(dflt->nv_int);
421*57495Storek 		min = (minor(dflt->nv_int) & ~7) | part;
422*57495Storek 		*nvp = nv = newnv(NULL, NULL, NULL, makedev(maj, min));
423*57495Storek 	}
424*57495Storek 	if (nv->nv_int != NODEV) {
425*57495Storek 		/*
426*57495Storek 		 * By the numbers.  Find the appropriate major number
427*57495Storek 		 * to make a name.
428*57495Storek 		 */
429*57495Storek 		maj = major(nv->nv_int);
430*57495Storek 		min = minor(nv->nv_int);
431*57495Storek 		for (dev = allbases; dev != NULL; dev = dev->d_next)
432*57495Storek 			if (dev->d_major == maj)
433*57495Storek 				break;
434*57495Storek 		if (dev == NULL)
435*57495Storek 			(void)sprintf(buf, "<%d/%d>", maj, min);
436*57495Storek 		else
437*57495Storek 			(void)sprintf(buf, "%s%d%c", dev->d_name,
438*57495Storek 			    min >> 3, (min & 7) + 'a');
439*57495Storek 		nv->nv_str = intern(buf);
440*57495Storek 		return (0);
441*57495Storek 	}
442*57495Storek 
443*57495Storek 	/*
444*57495Storek 	 * The normal case: things like "ra2b".  Check for partition
445*57495Storek 	 * suffix, remove it if there, and split into name ("ra") and
446*57495Storek 	 * unit (2).
447*57495Storek 	 */
448*57495Storek 	l = strlen(nv->nv_str);
449*57495Storek 	cp = &nv->nv_str[l];
450*57495Storek 	if (l > 1 && *--cp >= 'a' && *cp <= 'h' && isdigit(cp[-1])) {
451*57495Storek 		l--;
452*57495Storek 		part = *cp - 'a';
453*57495Storek 	}
454*57495Storek 	cp = nv->nv_str;
455*57495Storek 	if (split(cp, l, buf, sizeof buf, &unit)) {
456*57495Storek 		error("%s: invalid %s device name `%s'", name, what, cp);
457*57495Storek 		return (1);
458*57495Storek 	}
459*57495Storek 	dev = ht_lookup(devbasetab, intern(buf));
460*57495Storek 	if (dev == NULL || dev->d_major == NODEV) {
461*57495Storek 		error("%s: can't make %s device from `%s'",
462*57495Storek 		    name, what, nv->nv_str);
463*57495Storek 		return (1);
464*57495Storek 	}
465*57495Storek 	nv->nv_name = dev->d_name;
466*57495Storek 	nv->nv_int = makedev(dev->d_major, unit * 8 + part);
467*57495Storek 	return (0);
468*57495Storek }
469*57495Storek 
470*57495Storek static int
471*57495Storek lresolve(nvp, name, what, dflt, part)
472*57495Storek 	register struct nvlist **nvp;
473*57495Storek 	const char *name, *what;
474*57495Storek 	struct nvlist *dflt;
475*57495Storek 	int part;
476*57495Storek {
477*57495Storek 	int err;
478*57495Storek 
479*57495Storek 	while ((err = resolve(nvp, name, what, dflt, part)) == 0 &&
480*57495Storek 	    (*nvp)->nv_next != NULL)
481*57495Storek 		nvp = &(*nvp)->nv_next;
482*57495Storek 	return (err);
483*57495Storek }
484*57495Storek 
485*57495Storek /*
486*57495Storek  * Add a completed configuration to the list.
487*57495Storek  */
488*57495Storek void
489*57495Storek addconf(cf0)
490*57495Storek 	register struct config *cf0;
491*57495Storek {
492*57495Storek 	register struct config *cf;
493*57495Storek 	register struct nvlist *nv;
494*57495Storek 	const char *name;
495*57495Storek 
496*57495Storek 	name = cf0->cf_name;
497*57495Storek 	cf = emalloc(sizeof *cf);
498*57495Storek 	if (ht_insert(cfhashtab, name, cf)) {
499*57495Storek 		error("configuration `%s' already defined", name);
500*57495Storek 		free(cf);
501*57495Storek 		goto bad;
502*57495Storek 	}
503*57495Storek 	*cf = *cf0;
504*57495Storek 
505*57495Storek 	/*
506*57495Storek 	 * Look for "swap generic".
507*57495Storek 	 */
508*57495Storek 	for (nv = cf->cf_swap; nv != NULL; nv = nv->nv_next)
509*57495Storek 		if (nv->nv_str == s_generic)
510*57495Storek 			break;
511*57495Storek 	if (nv != NULL) {
512*57495Storek 		/*
513*57495Storek 		 * Make sure no root or dump device specified, and no
514*57495Storek 		 * other swap devices.  Note single | here (check all).
515*57495Storek 		 */
516*57495Storek 		nv = cf->cf_swap;
517*57495Storek 		if (exclude(cf->cf_root, name, "root device") |
518*57495Storek 		    exclude(nv->nv_next, name, "additional swap devices") |
519*57495Storek 		    exclude(cf->cf_dump, name, "dump device"))
520*57495Storek 			goto bad;
521*57495Storek 	} else {
522*57495Storek 		nv = cf->cf_root;
523*57495Storek 		if (nv == NULL) {
524*57495Storek 			error("%s: no root device specified", name);
525*57495Storek 			goto bad;
526*57495Storek 		}
527*57495Storek 		if (resolve(&cf->cf_root, name, "root", nv, 'a') |
528*57495Storek 		    lresolve(&cf->cf_swap, name, "swap", nv, 'b') |
529*57495Storek 		    resolve(&cf->cf_dump, name, "dumps", nv, 'b'))
530*57495Storek 			goto bad;
531*57495Storek 	}
532*57495Storek 	*nextcf = cf;
533*57495Storek 	nextcf = &cf->cf_next;
534*57495Storek 	return;
535*57495Storek bad:
536*57495Storek 	nvfreel(cf0->cf_root);
537*57495Storek 	nvfreel(cf0->cf_swap);
538*57495Storek 	nvfreel(cf0->cf_dump);
539*57495Storek }
540*57495Storek 
541*57495Storek void
542*57495Storek setconf(npp, what, v)
543*57495Storek 	register struct nvlist **npp;
544*57495Storek 	const char *what;
545*57495Storek 	struct nvlist *v;
546*57495Storek {
547*57495Storek 
548*57495Storek 	if (*npp != NULL) {
549*57495Storek 		error("duplicate %s specification", what);
550*57495Storek 		nvfreel(v);
551*57495Storek 	} else
552*57495Storek 		*npp = v;
553*57495Storek }
554*57495Storek 
555*57495Storek static struct devi *
556*57495Storek newdevi(name, unit, d)
557*57495Storek 	const char *name;
558*57495Storek 	int unit;
559*57495Storek 	struct devbase *d;
560*57495Storek {
561*57495Storek 	register struct devi *i;
562*57495Storek 
563*57495Storek 	i = emalloc(sizeof *i);
564*57495Storek 	i->i_name = name;
565*57495Storek 	i->i_unit = unit;
566*57495Storek 	i->i_base = d;
567*57495Storek 	i->i_next = NULL;
568*57495Storek 	i->i_bsame = NULL;
569*57495Storek 	i->i_alias = NULL;
570*57495Storek 	i->i_at = NULL;
571*57495Storek 	i->i_atattr = NULL;
572*57495Storek 	i->i_atdev = NULL;
573*57495Storek 	i->i_locs = NULL;
574*57495Storek 	i->i_cfflags = 0;
575*57495Storek 	i->i_lineno = currentline();
576*57495Storek 	if (unit >= d->d_umax)
577*57495Storek 		d->d_umax = unit + 1;
578*57495Storek 	return (i);
579*57495Storek }
580*57495Storek 
581*57495Storek /*
582*57495Storek  * Add the named device as attaching to the named attribute (or perhaps
583*57495Storek  * another device instead) plus unit number.
584*57495Storek  */
585*57495Storek void
586*57495Storek adddev(name, at, loclist, flags)
587*57495Storek 	const char *name, *at;
588*57495Storek 	struct nvlist *loclist;
589*57495Storek 	int flags;
590*57495Storek {
591*57495Storek 	register struct devi *i;	/* the new instance */
592*57495Storek 	register struct attr *attr;	/* attribute that allows attach */
593*57495Storek 	register struct devbase *ib;	/* i->i_base */
594*57495Storek 	register struct devbase *ab;	/* not NULL => at another dev */
595*57495Storek 	register struct nvlist *nv;
596*57495Storek 	const char *cp;
597*57495Storek 	int atunit;
598*57495Storek 	char atbuf[NAMESIZE];
599*57495Storek 
600*57495Storek 	ab = NULL;
601*57495Storek 	if (at == NULL) {
602*57495Storek 		/* "at root" */
603*57495Storek 		if ((i = getdevi(name)) == NULL)
604*57495Storek 			goto bad;
605*57495Storek 		/*
606*57495Storek 		 * Must warn about i_unit > 0 later, after taking care of
607*57495Storek 		 * the STAR cases (we could do non-star's here but why
608*57495Storek 		 * bother?).  Make sure this device can be at root.
609*57495Storek 		 */
610*57495Storek 		ib = i->i_base;
611*57495Storek 		if (!onlist(ib->d_atlist, NULL)) {
612*57495Storek 			error("%s's cannot attach to the root", ib->d_name);
613*57495Storek 			goto bad;
614*57495Storek 		}
615*57495Storek 		attr = &errattr;	/* a convenient "empty" attr */
616*57495Storek 	} else {
617*57495Storek 		if (split(at, strlen(at), atbuf, sizeof atbuf, &atunit)) {
618*57495Storek 			error("invalid attachment name `%s'", at);
619*57495Storek 			/* (void)getdevi(name); -- ??? */
620*57495Storek 			goto bad;
621*57495Storek 		}
622*57495Storek 		if ((i = getdevi(name)) == NULL)
623*57495Storek 			goto bad;
624*57495Storek 		ib = i->i_base;
625*57495Storek 		cp = intern(atbuf);
626*57495Storek 		if ((attr = ht_lookup(attrtab, cp)) == NULL) {
627*57495Storek 			/*
628*57495Storek 			 * Have to work a bit harder to see whether we have
629*57495Storek 			 * something like "tg0 at esp0" (where esp is merely
630*57495Storek 			 * not an attribute) or "tg0 at nonesuch0" (where
631*57495Storek 			 * nonesuch is not even a device).
632*57495Storek 			 */
633*57495Storek 			if ((ab = ht_lookup(devbasetab, cp)) == NULL) {
634*57495Storek 				error("%s at %s: `%s' unknown",
635*57495Storek 				    name, at, atbuf);
636*57495Storek 				goto bad;
637*57495Storek 			}
638*57495Storek 			/*
639*57495Storek 			 * See if the named parent carries an attribute
640*57495Storek 			 * that allows it to supervise device ib.
641*57495Storek 			 */
642*57495Storek 			for (nv = ab->d_attrs; nv != NULL; nv = nv->nv_next) {
643*57495Storek 				attr = nv->nv_ptr;
644*57495Storek 				if (onlist(attr->a_devs, ib))
645*57495Storek 					goto ok;
646*57495Storek 			}
647*57495Storek 			attr = &errattr;/* now onlist below will fail */
648*57495Storek 		}
649*57495Storek 		if (!onlist(attr->a_devs, ib)) {
650*57495Storek 			error("%s's cannot attach to %s's", ib->d_name, atbuf);
651*57495Storek 			goto bad;
652*57495Storek 		}
653*57495Storek 	}
654*57495Storek ok:
655*57495Storek 	if ((i->i_locs = fixloc(name, attr, loclist)) == NULL)
656*57495Storek 		goto bad;
657*57495Storek 	if (i->i_unit == STAR && ib->d_vectors != NULL) {
658*57495Storek 		error("%s's cannot be *'d as they have preset vectors",
659*57495Storek 		    ib->d_name);
660*57495Storek 		goto bad;
661*57495Storek 	}
662*57495Storek 	i->i_at = at;
663*57495Storek 	i->i_atattr = attr;
664*57495Storek 	i->i_atdev = ab;
665*57495Storek 	i->i_atunit = atunit;
666*57495Storek 	i->i_cfflags = flags;
667*57495Storek 	selectbase(ib);
668*57495Storek 	/* all done, fall into ... */
669*57495Storek bad:
670*57495Storek 	nvfreel(loclist);
671*57495Storek 	return;
672*57495Storek }
673*57495Storek 
674*57495Storek void
675*57495Storek addpseudo(name, number)
676*57495Storek 	const char *name;
677*57495Storek 	int number;
678*57495Storek {
679*57495Storek 	register struct devbase *d;
680*57495Storek 	register struct devi *i;
681*57495Storek 
682*57495Storek 	d = ht_lookup(devbasetab, name);
683*57495Storek 	if (d == NULL) {
684*57495Storek 		error("undefined pseudo-device %s", name);
685*57495Storek 		return;
686*57495Storek 	}
687*57495Storek 	if (!d->d_ispseudo) {
688*57495Storek 		error("%s is a real device, not a pseudo-device", name);
689*57495Storek 		return;
690*57495Storek 	}
691*57495Storek 	if (ht_lookup(devitab, name) != NULL) {
692*57495Storek 		error("`%s' already defined", name);
693*57495Storek 		return;
694*57495Storek 	}
695*57495Storek 	i = newdevi(name, number - 1, d);	/* foo 16 => "foo0..foo15" */
696*57495Storek 	if (ht_insert(devitab, name, i))
697*57495Storek 		panic("addpseudo(%s)", name);
698*57495Storek 	selectbase(d);
699*57495Storek 	*nextpseudo = i;
700*57495Storek 	nextpseudo = &i->i_next;
701*57495Storek 	npseudo++;
702*57495Storek }
703*57495Storek 
704*57495Storek /*
705*57495Storek  * Define a new instance of a specific device.
706*57495Storek  */
707*57495Storek static struct devi *
708*57495Storek getdevi(name)
709*57495Storek 	const char *name;
710*57495Storek {
711*57495Storek 	register struct devi *i, *firsti;
712*57495Storek 	register struct devbase *d;
713*57495Storek 	int unit;
714*57495Storek 	char base[NAMESIZE];
715*57495Storek 
716*57495Storek 	if (split(name, strlen(name), base, sizeof base, &unit)) {
717*57495Storek 		error("invalid device name `%s'", name);
718*57495Storek 		return (NULL);
719*57495Storek 	}
720*57495Storek 	d = ht_lookup(devbasetab, intern(base));
721*57495Storek 	if (d == NULL) {
722*57495Storek 		error("%s: unknown device `%s'", name, base);
723*57495Storek 		return (NULL);
724*57495Storek 	}
725*57495Storek 	if (d->d_ispseudo) {
726*57495Storek 		error("%s: %s is a pseudo-device", name, base);
727*57495Storek 		return (NULL);
728*57495Storek 	}
729*57495Storek 	firsti = ht_lookup(devitab, name);
730*57495Storek 	i = newdevi(name, unit, d);
731*57495Storek 	if (firsti == NULL) {
732*57495Storek 		if (ht_insert(devitab, name, i))
733*57495Storek 			panic("getdevi(%s)", name);
734*57495Storek 		*d->d_ipp = i;
735*57495Storek 		d->d_ipp = &i->i_bsame;
736*57495Storek 	} else {
737*57495Storek 		while (firsti->i_alias)
738*57495Storek 			firsti = firsti->i_alias;
739*57495Storek 		firsti->i_alias = i;
740*57495Storek 	}
741*57495Storek 	*nextdevi = i;
742*57495Storek 	nextdevi = &i->i_next;
743*57495Storek 	ndevi++;
744*57495Storek 	return (i);
745*57495Storek }
746*57495Storek 
747*57495Storek static const char *
748*57495Storek concat(name, c)
749*57495Storek 	const char *name;
750*57495Storek 	int c;
751*57495Storek {
752*57495Storek 	register int len;
753*57495Storek 	char buf[NAMESIZE];
754*57495Storek 
755*57495Storek 	len = strlen(name);
756*57495Storek 	if (len + 2 > sizeof(buf)) {
757*57495Storek 		error("device name `%s%c' too long", name, c);
758*57495Storek 		len = sizeof(buf) - 2;
759*57495Storek 	}
760*57495Storek 	bcopy(name, buf, len);
761*57495Storek 	buf[len] = c;
762*57495Storek 	buf[len + 1] = 0;
763*57495Storek 	return (intern(buf));
764*57495Storek }
765*57495Storek 
766*57495Storek const char *
767*57495Storek starref(name)
768*57495Storek 	const char *name;
769*57495Storek {
770*57495Storek 
771*57495Storek 	return (concat(name, '*'));
772*57495Storek }
773*57495Storek 
774*57495Storek const char *
775*57495Storek wildref(name)
776*57495Storek 	const char *name;
777*57495Storek {
778*57495Storek 
779*57495Storek 	return (concat(name, '?'));
780*57495Storek }
781*57495Storek 
782*57495Storek /*
783*57495Storek  * Split a name like "foo0" into base name (foo) and unit number (0).
784*57495Storek  * Return 0 on success.  To make this useful for names like "foo0a",
785*57495Storek  * the length of the "foo0" part is one of the arguments.
786*57495Storek  */
787*57495Storek static int
788*57495Storek split(name, nlen, base, bsize, aunit)
789*57495Storek 	register const char *name;
790*57495Storek 	size_t nlen;
791*57495Storek 	char *base;
792*57495Storek 	size_t bsize;
793*57495Storek 	int *aunit;
794*57495Storek {
795*57495Storek 	register const char *cp;
796*57495Storek 	register int c, l;
797*57495Storek 
798*57495Storek 	l = nlen;
799*57495Storek 	if (l < 2 || l >= bsize || isdigit(*name))
800*57495Storek 		return (1);
801*57495Storek 	c = (u_char)name[--l];
802*57495Storek 	if (!isdigit(c)) {
803*57495Storek 		if (c == '*')
804*57495Storek 			*aunit = STAR;
805*57495Storek 		else if (c == '?')
806*57495Storek 			*aunit = WILD;
807*57495Storek 		else
808*57495Storek 			return (1);
809*57495Storek 	} else {
810*57495Storek 		cp = &name[l];
811*57495Storek 		while (isdigit(cp[-1]))
812*57495Storek 			l--, cp--;
813*57495Storek 		*aunit = atoi(cp);
814*57495Storek 	}
815*57495Storek 	bcopy(name, base, l);
816*57495Storek 	base[l] = 0;
817*57495Storek 	return (0);
818*57495Storek }
819*57495Storek 
820*57495Storek /*
821*57495Storek  * We have an instance of the base foo, so select it and all its
822*57495Storek  * attributes for "optional foo".
823*57495Storek  */
824*57495Storek static void
825*57495Storek selectbase(d)
826*57495Storek 	register struct devbase *d;
827*57495Storek {
828*57495Storek 	register struct attr *a;
829*57495Storek 	register struct nvlist *nv;
830*57495Storek 
831*57495Storek 	(void)ht_insert(selecttab, d->d_name, (char *)d->d_name);
832*57495Storek 	for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) {
833*57495Storek 		a = nv->nv_ptr;
834*57495Storek 		(void)ht_insert(selecttab, a->a_name, (char *)a->a_name);
835*57495Storek 	}
836*57495Storek }
837*57495Storek 
838*57495Storek /*
839*57495Storek  * Is the given pointer on the given list of pointers?
840*57495Storek  */
841*57495Storek static int
842*57495Storek onlist(nv, ptr)
843*57495Storek 	register struct nvlist *nv;
844*57495Storek 	register void *ptr;
845*57495Storek {
846*57495Storek 	for (; nv != NULL; nv = nv->nv_next)
847*57495Storek 		if (nv->nv_ptr == ptr)
848*57495Storek 			return (1);
849*57495Storek 	return (0);
850*57495Storek }
851*57495Storek 
852*57495Storek static char *
853*57495Storek extend(p, name)
854*57495Storek 	register char *p;
855*57495Storek 	const char *name;
856*57495Storek {
857*57495Storek 	register int l;
858*57495Storek 
859*57495Storek 	l = strlen(name);
860*57495Storek 	bcopy(name, p, l);
861*57495Storek 	p += l;
862*57495Storek 	*p++ = ',';
863*57495Storek 	*p++ = ' ';
864*57495Storek 	return (p);
865*57495Storek }
866*57495Storek 
867*57495Storek /*
868*57495Storek  * Check that we got all required locators, and default any that are
869*57495Storek  * given as "?" and have defaults.  Return 0 on success.
870*57495Storek  */
871*57495Storek static const char **
872*57495Storek fixloc(name, attr, got)
873*57495Storek 	const char *name;
874*57495Storek 	register struct attr *attr;
875*57495Storek 	register struct nvlist *got;
876*57495Storek {
877*57495Storek 	register struct nvlist *m, *n;
878*57495Storek 	register int ord;
879*57495Storek 	register const char **lp;
880*57495Storek 	int nmissing, nextra, nnodefault;
881*57495Storek 	char *mp, *ep, *ndp;
882*57495Storek 	char missing[1000], extra[1000], nodefault[1000];
883*57495Storek 	static const char *nullvec[1];
884*57495Storek 
885*57495Storek 	/*
886*57495Storek 	 * Look for all required locators, and number the given ones
887*57495Storek 	 * according to the required order.  While we are numbering,
888*57495Storek 	 * set default values for defaulted locators.
889*57495Storek 	 */
890*57495Storek 	if (attr->a_loclen == 0)	/* e.g., "at root" */
891*57495Storek 		lp = nullvec;
892*57495Storek 	else
893*57495Storek 		lp = emalloc((attr->a_loclen + 1) * sizeof(const char *));
894*57495Storek 	for (n = got; n != NULL; n = n->nv_next)
895*57495Storek 		n->nv_int = -1;
896*57495Storek 	nmissing = 0;
897*57495Storek 	mp = missing;
898*57495Storek 	/* yes, this is O(mn), but m and n should be small */
899*57495Storek 	for (ord = 0, m = attr->a_locs; m != NULL; m = m->nv_next, ord++) {
900*57495Storek 		for (n = got; n != NULL; n = n->nv_next) {
901*57495Storek 			if (n->nv_name == m->nv_name) {
902*57495Storek 				n->nv_int = ord;
903*57495Storek 				break;
904*57495Storek 			}
905*57495Storek 		}
906*57495Storek 		if (n == NULL && m->nv_int == 0) {
907*57495Storek 			nmissing++;
908*57495Storek 			mp = extend(mp, m->nv_name);
909*57495Storek 		}
910*57495Storek 		lp[ord] = m->nv_str;
911*57495Storek 	}
912*57495Storek 	if (ord != attr->a_loclen)
913*57495Storek 		panic("fixloc");
914*57495Storek 	lp[ord] = NULL;
915*57495Storek 	nextra = 0;
916*57495Storek 	ep = extra;
917*57495Storek 	nnodefault = 0;
918*57495Storek 	ndp = nodefault;
919*57495Storek 	for (n = got; n != NULL; n = n->nv_next) {
920*57495Storek 		if (n->nv_int >= 0) {
921*57495Storek 			if (n->nv_str != NULL)
922*57495Storek 				lp[n->nv_int] = n->nv_str;
923*57495Storek 			else if (lp[n->nv_int] == NULL) {
924*57495Storek 				nnodefault++;
925*57495Storek 				ndp = extend(ndp, n->nv_name);
926*57495Storek 			}
927*57495Storek 		} else {
928*57495Storek 			nextra++;
929*57495Storek 			ep = extend(ep, n->nv_name);
930*57495Storek 		}
931*57495Storek 	}
932*57495Storek 	if (nextra) {
933*57495Storek 		ep[-2] = 0;	/* kill ", " */
934*57495Storek 		error("%s: extraneous locator%s: %s",
935*57495Storek 		    name, nextra > 1 ? "s" : "", extra);
936*57495Storek 	}
937*57495Storek 	if (nmissing) {
938*57495Storek 		mp[-2] = 0;
939*57495Storek 		error("%s: must specify %s", name, missing);
940*57495Storek 	}
941*57495Storek 	if (nnodefault) {
942*57495Storek 		ndp[-2] = 0;
943*57495Storek 		error("%s: cannot wildcard %s", name, nodefault);
944*57495Storek 	}
945*57495Storek 	if (nmissing || nnodefault) {
946*57495Storek 		free(lp);
947*57495Storek 		lp = NULL;
948*57495Storek 	}
949*57495Storek 	return (lp);
950*57495Storek }
951