]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - policy.c
Assemble: add support for RAID0 layouts.
[thirdparty/mdadm.git] / policy.c
index 48eed6c8e16416b747beb94eb31067b192becc14..3c53bd35e0b19a693ff84b81a927f27c3084048d 100644 (file)
--- a/policy.c
+++ b/policy.c
@@ -189,48 +189,40 @@ struct dev_policy *pol_find(struct dev_policy *pol, char *name)
        return pol;
 }
 
-static char *disk_path(struct mdinfo *disk)
+static char **disk_paths(struct mdinfo *disk)
 {
        struct stat stb;
        int prefix_len;
        DIR *by_path;
        char symlink[PATH_MAX] = "/dev/disk/by-path/";
-       char nm[PATH_MAX];
+       char **paths;
+       int cnt = 0;
        struct dirent *ent;
-       int rv;
 
-       by_path = opendir(symlink);
-       if (!by_path)
-               return NULL;
-       prefix_len = strlen(symlink);
+       paths = xmalloc(sizeof(*paths) * (cnt+1));
 
-       while ((ent = readdir(by_path)) != NULL) {
-               if (ent->d_type != DT_LNK)
-                       continue;
-               strncpy(symlink + prefix_len,
-                       ent->d_name,
-                       sizeof(symlink) - prefix_len);
-               if (stat(symlink, &stb) < 0)
-                       continue;
-               if ((stb.st_mode & S_IFMT) != S_IFBLK)
-                       continue;
-               if (stb.st_rdev != makedev(disk->disk.major, disk->disk.minor))
-                       continue;
+       by_path = opendir(symlink);
+       if (by_path) {
+               prefix_len = strlen(symlink);
+               while ((ent = readdir(by_path)) != NULL) {
+                       if (ent->d_type != DT_LNK)
+                               continue;
+                       strncpy(symlink + prefix_len,
+                                       ent->d_name,
+                                       sizeof(symlink) - prefix_len);
+                       if (stat(symlink, &stb) < 0)
+                               continue;
+                       if ((stb.st_mode & S_IFMT) != S_IFBLK)
+                               continue;
+                       if (stb.st_rdev != makedev(disk->disk.major, disk->disk.minor))
+                               continue;
+                       paths[cnt++] = xstrdup(ent->d_name);
+                       paths = xrealloc(paths, sizeof(*paths) * (cnt+1));
+               }
                closedir(by_path);
-               return xstrdup(ent->d_name);
        }
-       closedir(by_path);
-       /* A NULL path isn't really acceptable - use the devname.. */
-       sprintf(symlink, "/sys/dev/block/%d:%d", disk->disk.major, disk->disk.minor);
-       rv = readlink(symlink, nm, sizeof(nm)-1);
-       if (rv > 0) {
-               char *dname;
-               nm[rv] = 0;
-               dname = strrchr(nm, '/');
-               if (dname)
-                       return xstrdup(dname + 1);
-       }
-       return xstrdup("unknown");
+       paths[cnt] = NULL;
+       return paths;
 }
 
 char type_part[] = "part";
@@ -247,18 +239,53 @@ static char *disk_type(struct mdinfo *disk)
                return type_disk;
 }
 
-static int pol_match(struct rule *rule, char *path, char *type)
+static int path_has_part(char *path, char **part)
 {
-       /* check if this rule matches on path and type */
+       /* check if path ends with "-partNN" and
+        * if it does, place a pointer to "-pathNN"
+        * in 'part'.
+        */
+       int l;
+       if (!path)
+               return 0;
+       l = strlen(path);
+       while (l > 1 && isdigit(path[l-1]))
+               l--;
+       if (l < 5 || strncmp(path+l-5, "-part", 5) != 0)
+               return 0;
+       *part = path+l-5;
+       return 1;
+}
+
+static int pol_match(struct rule *rule, char **paths, char *type, char **part)
+{
+       /* Check if this rule matches on any path and type.
+        * If 'part' is not NULL, then 'path' must end in -partN, which
+        * we ignore for matching, and return in *part on success.
+        */
        int pathok = 0; /* 0 == no path, 1 == match, -1 == no match yet */
        int typeok = 0;
 
-       while (rule) {
+       for (; rule; rule = rule->next) {
                if (rule->name == rule_path) {
+                       char *p = NULL;
+                       int i;
                        if (pathok == 0)
                                pathok = -1;
-                       if (path && fnmatch(rule->value, path, 0) == 0)
-                               pathok = 1;
+                       if (!paths)
+                               continue;
+                       for (i = 0; paths[i]; i++) {
+                               if (part) {
+                                       if (!path_has_part(paths[i], &p))
+                                               continue;
+                                       *p = '\0';
+                                       *part = p+1;
+                               }
+                               if (fnmatch(rule->value, paths[i], 0) == 0)
+                                       pathok = 1;
+                               if (part)
+                                       *p = '-';
+                       }
                }
                if (rule->name == rule_type) {
                        if (typeok == 0)
@@ -266,7 +293,6 @@ static int pol_match(struct rule *rule, char *path, char *type)
                        if (type && strcmp(rule->value, type) == 0)
                                typeok = 1;
                }
-               rule = rule->next;
        }
        return pathok >= 0 && typeok >= 0;
 }
@@ -287,24 +313,6 @@ static void pol_merge(struct dev_policy **pol, struct rule *rule)
                        pol_new(pol, r->name, r->value, metadata);
 }
 
-static int path_has_part(char *path, char **part)
-{
-       /* check if path ends with "-partNN" and
-        * if it does, place a pointer to "-pathNN"
-        * in 'part'.
-        */
-       int l;
-       if (!path)
-               return 0;
-       l = strlen(path);
-       while (l > 1 && isdigit(path[l-1]))
-               l--;
-       if (l < 5 || strncmp(path+l-5, "-part", 5) != 0)
-               return 0;
-       *part = path+l-4;
-       return 1;
-}
-
 static void pol_merge_part(struct dev_policy **pol, struct rule *rule, char *part)
 {
        /* copy any name assignments from rule into pol, appending
@@ -353,7 +361,7 @@ static int config_rules_has_path = 0;
  * path_policy() gathers policy information for the
  * disk described in the given a 'path' and a 'type'.
  */
-struct dev_policy *path_policy(char *path, char *type)
+struct dev_policy *path_policy(char **paths, char *type)
 {
        struct pol_rule *rules;
        struct dev_policy *pol = NULL;
@@ -362,27 +370,24 @@ struct dev_policy *path_policy(char *path, char *type)
        rules = config_rules;
 
        while (rules) {
-               char *part;
+               char *part = NULL;
                if (rules->type == rule_policy)
-                       if (pol_match(rules->rule, path, type))
+                       if (pol_match(rules->rule, paths, type, NULL))
                                pol_merge(&pol, rules->rule);
                if (rules->type == rule_part && strcmp(type, type_part) == 0)
-                       if (path_has_part(path, &part)) {
-                               *part = 0;
-                               if (pol_match(rules->rule, path, type_disk))
-                                       pol_merge_part(&pol, rules->rule, part+1);
-                               *part = '-';
-                       }
+                       if (pol_match(rules->rule, paths, type_disk, &part))
+                                       pol_merge_part(&pol, rules->rule, part);
                rules = rules->next;
        }
 
        /* Now add any metadata-specific internal knowledge
         * about this path
         */
-       for (i=0; path && superlist[i]; i++)
+       for (i=0; paths && paths[0] && superlist[i]; i++)
                if (superlist[i]->get_disk_controller_domain) {
                        const char *d =
-                               superlist[i]->get_disk_controller_domain(path);
+                               superlist[i]->get_disk_controller_domain(
+                                       paths[0]);
                        if (d)
                                pol_new(&pol, pol_domain, d, superlist[i]->name);
                }
@@ -401,6 +406,17 @@ void pol_add(struct dev_policy **pol,
        pol_dedup(*pol);
 }
 
+static void free_paths(char **paths)
+{
+       int i;
+
+       if (!paths)
+               return;
+
+       for (i = 0; paths[i]; i++)
+               free(paths[i]);
+       free(paths);
+}
 
 /*
  * disk_policy() gathers policy information for the
@@ -408,16 +424,16 @@ void pol_add(struct dev_policy **pol,
  */
 struct dev_policy *disk_policy(struct mdinfo *disk)
 {
-       char *path = NULL;
+       char **paths = NULL;
        char *type = disk_type(disk);
        struct dev_policy *pol = NULL;
 
        if (config_rules_has_path)
-               path = disk_path(disk);
+               paths = disk_paths(disk);
 
-       pol = path_policy(path, type);
+       pol = path_policy(paths, type);
 
-       free(path);
+       free_paths(paths);
        return pol;
 }
 
@@ -592,7 +608,6 @@ int disk_action_allows(struct mdinfo *disk, const char *metadata, enum policy_ac
        return rv;
 }
 
-
 /* Domain policy:
  * Any device can have a list of domains asserted by different policy
  * statements.
@@ -664,6 +679,7 @@ int domain_test(struct domainlist *dom, struct dev_policy *pol,
         *  1:  has domains, all match
         */
        int found_any = -1;
+       int has_one_domain = 1;
        struct dev_policy *p;
 
        pol = pol_find(pol, pol_domain);
@@ -673,6 +689,9 @@ int domain_test(struct domainlist *dom, struct dev_policy *pol,
                        dom = dom->next;
                if (!dom || strcmp(dom->dom, p->value) != 0)
                        return 0;
+               if (has_one_domain && metadata && strcmp(metadata, "imsm") == 0)
+                       found_any = -1;
+               has_one_domain = 0;
        }
        return found_any;
 }
@@ -703,7 +722,6 @@ void domain_add(struct domainlist **domp, char *domain)
        domain_merge_one(domp, domain);
 }
 
-
 void domain_free(struct domainlist *dl)
 {
        while (dl) {
@@ -731,16 +749,14 @@ void policy_save_path(char *id_path, struct map_ent *array)
        FILE *f = NULL;
 
        if (mkdir(FAILED_SLOTS_DIR, S_IRWXU) < 0 && errno != EEXIST) {
-               pr_err("can't create file to save path "
-                       "to old disk: %s\n", strerror(errno));
+               pr_err("can't create file to save path to old disk: %s\n", strerror(errno));
                return;
        }
 
        snprintf(path, PATH_MAX, FAILED_SLOTS_DIR "/%s", id_path);
        f = fopen(path, "w");
        if (!f) {
-               pr_err("can't create file to"
-                       " save path to old disk: %s\n",
+               pr_err("can't create file to save path to old disk: %s\n",
                        strerror(errno));
                return;
        }
@@ -749,8 +765,7 @@ void policy_save_path(char *id_path, struct map_ent *array)
                    array->metadata,
                    array->uuid[0], array->uuid[1],
                    array->uuid[2], array->uuid[3]) <= 0)
-               pr_err("Failed to write to "
-                      "<id_path> cookie\n");
+               pr_err("Failed to write to <id_path> cookie\n");
 
        fclose(f);
 }
@@ -759,27 +774,26 @@ int policy_check_path(struct mdinfo *disk, struct map_ent *array)
 {
        char path[PATH_MAX];
        FILE *f = NULL;
-       char *id_path = disk_path(disk);
-       int rv;
+       char **id_paths = disk_paths(disk);
+       int i;
+       int rv = 0;
 
-       if (!id_path)
-               return 0;
+       for (i = 0; id_paths[i]; i++) {
+               snprintf(path, PATH_MAX, FAILED_SLOTS_DIR "/%s", id_paths[i]);
+               f = fopen(path, "r");
+               if (!f)
+                       continue;
 
-       snprintf(path, PATH_MAX, FAILED_SLOTS_DIR "/%s", id_path);
-       f = fopen(path, "r");
-       if (!f) {
-               free(id_path);
-               return 0;
+               rv = fscanf(f, " %s %x:%x:%x:%x\n",
+                           array->metadata,
+                           array->uuid,
+                           array->uuid+1,
+                           array->uuid+2,
+                           array->uuid+3);
+               fclose(f);
+               break;
        }
-
-       rv = fscanf(f, " %s %x:%x:%x:%x\n",
-                   array->metadata,
-                   array->uuid,
-                   array->uuid+1,
-                   array->uuid+2,
-                   array->uuid+3);
-       fclose(f);
-       free(id_path);
+       free_paths(id_paths);
        return rv == 5;
 }
 
@@ -803,12 +817,12 @@ char *find_rule(struct rule *rule, char *rule_type)
 #define UDEV_RULE_FORMAT \
 "ACTION==\"add\", SUBSYSTEM==\"block\", " \
 "ENV{DEVTYPE}==\"%s\", ENV{ID_PATH}==\"%s\", " \
-"RUN+=\"/sbin/mdadm --incremental $env{DEVNAME}\"\n"
+"RUN+=\"" BINDIR "/mdadm --incremental $env{DEVNAME}\"\n"
 
 #define UDEV_RULE_FORMAT_NOTYPE \
 "ACTION==\"add\", SUBSYSTEM==\"block\", " \
 "ENV{ID_PATH}==\"%s\", " \
-"RUN+=\"/sbin/mdadm --incremental $env{DEVNAME}\"\n"
+"RUN+=\"" BINDIR "/mdadm --incremental $env{DEVNAME}\"\n"
 
 /* Write rule in the rule file. Use format from UDEV_RULE_FORMAT */
 int write_rule(struct rule *rule, int fd, int force_part)
@@ -894,9 +908,8 @@ int Write_rules(char *rule_name)
                fd = 1;
 
        /* write static invocation */
-       if (write(fd, udev_template_start,
-                 sizeof(udev_template_start) - 1)
-           != (int)sizeof(udev_template_start)-1)
+       if (write(fd, udev_template_start, sizeof(udev_template_start) - 1) !=
+           (int)sizeof(udev_template_start) - 1)
                goto abort;
 
        /* iterate, if none created or error occurred, remove file */