Convert 'auto' config line to policy statements

This commit is contained in:
NeilBrown 2010-09-02 21:21:36 +10:00
parent 61018da020
commit 4e8d9f0a16
5 changed files with 167 additions and 68 deletions

View File

@ -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)

View File

@ -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

176
config.c
View File

@ -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)
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;
pol = pol_find(pol, pol_auto);
pol_for_each(p, pol, version) {
if (strcmp(p->value, "yes") == 0)
return 1;
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;

View File

@ -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);

View File

@ -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;