Module Name:    src
Committed By:   christos
Date:           Sat Nov 18 18:44:20 UTC 2017

Modified Files:
        src/usr.bin/config: defs.h mkioconf.c sem.c

Log Message:
Allow multiple attachments methods to the same child+parent combination:

    foo* at bar? with baz
    foo* at bar? with barf

Do this by scanning the list of iba's and allocating a new cfparent for
each. Keep track of the shared parent+child combinations by using the
same id for them.


To generate a diff of this commit:
cvs rdiff -u -r1.100 -r1.101 src/usr.bin/config/defs.h
cvs rdiff -u -r1.33 -r1.34 src/usr.bin/config/mkioconf.c
cvs rdiff -u -r1.78 -r1.79 src/usr.bin/config/sem.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/config/defs.h
diff -u src/usr.bin/config/defs.h:1.100 src/usr.bin/config/defs.h:1.101
--- src/usr.bin/config/defs.h:1.100	Thu Nov 16 12:08:07 2017
+++ src/usr.bin/config/defs.h	Sat Nov 18 13:44:20 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: defs.h,v 1.100 2017/11/16 17:08:07 christos Exp $	*/
+/*	$NetBSD: defs.h,v 1.101 2017/11/18 18:44:20 christos Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -107,7 +107,7 @@ extern const char *progname;
  * The next two lines define the current version of the config(1) binary,
  * and the minimum version of the configuration files it supports.
  */
-#define CONFIG_VERSION		20170615
+#define CONFIG_VERSION		20171118
 #define CONFIG_MINVERSION	0
 
 /*
@@ -234,6 +234,7 @@ struct pspec {
 	struct	devbase *p_atdev;	/* optional parent device base */
 	int	p_atunit;		/* optional parent device unit */
 	struct	nvlist *p_devs;		/* children using it */
+	struct	deva *p_deva;		/* attribute */
 	int	p_inst;			/* parent spec instance */
 	int	p_active;		/* parent spec is actively used */
 };

Index: src/usr.bin/config/mkioconf.c
diff -u src/usr.bin/config/mkioconf.c:1.33 src/usr.bin/config/mkioconf.c:1.34
--- src/usr.bin/config/mkioconf.c:1.33	Thu Nov 12 09:38:21 2015
+++ src/usr.bin/config/mkioconf.c	Sat Nov 18 13:44:20 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: mkioconf.c,v 1.33 2015/11/12 14:38:21 pooka Exp $	*/
+/*	$NetBSD: mkioconf.c,v 1.34 2017/11/18 18:44:20 christos Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -45,7 +45,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: mkioconf.c,v 1.33 2015/11/12 14:38:21 pooka Exp $");
+__RCSID("$NetBSD: mkioconf.c,v 1.34 2017/11/18 18:44:20 christos Exp $");
 
 #include <sys/param.h>
 #include <err.h>
@@ -338,11 +338,15 @@ static void
 emitparents(FILE *fp)
 {
 	struct pspec *p;
+	int inst = -1;
 
 	NEWLINE;
 	TAILQ_FOREACH(p, &allpspecs, p_list) {
 		if (p->p_devs == NULL || p->p_active != DEVI_ACTIVE)
 			continue;
+		if (inst == p->p_inst)
+			continue;
+		inst = p->p_inst;
 		fprintf(fp,
 		    "static const struct cfparent pspec%d = {\n", p->p_inst);
 		fprintf(fp, "\t\"%s\", ", p->p_iattr->a_name);

Index: src/usr.bin/config/sem.c
diff -u src/usr.bin/config/sem.c:1.78 src/usr.bin/config/sem.c:1.79
--- src/usr.bin/config/sem.c:1.78	Sat Nov 18 13:41:44 2017
+++ src/usr.bin/config/sem.c	Sat Nov 18 13:44:20 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: sem.c,v 1.78 2017/11/18 18:41:44 christos Exp $	*/
+/*	$NetBSD: sem.c,v 1.79 2017/11/18 18:44:20 christos Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -45,7 +45,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: sem.c,v 1.78 2017/11/18 18:41:44 christos Exp $");
+__RCSID("$NetBSD: sem.c,v 1.79 2017/11/18 18:44:20 christos Exp $");
 
 #include <sys/param.h>
 #include <ctype.h>
@@ -79,7 +79,8 @@ static int has_errobj(struct attrlist *,
 static struct nvlist *addtoattr(struct nvlist *, struct devbase *);
 static int resolve(struct nvlist **, const char *, const char *,
 		   struct nvlist *, int);
-static struct pspec *getpspec(struct attr *, struct devbase *, int);
+static struct pspec *getpspec(struct attr *, struct devbase *, int,
+    struct deva *);
 static struct devi *newdevi(const char *, int, struct devbase *d);
 static struct devi *getdevi(const char *);
 static void remove_devi(struct devi *);
@@ -641,7 +642,6 @@ defdevattach(struct deva *deva, struct d
 	struct nvlist *nv;
 	struct attrlist *al;
 	struct attr *a;
-	struct deva *da;
 
 	if (dev == &errdev)
 		goto bad;
@@ -699,14 +699,16 @@ defdevattach(struct deva *deva, struct d
 		if (a == &errattr)
 			continue;		/* already complained */
 
+#if 0
 		/*
 		 * Make sure that an attachment spec doesn't
 		 * already say how to attach to this attribute.
 		 */
-		for (da = dev->d_ahead; da != NULL; da = da->d_bsame)
+		for (struct deva *da = dev->d_ahead; da; da = da->d_bsame)
 			if (onlist(da->d_atlist, a))
 				cfgerror("attach at `%s' already done by `%s'",
 				     a ? a->a_name : "root", da->d_name);
+#endif
 
 		if (a == NULL) {
 			ht_insert(devroottab, dev->d_name, dev);
@@ -1158,6 +1160,83 @@ newdevi(const char *name, int unit, stru
 	return (i);
 }
 
+static struct attr *
+finddevattr(const char *name, const char *at, struct devbase *ib,
+    struct devbase **ab, int *atunit)
+{
+	const char *cp;
+	char atbuf[NAMESIZE];
+	struct attrlist *al;
+	struct attr *attr;
+
+	if (at == NULL) {
+		*ab = NULL;
+		*atunit = -1;
+		return &errattr;	/* a convenient "empty" attr */
+	}
+	if (split(at, strlen(at), atbuf, sizeof atbuf, atunit)) {
+		cfgerror("invalid attachment name `%s'", at);
+		/* (void)getdevi(name); -- ??? */
+		return NULL;
+	}
+
+	/*
+	 * Devices can attach to two types of things: Attributes,
+	 * and other devices (which have the appropriate attributes
+	 * to allow attachment).
+	 *
+	 * (1) If we're attached to an attribute, then we don't need
+	 *     look at the parent base device to see what attributes
+	 *     it has, and make sure that we can attach to them.    
+	 *
+	 * (2) If we're attached to a real device (i.e. named in
+	 *     the config file), we want to remember that so that
+	 *     at cross-check time, if the device we're attached to
+	 *     is missing but other devices which also provide the
+	 *     attribute are present, we don't get a false "OK."
+	 *
+	 * (3) If the thing we're attached to is an attribute
+	 *     but is actually named in the config file, we still
+	 *     have to remember its devbase.
+	 */
+	cp = intern(atbuf);
+
+	/* Figure out parent's devbase, to satisfy case (3). */
+	*ab = ht_lookup(devbasetab, cp);
+
+	/* Find out if it's an attribute. */
+	attr = ht_lookup(attrtab, cp);
+
+	/* Make sure we're _really_ attached to the attr.  Case (1). */
+	if (attr != NULL && onlist(attr->a_devs, ib))
+		return attr;
+
+	/*
+	 * Else a real device, and not just an attribute.  Case (2).
+	 *
+	 * Have to work a bit harder to see whether we have
+	 * something like "tg0 at esp0" (where esp is merely
+	 * not an attribute) or "tg0 at nonesuch0" (where
+	 * nonesuch is not even a device).
+	 */
+	if (*ab == NULL) {
+		cfgerror("%s at %s: `%s' unknown", name, at, atbuf);
+		return NULL;
+	}
+
+	/*
+	 * See if the named parent carries an attribute
+	 * that allows it to supervise device ib.
+	 */
+	for (al = (*ab)->d_attrs; al != NULL; al = al->al_next) {
+		attr = al->al_this;
+		if (onlist(attr->a_devs, ib))
+			return attr;
+	}
+	cfgerror("`%s' cannot attach to `%s'", ib->d_name, atbuf);
+	return NULL;
+}
+
 /*
  * Add the named device as attaching to the named attribute (or perhaps
  * another device instead) plus unit number.
@@ -1170,137 +1249,68 @@ adddev(const char *name, const char *at,
 	struct attr *attr;	/* attribute that allows attach */
 	struct devbase *ib;	/* i->i_base */
 	struct devbase *ab;	/* not NULL => at another dev */
-	struct attrlist *al;
 	struct deva *iba;	/* devbase attachment used */
-	const char *cp;
+	struct deva *lastiba;
 	int atunit;
-	char atbuf[NAMESIZE];
-	int hit;
 
-	ab = NULL;
+	lastiba = NULL;
+	if ((i = getdevi(name)) == NULL)
+		goto bad;
+	ib = i->i_base;
 	iba = NULL;
-	if (at == NULL) {
-		/* "at root" */
-		p = NULL;
-		if ((i = getdevi(name)) == NULL)
-			goto bad;
-		/*
-		 * Must warn about i_unit > 0 later, after taking care of
-		 * the STAR cases (we could do non-star's here but why
-		 * bother?).  Make sure this device can be at root.
-		 */
-		ib = i->i_base;
-		hit = 0;
-		for (iba = ib->d_ahead; iba != NULL; iba = iba->d_bsame)
-			if (onlist(iba->d_atlist, NULL)) {
-				hit = 1;
+	p = NULL;
+	attr = finddevattr(name, at, ib, &ab, &atunit);
+	if (attr == NULL) {
+		i->i_active = DEVI_BROKEN;
+		goto bad;
+	}
+
+	for (lastiba = ib->d_ahead; lastiba; lastiba = iba->d_bsame) {
+		for (iba = lastiba; iba != NULL; iba = iba->d_bsame)
+			if (onlist(iba->d_atlist,
+			    attr == &errattr ? NULL : attr))
 				break;
+
+		if (iba == NULL) {
+			if (lastiba != ib->d_ahead)
+				goto bad;
+			if (attr != &errattr) {
+				panic("adddev: can't figure out attachment");
+			} else {
+				cfgerror("`%s' cannot attach to the root",
+				    ib->d_name);
+				i->i_active = DEVI_BROKEN;
 			}
-		if (!hit) {
-			cfgerror("`%s' cannot attach to the root", ib->d_name);
-			i->i_active = DEVI_BROKEN;
-			goto bad;
 		}
-		attr = &errattr;	/* a convenient "empty" attr */
-	} else {
-		if (split(at, strlen(at), atbuf, sizeof atbuf, &atunit)) {
-			cfgerror("invalid attachment name `%s'", at);
-			/* (void)getdevi(name); -- ??? */
-			goto bad;
-		}
-		if ((i = getdevi(name)) == NULL)
+		// get a new one if it is not the first time
+		if (lastiba != ib->d_ahead && (i = getdevi(name)) == NULL)
 			goto bad;
-		ib = i->i_base;
 
-		/*
-		 * Devices can attach to two types of things: Attributes,
-		 * and other devices (which have the appropriate attributes
-		 * to allow attachment).
-		 *
-		 * (1) If we're attached to an attribute, then we don't need
-		 *     look at the parent base device to see what attributes
-		 *     it has, and make sure that we can attach to them.    
-		 *
-		 * (2) If we're attached to a real device (i.e. named in
-		 *     the config file), we want to remember that so that
-		 *     at cross-check time, if the device we're attached to
-		 *     is missing but other devices which also provide the
-		 *     attribute are present, we don't get a false "OK."
-		 *
-		 * (3) If the thing we're attached to is an attribute
-		 *     but is actually named in the config file, we still
-		 *     have to remember its devbase.
-		 */
-		cp = intern(atbuf);
-
-		/* Figure out parent's devbase, to satisfy case (3). */
-		ab = ht_lookup(devbasetab, cp);
-
-		/* Find out if it's an attribute. */
-		attr = ht_lookup(attrtab, cp);
-
-		/* Make sure we're _really_ attached to the attr.  Case (1). */
-		if (attr != NULL && onlist(attr->a_devs, ib))
-			goto findattachment;
+		if (attr != &errattr) {
+			/*
+			 * Find the parent spec.  If a matching one has not
+			 * yet been created, create one.
+			 *
+			 * XXX: This creates multiple pspecs that look the
+			 * same in the config file and could be merged.
+			 */
+			p = getpspec(attr, ab, atunit, iba);
+			p->p_devs = newnv(NULL, NULL, i, 0, p->p_devs);
+		}
 
-		/*
-		 * Else a real device, and not just an attribute.  Case (2).
-		 *
-		 * Have to work a bit harder to see whether we have
-		 * something like "tg0 at esp0" (where esp is merely
-		 * not an attribute) or "tg0 at nonesuch0" (where
-		 * nonesuch is not even a device).
-		 */
-		if (ab == NULL) {
-			cfgerror("%s at %s: `%s' unknown",
-			    name, at, atbuf);
+		if ((i->i_locs = fixloc(name, attr, loclist)) == NULL) {
 			i->i_active = DEVI_BROKEN;
 			goto bad;
 		}
+		i->i_at = at;
+		i->i_pspec = p;
+		i->i_atdeva = iba;
+		i->i_cfflags = flags;
+		CFGDBG(3, "devi `%s' at '%s' added", i->i_name, iba->d_name);
 
-		/*
-		 * See if the named parent carries an attribute
-		 * that allows it to supervise device ib.
-		 */
-		for (al = ab->d_attrs; al != NULL; al = al->al_next) {
-			attr = al->al_this;
-			if (onlist(attr->a_devs, ib))
-				goto findattachment;
-		}
-		cfgerror("`%s' cannot attach to `%s'", ib->d_name, atbuf);
-		i->i_active = DEVI_BROKEN;
-		goto bad;
-
- findattachment:
-		/*
-		 * Find the parent spec.  If a matching one has not yet been
-		 * created, create one.
-		 */
-		p = getpspec(attr, ab, atunit);
-		p->p_devs = newnv(NULL, NULL, i, 0, p->p_devs);
-
-		/* find out which attachment it uses */
-		hit = 0;
-		for (iba = ib->d_ahead; iba != NULL; iba = iba->d_bsame)
-			if (onlist(iba->d_atlist, attr)) {
-				hit = 1;
-				break;
-			}
-		if (!hit)
-			panic("adddev: can't figure out attachment");
-	}
-	if ((i->i_locs = fixloc(name, attr, loclist)) == NULL) {
-		i->i_active = DEVI_BROKEN;
-		goto bad;
+		*iba->d_ipp = i;
+		iba->d_ipp = &i->i_asame;
 	}
-	i->i_at = at;
-	i->i_pspec = p;
-	i->i_atdeva = iba;
-	i->i_cfflags = flags;
-	CFGDBG(3, "devi `%s' added", i->i_name);
-
-	*iba->d_ipp = i;
-	iba->d_ipp = &i->i_asame;
 
 	/* all done, fall into ... */
  bad:
@@ -1892,23 +1902,30 @@ fixdevis(void)
  * Look up a parent spec, creating a new one if it does not exist.
  */
 static struct pspec *
-getpspec(struct attr *attr, struct devbase *ab, int atunit)
+getpspec(struct attr *attr, struct devbase *ab, int atunit, struct deva *da)
 {
 	struct pspec *p;
+	int inst = npspecs;
 
 	TAILQ_FOREACH(p, &allpspecs, p_list) {
-		if (p->p_iattr == attr &&
-		    p->p_atdev == ab &&
-		    p->p_atunit == atunit)
-			return (p);
+		if (p->p_iattr == attr && p->p_atdev == ab &&
+		    p->p_atunit == atunit) {
+			if (p->p_deva == da)
+				return (p);
+		   	inst = p->p_inst; 
+		}
 	}
+printf("2. %d %p %s %d %s\n", npspecs, attr, ab->d_name, atunit, da->d_name);
 
 	p = ecalloc(1, sizeof(*p));
 
 	p->p_iattr = attr;
 	p->p_atdev = ab;
 	p->p_atunit = atunit;
-	p->p_inst = npspecs++;
+	p->p_inst = inst;
+	if (inst == npspecs)
+		npspecs++;
+	p->p_deva = da;
 	p->p_active = 0;
 
 	TAILQ_INSERT_TAIL(&allpspecs, p, p_list);

Reply via email to