multipathd: fix reservation_key check
[multipath-tools/.git] / libmultipath / config.c
index cbc8e4b..085a3e1 100644 (file)
@@ -6,6 +6,9 @@
 #include <stdio.h>
 #include <string.h>
 #include <libudev.h>
+#include <dirent.h>
+#include <limits.h>
+#include <errno.h>
 
 #include "checkers.h"
 #include "memory.h"
@@ -21,6 +24,8 @@
 #include "defaults.h"
 #include "prio.h"
 #include "devmapper.h"
+#include "mpath_cmd.h"
+#include "propsel.h"
 
 static int
 hwe_strmatch (struct hwentry *hwe1, struct hwentry *hwe2)
@@ -76,7 +81,8 @@ hwe_regmatch (struct hwentry *hwe1, struct hwentry *hwe2)
            regcomp(&rre, hwe1->revision, REG_EXTENDED|REG_NOSUB))
                goto out_pre;
 
-       if ((!hwe1->vendor || !hwe2->vendor ||
+       if ((hwe2->vendor || hwe2->product || hwe2->revision) &&
+           (!hwe1->vendor || !hwe2->vendor ||
             !regexec(&vre, hwe2->vendor, 0, NULL, 0)) &&
            (!hwe1->product || !hwe2->product ||
             !regexec(&pre, hwe2->product, 0, NULL, 0)) &&
@@ -120,8 +126,7 @@ find_hwe (vector hwtable, char * vendor, char * product, char * revision)
        return ret;
 }
 
-extern struct mpentry *
-find_mpe (char * wwid)
+struct mpentry *find_mpe(vector mptable, char *wwid)
 {
        int i;
        struct mpentry * mpe;
@@ -129,15 +134,14 @@ find_mpe (char * wwid)
        if (!wwid)
                return NULL;
 
-       vector_foreach_slot (conf->mptable, mpe, i)
+       vector_foreach_slot (mptable, mpe, i)
                if (mpe->wwid && !strcmp(mpe->wwid, wwid))
                        return mpe;
 
        return NULL;
 }
 
-extern char *
-get_mpe_wwid (char * alias)
+char *get_mpe_wwid(vector mptable, char *alias)
 {
        int i;
        struct mpentry * mpe;
@@ -145,7 +149,7 @@ get_mpe_wwid (char * alias)
        if (!alias)
                return NULL;
 
-       vector_foreach_slot (conf->mptable, mpe, i)
+       vector_foreach_slot (mptable, mpe, i)
                if (mpe->alias && strcmp(mpe->alias, alias) == 0)
                        return mpe->wwid;
 
@@ -315,6 +319,7 @@ set_param_str(char * str)
 static int
 merge_hwe (struct hwentry * dst, struct hwentry * src)
 {
+       char id[SCSI_VENDOR_SIZE+PATH_PRODUCT_SIZE];
        merge_str(vendor);
        merge_str(product);
        merge_str(revision);
@@ -340,16 +345,18 @@ merge_hwe (struct hwentry * dst, struct hwentry * src)
        merge_num(user_friendly_names);
        merge_num(retain_hwhandler);
        merge_num(detect_prio);
-
-       /*
-        * Make sure features is consistent with
-        * no_path_retry
-        */
-       if (dst->no_path_retry == NO_PATH_RETRY_FAIL)
-               remove_feature(&dst->features, "queue_if_no_path");
-       else if (dst->no_path_retry != NO_PATH_RETRY_UNDEF)
-               add_feature(&dst->features, "queue_if_no_path");
-
+       merge_num(detect_checker);
+       merge_num(deferred_remove);
+       merge_num(delay_watch_checks);
+       merge_num(delay_wait_checks);
+       merge_num(skip_kpartx);
+       merge_num(max_sectors_kb);
+       merge_num(ghost_delay);
+
+       snprintf(id, sizeof(id), "%s/%s", dst->vendor, dst->product);
+       reconcile_features_with_options(id, &dst->features,
+                                       &dst->no_path_retry,
+                                       &dst->retain_hwhandler);
        return 0;
 }
 
@@ -412,6 +419,8 @@ store_hwe (vector hwtable, struct hwentry * dhwe)
        hwe->user_friendly_names = dhwe->user_friendly_names;
        hwe->retain_hwhandler = dhwe->retain_hwhandler;
        hwe->detect_prio = dhwe->detect_prio;
+       hwe->detect_checker = dhwe->detect_checker;
+       hwe->ghost_delay = dhwe->ghost_delay;
 
        if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product)))
                goto out;
@@ -438,6 +447,13 @@ restart:
                        break;
                j = n;
                vector_foreach_slot_after(hw, hwe2, j) {
+                       /* drop invalid device configs */
+                       if (!hwe2->vendor || !hwe2->product) {
+                               condlog(0, "device config missing vendor or product parameter");
+                               vector_del_slot(hw, j--);
+                               free_hwe(hwe2);
+                               continue;
+                       }
                        if (hwe_regmatch(hwe1, hwe2))
                                continue;
                        /* dup */
@@ -471,9 +487,6 @@ free_config (struct config * conf)
        if (!conf)
                return;
 
-       if (conf->dev)
-               FREE(conf->dev);
-
        if (conf->multipath_dir)
                FREE(conf->multipath_dir);
 
@@ -483,6 +496,9 @@ free_config (struct config * conf)
        if (conf->uid_attribute)
                FREE(conf->uid_attribute);
 
+       if (conf->uid_attrs)
+               FREE(conf->uid_attrs);
+
        if (conf->getuid)
                FREE(conf->getuid);
 
@@ -497,6 +513,10 @@ free_config (struct config * conf)
 
        if (conf->wwids_file)
                FREE(conf->wwids_file);
+
+       if (conf->prkeys_file)
+               FREE(conf->prkeys_file);
+
        if (conf->prio_name)
                FREE(conf->prio_name);
 
@@ -510,8 +530,9 @@ free_config (struct config * conf)
 
        if (conf->checker_name)
                FREE(conf->checker_name);
-       if (conf->reservation_key)
-               FREE(conf->reservation_key);
+
+       if (conf->config_dir)
+               FREE(conf->config_dir);
 
        free_blacklist(conf->blist_devnode);
        free_blacklist(conf->blist_wwid);
@@ -530,14 +551,50 @@ free_config (struct config * conf)
        FREE(conf);
 }
 
-int
-load_config (char * file, struct udev *udev)
+/* if multipath fails to process the config directory, it should continue,
+ * with just a warning message */
+static void
+process_config_dir(struct config *conf, vector keywords, char *dir)
 {
-       if (!conf)
-               conf = alloc_config();
+       struct dirent **namelist;
+       int i, n;
+       char path[LINE_MAX];
+       int old_hwtable_size;
+
+       if (dir[0] != '/') {
+               condlog(1, "config_dir '%s' must be a fully qualified path",
+                       dir);
+               return;
+       }
+       n = scandir(dir, &namelist, NULL, alphasort);
+       if (n < 0) {
+               if (errno == ENOENT)
+                       condlog(3, "No configuration dir '%s'", dir);
+               else
+                       condlog(0, "couldn't open configuration dir '%s': %s",
+                               dir, strerror(errno));
+               return;
+       }
+       for (i = 0; i < n; i++) {
+               if (!strstr(namelist[i]->d_name, ".conf"))
+                       continue;
+               old_hwtable_size = VECTOR_SIZE(conf->hwtable);
+               snprintf(path, LINE_MAX, "%s/%s", dir, namelist[i]->d_name);
+               path[LINE_MAX-1] = '\0';
+               process_file(conf, path);
+               if (VECTOR_SIZE(conf->hwtable) > old_hwtable_size)
+                       factorize_hwtable(conf->hwtable, old_hwtable_size);
 
-       if (!conf || !udev)
-               return 1;
+       }
+}
+
+struct config *
+load_config (char * file)
+{
+       struct config *conf = alloc_config();
+
+       if (!conf)
+               return NULL;
 
        /*
         * internal defaults
@@ -545,27 +602,26 @@ load_config (char * file, struct udev *udev)
        if (!conf->verbosity)
                conf->verbosity = DEFAULT_VERBOSITY;
 
-       conf->udev = udev;
-       conf->dev_type = DEV_NONE;
-       conf->minio = DEFAULT_MINIO;
-       conf->minio_rq = DEFAULT_MINIO_RQ;
        get_sys_max_fds(&conf->max_fds);
        conf->bindings_file = set_default(DEFAULT_BINDINGS_FILE);
        conf->wwids_file = set_default(DEFAULT_WWIDS_FILE);
-       conf->bindings_read_only = 0;
+       conf->prkeys_file = set_default(DEFAULT_PRKEYS_FILE);
        conf->multipath_dir = set_default(DEFAULT_MULTIPATHDIR);
-       conf->features = set_default(DEFAULT_FEATURES);
-       conf->flush_on_last_del = 0;
        conf->attribute_flags = 0;
        conf->reassign_maps = DEFAULT_REASSIGN_MAPS;
        conf->checkint = DEFAULT_CHECKINT;
        conf->max_checkint = 0;
-       conf->pgfailback = DEFAULT_FAILBACK;
-       conf->fast_io_fail = DEFAULT_FAST_IO_FAIL;
-       conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER;
-       conf->detect_prio = DEFAULT_DETECT_PRIO;
-       conf->force_sync = 0;
-       conf->partition_delim = NULL;
+       conf->force_sync = DEFAULT_FORCE_SYNC;
+       conf->partition_delim = DEFAULT_PARTITION_DELIM;
+       conf->processed_main_config = 0;
+       conf->find_multipaths = DEFAULT_FIND_MULTIPATHS;
+       conf->uxsock_timeout = DEFAULT_REPLY_TIMEOUT;
+       conf->retrigger_tries = DEFAULT_RETRIGGER_TRIES;
+       conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY;
+       conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT;
+       conf->disable_changed_wwids = DEFAULT_DISABLE_CHANGED_WWIDS;
+       conf->remove_retries = 0;
+       conf->ghost_delay = DEFAULT_GHOST_DELAY;
 
        /*
         * preload default hwtable
@@ -582,13 +638,13 @@ load_config (char * file, struct udev *udev)
        /*
         * read the config file
         */
-       set_current_keywords(&conf->keywords);
-       alloc_keywords();
+       conf->keywords = vector_alloc();
+       init_keywords(conf->keywords);
        if (filepresent(file)) {
                int builtin_hwtable_size;
 
                builtin_hwtable_size = VECTOR_SIZE(conf->hwtable);
-               if (init_data(file, init_keywords)) {
+               if (process_file(conf, file)) {
                        condlog(0, "error parsing config file");
                        goto out;
                }
@@ -600,14 +656,19 @@ load_config (char * file, struct udev *udev)
                        factorize_hwtable(conf->hwtable, builtin_hwtable_size);
                }
 
-       } else {
-               init_keywords();
        }
-       if (conf->max_checkint == 0)
-               conf->max_checkint = MAX_CHECKINT(conf->checkint);
+
+       conf->processed_main_config = 1;
+       if (conf->config_dir == NULL)
+               conf->config_dir = set_default(DEFAULT_CONFIG_DIR);
+       if (conf->config_dir && conf->config_dir[0] != '\0')
+               process_config_dir(conf, conf->keywords, conf->config_dir);
+
        /*
         * fill the voids left in the config file
         */
+       if (conf->max_checkint == 0)
+               conf->max_checkint = MAX_CHECKINT(conf->checkint);
        if (conf->blist_devnode == NULL) {
                conf->blist_devnode = vector_alloc();
 
@@ -671,12 +732,11 @@ load_config (char * file, struct udev *udev)
                conf->bindings_file = set_default(DEFAULT_BINDINGS_FILE);
 
        if (!conf->multipath_dir || !conf->bindings_file ||
-           !conf->wwids_file)
+           !conf->wwids_file || !conf->prkeys_file)
                goto out;
 
-       return 0;
+       return conf;
 out:
        free_config(conf);
-       return 1;
+       return NULL;
 }
-