diff --git a/lib/filters/filter-persistent.c b/lib/filters/filter-persistent.c index 6fd2c6337..71728f36d 100644 --- a/lib/filters/filter-persistent.c +++ b/lib/filters/filter-persistent.c @@ -19,14 +19,15 @@ struct pfilter { char *file; struct hash_table *devices; + struct dev_filter *real; }; /* * entries in the table can be in one of these * states. */ -#define PF_UNCHECKED ((void *) 1) -#define PF_CHECKED ((void *) 2) +#define PF_BAD_DEVICE ((void *) 1) +#define PF_GOOD_DEVICE ((void *) 2) static int _init_hash(struct pfilter *pf) { @@ -34,30 +35,27 @@ static int _init_hash(struct pfilter *pf) hash_destroy(pf->devices); pf->devices = hash_create(128); - return pf ? 1 : 0; + return pf->devices ? 1 : 0; } -static int _load(struct pfilter *pf) +int persistent_filter_wipe(struct dev_filter *f) +{ + struct pfilter *pf = (struct pfilter *) f->private; + + hash_destroy(pf->devices); + return _init_hash(pf); +} + +static int _read_array(struct pfilter *pf, struct config_file *cf, + const char *path, void *data) { - int r = 0; - struct config_file *cf; struct config_node *cn; struct config_value *cv; - if (!(cf = create_config_file())) { - stack; - return 0; - } - - if (!read_config(cf, pf->file)) { - stack; - goto out; - } - if (!(cn = find_config_node(cf->root, "/valid_devices", '/'))) { log_info("Couldn't find 'valid_devices' array in '%s'", pf->file); - goto out; + return 0; } /* @@ -71,21 +69,69 @@ static int _load(struct pfilter *pf) continue; } - if (!hash_insert(pf->devices, cv->v.str, PF_UNCHECKED)) + if (!hash_insert(pf->devices, cv->v.str, data)) log_info("Couldn't add '%s' to filter ... ignoring", cv->v.str); } - r = 1; + return 1; +} + +int persistent_filter_load(struct dev_filter *f) +{ + struct pfilter *pf = (struct pfilter *) f->private; + + int r = 0; + struct config_file *cf; + + if (!(cf = create_config_file())) { + stack; + return 0; + } + + if (!read_config(cf, pf->file)) { + stack; + goto out; + } + + if (_read_array(pf, cf, "/valid_devices", PF_GOOD_DEVICE) && + _read_array(pf, cf, "/invalid_devices", PF_BAD_DEVICE)) + r = 1; out: destroy_config_file(cf); return r; } -static int _dump(struct pfilter *pf) +static void _write_array(struct pfilter *pf, FILE *fp, const char *path, + void *data) { + void *d; int first = 1; struct hash_node *n; + + fprintf(fp, "%s=[\n", path); + for (n = hash_get_first(pf->devices); n; + n = hash_get_next(pf->devices, n)) { + d = hash_get_data(pf->devices, n); + + if (d != data) + continue; + + if (!first) + fprintf(fp, ",\n"); + else + first = 0; + + fprintf(fp, "\t\"%s\"", hash_get_key(pf->devices, n)); + } + + fprintf(fp, "\n]\n"); +} + +int persistent_filter_dump(struct dev_filter *f) +{ + struct pfilter *pf = (struct pfilter *) f->private; + FILE *fp = fopen(pf->file, "w"); log_very_verbose("Dumping persistent device cache to %s", pf->file); @@ -97,80 +143,42 @@ static int _dump(struct pfilter *pf) } fprintf(fp, "# This file is automatically maintained by lvm.\n\n"); - fprintf(fp, "valid_devices=[\n"); - for (n = hash_get_first(pf->devices); n; - n = hash_get_next(pf->devices, n)) { - if (!first) - fprintf(fp, ",\n"); - else - first = 0; + _write_array(pf, fp, "valid_devices", PF_GOOD_DEVICE); + _write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); - fprintf(fp, "\t\"%s\"", hash_get_key(pf->devices, n)); - } - - fprintf(fp, "\n]\n"); fclose(fp); return 1; } -static int _check(const char *path) -{ - int fd = open(path, O_RDONLY), r = 0; - - if (fd >= 0) - r = 1; - else - log_debug("Unable to open %s: %s", path, strerror(errno)); - - close(fd); - return r; -} - -static int _init_valid_p(struct dev_filter *f, struct device *dev) +static int _lookup_p(struct dev_filter *f, struct device *dev) { struct pfilter *pf = (struct pfilter *) f->private; void *l = hash_lookup(pf->devices, dev->name); - if (l) - return 1; + if (!l) { + l = pf->real->passes_filter(pf->real, dev) ? + PF_GOOD_DEVICE : PF_BAD_DEVICE; - if (_check(dev->name)) { - hash_insert(pf->devices, dev->name, PF_CHECKED); - return 1; + hash_insert(pf->devices, dev->name, l); } - return 0; -} - -static int _valid_p(struct dev_filter *f, struct device *dev) -{ - struct pfilter *pf = (struct pfilter *) f->private; - void *l = hash_lookup(pf->devices, dev->name); - - if (!l) - return 0; - - if (l == PF_UNCHECKED && !_check(dev->name)) { - hash_remove(pf->devices, dev->name); - return 0; - } - - return 1; + return l == PF_GOOD_DEVICE; } static void _destroy(struct dev_filter *f) { struct pfilter *pf = (struct pfilter *) f->private; - _dump(pf); hash_destroy(pf->devices); dbg_free(pf->file); + pf->real->destroy(pf->real); dbg_free(pf); dbg_free(f); } -struct dev_filter *persistent_filter_create(const char *file, int init) +struct dev_filter *persistent_filter_create(struct dev_filter *real, + const char *file) { struct pfilter *pf; struct dev_filter *f = NULL; @@ -186,21 +194,19 @@ struct dev_filter *persistent_filter_create(const char *file, int init) goto bad; } strcpy(pf->file, file); + pf->real = real; if (!(_init_hash(pf))) { log_err("Couldn't create hash table for persistent filter."); goto bad; } - if (!init) - _load(pf); - if (!(f = dbg_malloc(sizeof(*f)))) { stack; goto bad; } - f->passes_filter = init ? _init_valid_p : _valid_p; + f->passes_filter = _lookup_p; f->destroy = _destroy; f->private = pf; @@ -214,4 +220,3 @@ struct dev_filter *persistent_filter_create(const char *file, int init) dbg_free(f); return NULL; } - diff --git a/lib/filters/filter-persistent.h b/lib/filters/filter-persistent.h index 6d68e1c4d..3accc7537 100644 --- a/lib/filters/filter-persistent.h +++ b/lib/filters/filter-persistent.h @@ -9,6 +9,11 @@ #include "dev-cache.h" -struct dev_filter *persistent_filter_create(const char *file, int init); +struct dev_filter *persistent_filter_create(struct dev_filter *f, + const char *file); + +int persistent_filter_wipe(struct dev_filter *f); +int persistent_filter_load(struct dev_filter *f); +int persistent_filter_dump(struct dev_filter *f); #endif