From 7aa6070d4e05497b05d6f48dc0b7f04e72659084 Mon Sep 17 00:00:00 2001 From: cube Date: Sat, 1 Oct 2005 23:30:37 +0000 Subject: [PATCH] o Keep track of negated devices in deaddevitab o Rework do_kill_orphans() to use that information and mark explicitely orphaned devices (i.e., the ones whose missing ancestor has been negated) o Make a distinction between erroneous orphans and explicit orphans. Error out on the former, ignore the later (but print a warning when -v is used) Yes, now config(1) will actually stop if you comment out a parent. That should help people still hoping adjustkernel is relevant these days :) --- usr.bin/config/defs.h | 8 +- usr.bin/config/main.c | 156 +++++++++++++++++++++++++++++++++----- usr.bin/config/mkioconf.c | 4 +- usr.bin/config/pack.c | 6 +- usr.bin/config/sem.c | 42 ++++++++-- usr.bin/config/sem.h | 4 +- 6 files changed, 185 insertions(+), 35 deletions(-) diff --git a/usr.bin/config/defs.h b/usr.bin/config/defs.h index 46b0b6f23e0a..90d616d7867e 100644 --- a/usr.bin/config/defs.h +++ b/usr.bin/config/defs.h @@ -1,4 +1,4 @@ -/* $NetBSD: defs.h,v 1.3 2005/09/30 22:36:20 cube Exp $ */ +/* $NetBSD: defs.h,v 1.4 2005/10/01 23:30:37 cube Exp $ */ /* * Copyright (c) 1992, 1993 @@ -243,7 +243,10 @@ struct devi { const char **i_locs; /* locators (as given by pspec's iattr) */ int i_cfflags; /* flags from config line */ int i_lineno; /* line # in config, for later errors */ - int i_active; /* instance is not orphaned in any way */ + int i_active; +#define DEVI_ORPHAN 0 /* instance has no active parent */ +#define DEVI_ACTIVE 1 /* instance has an active parent */ +#define DEVI_IGNORED 2 /* instance's parent has been removed */ /* created during packing or ioconf.c generation */ short i_collapsed; /* set => this alias no longer needed */ @@ -367,6 +370,7 @@ struct hashtab *devbasetab; /* devbase lookup */ struct hashtab *devroottab; /* attach at root lookup */ struct hashtab *devatab; /* devbase attachment lookup */ struct hashtab *devitab; /* device instance lookup */ +struct hashtab *deaddevitab; /* removed instances lookup */ struct hashtab *selecttab; /* selects things that are "optional foo" */ struct hashtab *needcnttab; /* retains names marked "needs-count" */ struct hashtab *opttab; /* table of configured options */ diff --git a/usr.bin/config/main.c b/usr.bin/config/main.c index 578a4f343b75..3e90262fb67c 100644 --- a/usr.bin/config/main.c +++ b/usr.bin/config/main.c @@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.2 2005/09/30 22:36:20 cube Exp $ */ +/* $NetBSD: main.c,v 1.3 2005/10/01 23:30:37 cube Exp $ */ /* * Copyright (c) 1992, 1993 @@ -104,8 +104,12 @@ static int badstar(void); int main(int, char **); static int mksymlinks(void); static int mkident(void); +static int devbase_has_dead_instances(const char *, void *, void *); +static int devbase_has_any_instance(struct devbase *, int, int); +static int check_dead_devi(const char *, void *, void *); static void kill_orphans(void); -static void do_kill_orphans(struct devbase *, struct attr *, struct devbase *); +static void do_kill_orphans(struct devbase *, struct attr *, + struct devbase *, int); static int kill_orphans_cb(const char *, void *, void *); static int cfcrosscheck(struct config *, const char *, struct nvlist *); static const char *strtolower(const char *); @@ -254,6 +258,7 @@ main(int argc, char **argv) devroottab = ht_new(); devatab = ht_new(); devitab = ht_new(); + deaddevitab = ht_new(); selecttab = ht_new(); needcnttab = ht_new(); opttab = ht_new(); @@ -347,7 +352,8 @@ main(int argc, char **argv) /* * Select devices and pseudo devices and their attributes */ - fixdevis(); + if (fixdevis()) + stop(); /* * Deal with option dependencies. @@ -996,7 +1002,7 @@ deva_has_instances(struct deva *deva, int unit) struct devi *i; for (i = deva->d_ihead; i != NULL; i = i->i_asame) - if (i->i_active && + if (i->i_active == DEVI_ACTIVE && (unit == WILD || unit == i->i_unit || i->i_unit == STAR)) return (1); return (0); @@ -1477,25 +1483,127 @@ extract_config(const char *kname, const char *cname, int cfd) return found; } +struct dhdi_params { + struct devbase *d; + int unit; +}; + +static int +devbase_has_dead_instances(const char *key, void *value, void *aux) +{ + struct devi *i = value; + struct dhdi_params *dhdi = aux; + + if (i->i_base == dhdi->d && + (dhdi->unit == WILD || dhdi->unit == i->i_unit || + i->i_unit == STAR)) + return 1; + return 0; +} + +/* + * This is almost the same as devbase_has_instances, except it + * may have special considerations regarding ignored instances. + */ + +static int +devbase_has_any_instance(struct devbase *dev, int unit, int state) +{ + struct deva *da; + struct devi *i; + + if (dev->d_ispseudo) { + if (dev->d_ihead != NULL) + return 1; + else if (state == DEVI_IGNORED) + return (ht_lookup(deaddevitab, dev->d_name) != NULL); + else + return 0; + } + + for (da = dev->d_ahead; da != NULL; da = da->d_bsame) + for (i = da->d_ihead; i != NULL; i = i->i_asame) + if ((i->i_active == DEVI_ACTIVE || + i->i_active == state) && + (unit == WILD || unit == i->i_unit || + i->i_unit == STAR)) + return 1; + + if (state == DEVI_IGNORED) { + struct dhdi_params dhdi = { dev, unit }; + /* also check dead devices */ + return ht_enumerate(deaddevitab, devbase_has_dead_instances, + &dhdi); + } + + return 0; +} + +/* + * check_dead_devi(), used with ht_enumerate, checks if any of the removed + * device instances would have been a valid instance considering the devbase, + * the parent device and the interface attribute. + * + * In other words, for a non-active device, it checks if children would be + * actual orphans or the result of a negative statement in the config file. + */ + +struct cdd_params { + struct devbase *d; + struct attr *at; + struct devbase *parent; +}; + +static int +check_dead_devi(const char *key, void *value, void *aux) +{ + struct cdd_params *cdd = aux; + struct devi *i = value; + struct pspec *p = i->i_pspec; + + if (i->i_base != cdd->d) + return 0; + + if ((p == NULL && cdd->at == NULL) || + (p != NULL && p->p_iattr == cdd->at && + (p->p_atdev == NULL || p->p_atdev == cdd->parent))) { + if (p != NULL && + !devbase_has_any_instance(cdd->parent, p->p_atunit, + DEVI_IGNORED)) + return 0; + else + return 1; + } + return 0; +} + static void -do_kill_orphans(struct devbase *d, struct attr *at, struct devbase *parent) +do_kill_orphans(struct devbase *d, struct attr *at, struct devbase *parent, + int state) { struct nvlist *nv, *nv1; struct attr *a; struct devi *i, *j = NULL; struct pspec *p; + int active = 0; /* * A pseudo-device will always attach at root, and if it has an * instance (it cannot have more than one), it is enough to consider * it active, as there is no real attachment. + * + * A pseudo device can never be marked DEVI_IGNORED. */ if (d->d_ispseudo) { - if (d->d_ihead == NULL) - return; - d->d_ihead->i_active = 1; + if (d->d_ihead != NULL) + d->d_ihead->i_active = active = DEVI_ACTIVE; + else { + if (ht_lookup(deaddevitab, d->d_name) != NULL) + active = DEVI_IGNORED; + else + return; + } } else { - int active = 0; for (i = d->d_ihead; i != NULL; i = i->i_bsame) { for (j = i; j != NULL; j = j->i_alias) { p = j->i_pspec; @@ -1504,8 +1612,8 @@ do_kill_orphans(struct devbase *d, struct attr *at, struct devbase *parent) (p->p_atdev == NULL || p->p_atdev == parent))) { if (p != NULL && - !devbase_has_instances(parent, - p->p_atunit)) + !devbase_has_any_instance(parent, + p->p_atunit, state)) continue; /* * There are Fry-like devices which can @@ -1515,33 +1623,45 @@ do_kill_orphans(struct devbase *d, struct attr *at, struct devbase *parent) * an instance for one reason or * another, stop there. */ - if (j->i_active) + if (j->i_active == DEVI_ACTIVE || + j->i_active == state) /* * Device has already been * seen */ return; - j->i_active = active = 1; + j->i_active = active = state; if (p != NULL) - p->p_active = 1; + p->p_active = state; } } } - if (!active) - return; + if (!active) { + struct cdd_params cdd = { d, at, parent }; + /* Look for a matching dead devi */ + if (ht_enumerate(deaddevitab, check_dead_devi, &cdd)) + /* + * That device had its instances removed. + * Continue the loop marking descendants + * with DEVI_IGNORED instead of DEVI_ACTIVE. + */ + active = DEVI_IGNORED; + else + return; + } } for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) { a = nv->nv_ptr; for (nv1 = a->a_devs; nv1 != NULL; nv1 = nv1->nv_next) - do_kill_orphans(nv1->nv_ptr, a, d); + do_kill_orphans(nv1->nv_ptr, a, d, active); } } static int kill_orphans_cb(const char *key, void *value, void *aux) { - do_kill_orphans((struct devbase *)value, NULL, NULL); + do_kill_orphans((struct devbase *)value, NULL, NULL, DEVI_ACTIVE); return 0; } diff --git a/usr.bin/config/mkioconf.c b/usr.bin/config/mkioconf.c index bf5ad013897a..17359fd61236 100644 --- a/usr.bin/config/mkioconf.c +++ b/usr.bin/config/mkioconf.c @@ -1,4 +1,4 @@ -/* $NetBSD: mkioconf.c,v 1.4 2005/09/30 22:36:20 cube Exp $ */ +/* $NetBSD: mkioconf.c,v 1.5 2005/10/01 23:30:37 cube Exp $ */ /* * Copyright (c) 1992, 1993 @@ -359,7 +359,7 @@ emitparents(FILE *fp) NEWLINE; TAILQ_FOREACH(p, &allpspecs, p_list) { - if (p->p_devs == NULL || !p->p_active) + if (p->p_devs == NULL || p->p_active != DEVI_ACTIVE) continue; if (fprintf(fp, "static const struct cfparent pspec%d = {\n", p->p_inst) < 0) diff --git a/usr.bin/config/pack.c b/usr.bin/config/pack.c index 77f2fb82ed0b..39756f2f17be 100644 --- a/usr.bin/config/pack.c +++ b/usr.bin/config/pack.c @@ -1,4 +1,4 @@ -/* $NetBSD: pack.c,v 1.2 2005/09/30 22:36:20 cube Exp $ */ +/* $NetBSD: pack.c,v 1.3 2005/10/01 23:30:37 cube Exp $ */ /* * Copyright (c) 1992, 1993 @@ -115,7 +115,7 @@ pack(void) */ locspace = 0; TAILQ_FOREACH(i, &alldevi, i_next) { - if (!i->i_active || i->i_collapsed) + if (!i->i_active == DEVI_ACTIVE || i->i_collapsed) continue; if ((p = i->i_pspec) == NULL) continue; @@ -186,7 +186,7 @@ packdevi(void) for (i = d->d_ihead; i != NULL; i = i->i_bsame) { m = n; for (l = i; l != NULL; l = l->i_alias) { - if (!l->i_active) + if (l->i_active != DEVI_ACTIVE) continue; l->i_locoff = -1; /* try to find an equivalent for l */ diff --git a/usr.bin/config/sem.c b/usr.bin/config/sem.c index 52ec3e800d4e..eac2b954370d 100644 --- a/usr.bin/config/sem.c +++ b/usr.bin/config/sem.c @@ -1,4 +1,4 @@ -/* $NetBSD: sem.c,v 1.7 2005/09/30 22:51:46 cube Exp $ */ +/* $NetBSD: sem.c,v 1.8 2005/10/01 23:30:37 cube Exp $ */ /* * Copyright (c) 1992, 1993 @@ -88,6 +88,7 @@ static const char *major2name(int); static int dev2major(struct devbase *); extern const char *yyfile; +extern int vflag; void initsem(void) @@ -877,7 +878,7 @@ newdevi(const char *name, int unit, struct devbase *d) i->i_locs = NULL; i->i_cfflags = 0; i->i_lineno = currentline(); - i->i_active = 0; + i->i_active = DEVI_ORPHAN; /* Proper analysis comes later */ if (unit >= d->d_umax) d->d_umax = unit + 1; return (i); @@ -1181,7 +1182,19 @@ remove_devi(struct devi *i) */ TAILQ_REMOVE(&alldevi, i, i_next); ndevi--; - free(i); + /* + * Put it in deaddevitab + */ + i->i_alias = NULL; + f = ht_lookup(deaddevitab, i->i_name); + if (f == NULL) { + if (ht_insert(deaddevitab, i->i_name, i)) + panic("remove_devi(%s) - can't add to deaddevitab", + i->i_name); + } else { + for (j = f; j->i_alias != NULL; j = j->i_alias); + j->i_alias = i; + } /* * - reconstuct d->d_umax */ @@ -1343,7 +1356,7 @@ addpseudo(const char *name, int number) panic("addpseudo(%s)", name); /* Useful to retrieve the instance from the devbase */ d->d_ihead = i; - i->i_active = 1; + i->i_active = DEVI_ACTIVE; TAILQ_INSERT_TAIL(&allpseudo, i, i_next); } @@ -1367,9 +1380,12 @@ delpseudo(const char *name) return; } d->d_umax = 0; /* clear neads-count entries */ + d->d_ihead = NULL; /* make sure it won't be considered active */ TAILQ_REMOVE(&allpseudo, i, i_next); if (ht_remove(devitab, name)) panic("delpseudo(%s) - can't remove from devitab", name); + if (ht_insert(deaddevitab, name, i)) + panic("delpseudo(%s) - can't add to deaddevitab", name); } void @@ -1408,28 +1424,38 @@ adddevm(const char *name, int cmajor, int bmajor, struct nvlist *options) maxbdevm = MAX(maxbdevm, dm->dm_bmajor); } -void +int fixdevis(void) { struct devi *i; + int error = 0; TAILQ_FOREACH(i, &alldevi, i_next) - if (i->i_active) + if (i->i_active == DEVI_ACTIVE) selectbase(i->i_base, i->i_atdeva); - else + else if (i->i_active == DEVI_ORPHAN) { /* * At this point, we can't have instances for which * i_at or i_pspec are NULL. */ + ++error; (void)fprintf(stderr, "%s:%d: `%s at %s' is orphaned" " (%s `%s' found)\n", conffile, i->i_lineno, i->i_name, i->i_at, i->i_pspec->p_atunit == WILD ? "nothing matching" : "no", i->i_at); + } else if (vflag && i->i_active == DEVI_IGNORED) + (void)fprintf(stderr, "%s:%d: ignoring explicitely" + " orphaned instance `%s at %s'\n", conffile, + i->i_lineno, i->i_name, i->i_at); + + if (error) + return error; TAILQ_FOREACH(i, &allpseudo, i_next) - if (i->i_active) + if (i->i_active == DEVI_ACTIVE) selectbase(i->i_base, NULL); + return 0; } /* diff --git a/usr.bin/config/sem.h b/usr.bin/config/sem.h index f9d290f3cee4..d973fe6103bf 100644 --- a/usr.bin/config/sem.h +++ b/usr.bin/config/sem.h @@ -1,4 +1,4 @@ -/* $NetBSD: sem.h,v 1.2 2005/09/30 22:51:46 cube Exp $ */ +/* $NetBSD: sem.h,v 1.3 2005/10/01 23:30:37 cube Exp $ */ /* * Copyright (c) 1992, 1993 @@ -65,7 +65,7 @@ void deldev(const char *); void addpseudo(const char *, int); void delpseudo(const char *); void adddevm(const char *, int, int, struct nvlist *); -void fixdevis(void); +int fixdevis(void); const char *ref(const char *); const char *starref(const char *); const char *wildref(const char *);