From 4e8d9f0a1650cd187554d7d34fd85c74441cbc7c Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 2 Sep 2010 21:21:36 +1000 Subject: [PATCH] Convert 'auto' config line to policy statements --- Assemble.c | 9 ++- Incremental.c | 2 +- config.c | 176 +++++++++++++++++++++++++++++++++----------------- mdadm.h | 6 +- policy.c | 42 +++++++++++- 5 files changed, 167 insertions(+), 68 deletions(-) diff --git a/Assemble.c b/Assemble.c index 23d0b826..e115ecac 100644 --- a/Assemble.c +++ b/Assemble.c @@ -230,6 +230,7 @@ int Assemble(struct supertype *st, char *mddev, int dfd; struct stat stb; struct supertype *tst = dup_super(st); + struct dev_policy *pol = NULL; if (tmpdev->used > 1) continue; @@ -271,7 +272,7 @@ int Assemble(struct supertype *st, char *mddev, tst->ss->free_super(tst); tmpdev->used = 2; } else if (auto_assem && st == NULL && - !conf_test_metadata(tst->ss->name, + !conf_test_metadata(tst->ss->name, (pol = devnum_policy(stb.st_rdev)), tst->ss->match_home(tst, homehost) == 1)) { if (report_missmatch) fprintf(stderr, Name ": %s has metadata type %s for which " @@ -403,6 +404,7 @@ int Assemble(struct supertype *st, char *mddev, devname); if (st) st->ss->free_super(st); + dev_policy_free(pol); return 1; } @@ -424,6 +426,7 @@ int Assemble(struct supertype *st, char *mddev, content = NULL; if (auto_assem) goto loop; + dev_policy_free(pol); return 1; } if (ident->member && ident->member[0]) { @@ -447,6 +450,7 @@ int Assemble(struct supertype *st, char *mddev, "only device given: confused and aborting\n", devname); st->ss->free_super(st); + dev_policy_free(pol); return 1; } if (verbose > 0) @@ -496,12 +500,15 @@ int Assemble(struct supertype *st, char *mddev, devname); tst->ss->free_super(tst); st->ss->free_super(st); + dev_policy_free(pol); return 1; } tmpdev->used = 1; loop: + dev_policy_free(pol); + pol = NULL; if (tmpdev->content) goto next_member; if (tst) diff --git a/Incremental.c b/Incremental.c index 3a41a1e1..a60be47a 100644 --- a/Incremental.c +++ b/Incremental.c @@ -246,7 +246,7 @@ int Incremental(char *devname, int verbose, int runstop, trustworthy = FOREIGN; - if (!match && !conf_test_metadata(st->ss->name, + if (!match && !conf_test_metadata(st->ss->name, policy, (trustworthy == LOCAL))) { if (verbose >= 1) fprintf(stderr, Name diff --git a/config.c b/config.c index 3baf7af4..bc450f94 100644 --- a/config.c +++ b/config.c @@ -677,24 +677,113 @@ void homehostline(char *line) } } -static char *auto_options = NULL; +char auto_yes[] = "yes"; +char auto_no[] = "no"; +char auto_homehost[] = "homehost"; + +static int auto_seen = 0; void autoline(char *line) { char *w; + char *seen; + int super_cnt; + char *dflt = auto_yes; + int homehost = 0; + int i; - if (auto_options) { + if (auto_seen) { fprintf(stderr, Name ": AUTO line may only be give once." " Subsequent lines ignored\n"); return; } + /* Parse the 'auto' line creating policy statements for the 'auto' policy. + * + * The default is 'yes' but the 'auto' line might over-ride that. + * Words in the line are processed in order with the first + * match winning. + * word can be: + * +version - that version can be assembled + * -version - that version cannot be auto-assembled + * yes or +all - any other version can be assembled + * no or -all - no other version can be assembled. + * homehost - any array associated by 'homehost' to this + * host can be assembled. + * + * Thus: + * +ddf -0.90 homehost -all + * will auto-assemble any ddf array, no 0.90 array, and + * any other array (imsm, 1.x) if and only if it is identified + * as belonging to this host. + * + * We translate that to policy by creating 'auto=yes' when we see + * a '+version' line, 'auto=no' if we see '-version' before 'homehost', + * or 'auto=homehost' if we see '-version' after 'homehost'. + * When we see yes, no, +all or -all we stop an any version that hasn't + * been seen gets an appropriate auto= entry. + */ - auto_options = dl_strdup(line); - dl_init(auto_options); + for (super_cnt = 0; superlist[super_cnt]; super_cnt++) + ; + seen = calloc(super_cnt, 1); - for (w=dl_next(line); w != line ; w=dl_next(w)) { - char *w2 = dl_strdup(w); - dl_add(auto_options, w2); + for (w = dl_next(line); w != line ; w = dl_next(w)) { + char *val; + + if (strcasecmp(w, "yes") == 0) { + dflt = auto_yes; + break; + } + if (strcasecmp(w, "no") == 0) { + if (homehost) + dflt = auto_homehost; + else + dflt = auto_no; + break; + } + if (strcasecmp(w, "homehost") == 0) { + homehost = 1; + continue; + } + if (w[0] == '+') + val = auto_yes; + else if (w[0] == '-') { + if (homehost) + val = auto_homehost; + else + val = auto_no; + } else + continue; + + if (strcasecmp(w+1, "all") == 0) { + dflt = val; + break; + } + for (i = 0; superlist[i]; i++) { + const char *version = superlist[i]->name; + if (strcasecmp(w+1, version) == 0) + break; + /* 1 matches 1.x, 0 matches 0.90 */ + if (version[1] == '.' && + strlen(w+1) == 1 && + w[1] == version[0]) + break; + /* 1.anything matches 1.x */ + if (strcmp(version, "1.x") == 0 && + strncmp(w+1, "1.", 2) == 0) + break; + } + if (superlist[i] == NULL) + /* ignore this word */ + continue; + if (seen[i]) + /* already know about this metadata */ + continue; + policy_add(rule_policy, pol_auto, val, pol_metadata, superlist[i]->name, NULL); + seen[i] = 1; } + for (i = 0; i < super_cnt; i++) + if (!seen[i]) + policy_add(rule_policy, pol_auto, dflt, pol_metadata, superlist[i]->name, NULL); } int loaded = 0; @@ -900,64 +989,30 @@ int conf_test_dev(char *devname) return 0; } -int conf_test_metadata(const char *version, int is_homehost) +int conf_test_metadata(const char *version, struct dev_policy *pol, int is_homehost) { - /* Check if the given metadata version is allowed - * to be auto-assembled. - * The default is 'yes' but the 'auto' line might over-ride that. - * Words in auto_options are processed in order with the first - * match winning. - * word can be: - * +version - that version can be assembled - * -version - that version cannot be auto-assembled - * yes or +all - any other version can be assembled - * no or -all - no other version can be assembled. - * homehost - any array associated by 'homehost' to this - * host can be assembled. - * - * Thus: - * +ddf -0.90 homehost -all - * will auto-assemble any ddf array, no 0.90 array, and - * any other array (imsm, 1.x) if and only if it is identified - * as belonging to this host. + /* If anyone said 'yes', that sticks. + * else if homehost applies, use that + * else if there is a 'no', say 'no'. + * else 'yes'. */ - char *w; + struct dev_policy *p; + int no=0, found_auto=0; load_conffile(); - if (!auto_options) - return 1; - for (w = dl_next(auto_options); w != auto_options; w = dl_next(w)) { - int rv; - if (strcasecmp(w, "yes") == 0) + + pol = pol_find(pol, pol_auto); + pol_for_each(p, pol, version) { + if (strcmp(p->value, "yes") == 0) return 1; - if (strcasecmp(w, "no") == 0) - return 0; - if (strcasecmp(w, "homehost") == 0) { - if (is_homehost) - return 1; - else - continue; - } - if (w[0] == '+') - rv = 1; - else if (w[0] == '-') - rv = 0; - else continue; - - if (strcasecmp(w+1, "all") == 0) - return rv; - if (strcasecmp(w+1, version) == 0) - return rv; - /* allow '0' to match version '0.90' - * and 1 or 1.whatever to match version '1.x' - */ - if (version[1] == '.' && - strlen(w+1) == 1 && - w[1] == version[0]) - return rv; - if (version[1] == '.' && version[2] == 'x' && - strncmp(w+1, version, 2) == 0) - return rv; + if (strcmp(p->value, "auto") == 0) + found_auto = 1; + if (strcmp(p->value, "no") == 0) + no = 1; } + if (is_homehost && found_auto) + return 1; + if (no) + return 0; return 1; } @@ -967,7 +1022,6 @@ int match_oneof(char *devices, char *devname) * matches devname */ - while (devices && *devices) { char patn[1024]; char *p = devices; diff --git a/mdadm.h b/mdadm.h index 89705603..9ad99f04 100644 --- a/mdadm.h +++ b/mdadm.h @@ -757,7 +757,7 @@ struct dev_policy { char *value; }; -extern char pol_act[], pol_domain[], pol_metadata[]; +extern char pol_act[], pol_domain[], pol_metadata[], pol_auto[]; /* iterate over the sublist starting at list, having the same * 'name' as 'list', and matching the given metadata (Where @@ -790,10 +790,12 @@ extern char rule_path[], rule_type[]; extern char type_part[], type_disk[]; extern void policyline(char *line, char *type); +extern void policy_add(char *type, ...); extern void policy_free(void); extern struct dev_policy *path_policy(char *path, char *type); extern struct dev_policy *disk_policy(struct mdinfo *disk); +extern struct dev_policy *devnum_policy(int dev); extern void dev_policy_free(struct dev_policy *p); extern void pol_new(struct dev_policy **pol, char *name, char *val, char *metadata); @@ -959,7 +961,7 @@ extern int parse_auto(char *str, char *msg, int config); extern mddev_ident_t conf_get_ident(char *dev); extern mddev_dev_t conf_get_devs(void); extern int conf_test_dev(char *devname); -extern int conf_test_metadata(const char *version, int is_homehost); +extern int conf_test_metadata(const char *version, struct dev_policy *pol, int is_homehost); extern struct createinfo *conf_get_create_info(void); extern void set_conffile(char *file); extern char *conf_get_mailaddr(void); diff --git a/policy.c b/policy.c index 8aa4cc8e..945d37ff 100644 --- a/policy.c +++ b/policy.c @@ -389,6 +389,14 @@ struct dev_policy *disk_policy(struct mdinfo *disk) return pol; } +struct dev_policy *devnum_policy(int dev) +{ + struct mdinfo disk; + disk.disk.major = major(dev); + disk.disk.minor = minor(dev); + return disk_policy(&disk); +} + /* * process policy rules read from config file. */ @@ -402,6 +410,7 @@ char rule_part[] = "part-policy"; char pol_metadata[] = "metadata"; char pol_act[] = "action"; char pol_domain[] = "domain"; +char pol_auto[] = "auto"; static int try_rule(char *w, char *name, struct rule **rp) { @@ -436,7 +445,8 @@ void policyline(char *line, char *type) else if (! try_rule(w, rule_type, &pr->rule) && ! try_rule(w, pol_metadata, &pr->rule) && ! try_rule(w, pol_act, &pr->rule) && - ! try_rule(w, pol_domain, &pr->rule)) + ! try_rule(w, pol_domain, &pr->rule) && + ! try_rule(w, pol_auto, &pr->rule)) fprintf(stderr, Name ": policy rule %s unrecognised and ignored\n", w); } @@ -444,6 +454,32 @@ void policyline(char *line, char *type) config_rules = pr; } +void policy_add(char *type, ...) +{ + va_list ap; + struct pol_rule *pr; + char *name, *val; + + pr = malloc(sizeof(*pr)); + pr->type = type; + pr->rule = NULL; + + va_start(ap, type); + while ((name = va_arg(ap, char*)) != NULL) { + struct rule *r; + + val = va_arg(ap, char*); + r = malloc(sizeof(*r)); + r->next = pr->rule; + r->name = name; + r->value = strdup(val); + r->dups = NULL; + pr->rule = r; + } + pr->next = config_rules; + config_rules = pr; +} + void policy_free(void) { while (config_rules) { @@ -580,9 +616,9 @@ int domain_test(struct domainlist *dom, struct dev_policy *pol, pol = pol_find(pol, pol_domain); pol_for_each(p, pol, metadata) { found_any = 1; - while (dom && strcmp(dom->dom, pol->value) < 0) + while (dom && strcmp(dom->dom, p->value) < 0) dom = dom->next; - if (!dom || strcmp(dom->dom, pol->value) != 0) + if (!dom || strcmp(dom->dom, p->value) != 0) return 0; } return found_any; -- 2.39.2