multipath: Deprecate 'getuid' configuration variable
authorHannes Reinecke <hare@suse.de>
Tue, 16 Jul 2013 07:13:00 +0000 (09:13 +0200)
committerChristophe Varoqui <christophe.varoqui@opensvc.com>
Tue, 16 Jul 2013 19:49:17 +0000 (21:49 +0200)
Older versions of multipath-tools used the 'getuid_callout'
configuration variable to generate the WWID. So for compatibility
we should be accepting existing configurations, but mark the
variable as 'deprecated'.

Signed-off-by: Hannes Reinecke <hare@suse.de>
12 files changed:
libmultipath/Makefile
libmultipath/callout.c [new file with mode: 0644]
libmultipath/callout.h [new file with mode: 0644]
libmultipath/config.c
libmultipath/config.h
libmultipath/dict.c
libmultipath/discovery.c
libmultipath/propsel.c
libmultipath/structs.h
libmultipath/structs_vec.c
multipath.conf.annotated
multipath/multipath.conf.5

index 22d3844..ae1d8a3 100644 (file)
@@ -9,7 +9,7 @@ DEVLIB = libmultipath.so
 LIBS = $(DEVLIB).$(SONAME)
 LIBDEPS = -lpthread -ldl -ldevmapper -ludev
 
-OBJS = memory.o parser.o vector.o devmapper.o \
+OBJS = memory.o parser.o vector.o devmapper.o callout.o \
        hwtable.o blacklist.o util.o dmparser.o config.o \
        structs.o discovery.o propsel.o dict.o \
        pgpolicies.o debug.o regex.o defaults.o uevent.o \
diff --git a/libmultipath/callout.c b/libmultipath/callout.c
new file mode 100644 (file)
index 0000000..c35c7c0
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Source: copy of the udev package source file
+ *
+ * Copyrights of the source file apply
+ * Copyright (c) 2004 Christophe Varoqui
+ */
+#include <stdio.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#include "checkers.h"
+#include "vector.h"
+#include "structs.h"
+#include "util.h"
+#include "debug.h"
+
+int execute_program(char *path, char *value, int len)
+{
+       int retval;
+       int count;
+       int status;
+       int fds[2], null_fd;
+       pid_t pid;
+       char *pos;
+       char arg[CALLOUT_MAX_SIZE];
+       int argc = sizeof(arg) / 2;
+       char *argv[argc + 1];
+       int i;
+
+       i = 0;
+
+       if (strchr(path, ' ')) {
+               strlcpy(arg, path, sizeof(arg));
+               pos = arg;
+               while (pos != NULL && i < argc) {
+                       if (pos[0] == '\'') {
+                               /* don't separate if in apostrophes */
+                               pos++;
+                               argv[i] = strsep(&pos, "\'");
+                               while (pos[0] == ' ')
+                                       pos++;
+                       } else {
+                               argv[i] = strsep(&pos, " ");
+                       }
+                       i++;
+               }
+       } else {
+               argv[i++] = path;
+       }
+       argv[i] =  NULL;
+
+       retval = pipe(fds);
+
+       if (retval != 0) {
+               condlog(0, "error creating pipe for callout: %s", strerror(errno));
+               return -1;
+       }
+
+       pid = fork();
+
+       switch(pid) {
+       case 0:
+               /* child */
+               close(STDOUT_FILENO);
+
+               /* dup write side of pipe to STDOUT */
+               if (dup(fds[1]) < 0)
+                       return -1;
+
+               /* Ignore writes to stderr */
+               null_fd = open("/dev/null", O_WRONLY);
+               if (null_fd > 0) {
+                       close(STDERR_FILENO);
+                       retval = dup(null_fd);
+                       close(null_fd);
+               }
+
+               retval = execv(argv[0], argv);
+               condlog(0, "error execing %s : %s", argv[0], strerror(errno));
+               exit(-1);
+       case -1:
+               condlog(0, "fork failed: %s", strerror(errno));
+               close(fds[0]);
+               close(fds[1]);
+               return -1;
+       default:
+               /* parent reads from fds[0] */
+               close(fds[1]);
+               retval = 0;
+               i = 0;
+               while (1) {
+                       count = read(fds[0], value + i, len - i-1);
+                       if (count <= 0)
+                               break;
+
+                       i += count;
+                       if (i >= len-1) {
+                               condlog(0, "not enough space for response from %s", argv[0]);
+                               retval = -1;
+                               break;
+                       }
+               }
+
+               if (count < 0) {
+                       condlog(0, "no response from %s", argv[0]);
+                       retval = -1;
+               }
+
+               if (i > 0 && value[i-1] == '\n')
+                       i--;
+               value[i] = '\0';
+
+               wait(&status);
+               close(fds[0]);
+
+               retval = -1;
+               if (WIFEXITED(status)) {
+                       status = WEXITSTATUS(status);
+                       if (status == 0)
+                               retval = 0;
+                       else
+                               condlog(0, "%s exitted with %d", argv[0], status);
+               }
+               else if (WIFSIGNALED(status))
+                       condlog(0, "%s was terminated by signal %d", argv[0], WTERMSIG(status));
+               else
+                       condlog(0, "%s terminated abnormally", argv[0]);
+       }
+       return retval;
+}
+
+extern int
+apply_format (char * string, char * cmd, struct path * pp)
+{
+       char * pos;
+       char * dst;
+       char * p;
+       char * q;
+       int len;
+       int myfree;
+
+       if (!string)
+               return 1;
+
+       if (!cmd)
+               return 1;
+
+       dst = cmd;
+       p = dst;
+       pos = strchr(string, '%');
+       myfree = CALLOUT_MAX_SIZE;
+
+       if (!pos) {
+               strcpy(dst, string);
+               return 0;
+       }
+
+       len = (int) (pos - string) + 1;
+       myfree -= len;
+
+       if (myfree < 2)
+               return 1;
+
+       snprintf(p, len, "%s", string);
+       p += len - 1;
+       pos++;
+
+       switch (*pos) {
+       case 'n':
+               len = strlen(pp->dev) + 1;
+               myfree -= len;
+
+               if (myfree < 2)
+                       return 1;
+
+               snprintf(p, len, "%s", pp->dev);
+               for (q = p; q < p + len; q++) {
+                       if (q && *q == '!')
+                               *q = '/';
+               }
+               p += len - 1;
+               break;
+       case 'd':
+               len = strlen(pp->dev_t) + 1;
+               myfree -= len;
+
+               if (myfree < 2)
+                       return 1;
+
+               snprintf(p, len, "%s", pp->dev_t);
+               p += len - 1;
+               break;
+       default:
+               break;
+       }
+       pos++;
+
+       if (!*pos)
+               return 0;
+
+       len = strlen(pos) + 1;
+       myfree -= len;
+
+       if (myfree < 2)
+               return 1;
+
+       snprintf(p, len, "%s", pos);
+       condlog(3, "reformated callout = %s", dst);
+       return 0;
+}
diff --git a/libmultipath/callout.h b/libmultipath/callout.h
new file mode 100644 (file)
index 0000000..ab648e8
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _CALLOUT_H
+#define _CALLOUT_H
+
+int execute_program(char *, char *, int);
+int apply_format (char *, char *, struct path *);
+
+#endif /* _CALLOUT_H */
index a322dfe..c660a38 100644 (file)
@@ -167,6 +167,9 @@ free_hwe (struct hwentry * hwe)
        if (hwe->revision)
                FREE(hwe->revision);
 
+       if (hwe->getuid)
+               FREE(hwe->getuid);
+
        if (hwe->uid_attribute)
                FREE(hwe->uid_attribute);
 
@@ -224,6 +227,9 @@ free_mpe (struct mpentry * mpe)
        if (mpe->selector)
                FREE(mpe->selector);
 
+       if (mpe->getuid)
+               FREE(mpe->getuid);
+
        if (mpe->uid_attribute)
                FREE(mpe->uid_attribute);
 
@@ -312,6 +318,7 @@ merge_hwe (struct hwentry * dst, struct hwentry * src)
        merge_str(vendor);
        merge_str(product);
        merge_str(revision);
+       merge_str(getuid);
        merge_str(uid_attribute);
        merge_str(features);
        merge_str(hwhandler);
@@ -370,6 +377,9 @@ store_hwe (vector hwtable, struct hwentry * dhwe)
        if (dhwe->uid_attribute && !(hwe->uid_attribute = set_param_str(dhwe->uid_attribute)))
                goto out;
 
+       if (dhwe->getuid && !(hwe->getuid = set_param_str(dhwe->getuid)))
+               goto out;
+
        if (dhwe->features && !(hwe->features = set_param_str(dhwe->features)))
                goto out;
 
@@ -475,6 +485,9 @@ free_config (struct config * conf)
        if (conf->uid_attribute)
                FREE(conf->uid_attribute);
 
+       if (conf->getuid)
+               FREE(conf->getuid);
+
        if (conf->features)
                FREE(conf->features);
 
index 405a8f3..9aa88cf 100644 (file)
@@ -27,6 +27,7 @@ struct hwentry {
        char * product;
        char * revision;
        char * uid_attribute;
+       char * getuid;
        char * features;
        char * hwhandler;
        char * selector;
@@ -55,6 +56,7 @@ struct mpentry {
        char * wwid;
        char * alias;
        char * uid_attribute;
+       char * getuid;
        char * selector;
        char * features;
 
@@ -119,6 +121,7 @@ struct config {
        char * multipath_dir;
        char * selector;
        char * uid_attribute;
+       char * getuid;
        char * features;
        char * hwhandler;
        char * bindings_file;
index 14e7c57..f88d8c9 100644 (file)
@@ -160,6 +160,17 @@ def_uid_attribute_handler(vector strvec)
        return 0;
 }
 
+static int
+def_getuid_callout_handler(vector strvec)
+{
+       conf->getuid = set_value(strvec);
+
+       if (!conf->getuid)
+               return 1;
+
+       return 0;
+}
+
 static int
 def_prio_handler(vector strvec)
 {
@@ -982,6 +993,19 @@ hw_uid_attribute_handler(vector strvec)
        return 0;
 }
 
+static int
+hw_getuid_callout_handler(vector strvec)
+{
+       struct hwentry * hwe = VECTOR_LAST_SLOT(conf->hwtable);
+
+       hwe->getuid = set_value(strvec);
+
+       if (!hwe->getuid)
+               return 1;
+
+       return 0;
+}
+
 static int
 hw_selector_handler(vector strvec)
 {
@@ -2164,6 +2188,17 @@ snprint_hw_uid_attribute (char * buff, int len, void * data)
        return snprintf(buff, len, "\"%s\"", hwe->uid_attribute);
 }
 
+static int
+snprint_hw_getuid_callout (char * buff, int len, void * data)
+{
+       struct hwentry * hwe = (struct hwentry *)data;
+
+       if (!hwe->getuid)
+               return 0;
+
+       return snprintf(buff, len, "\"%s\"", hwe->getuid);
+}
+
 static int
 snprint_hw_prio (char * buff, int len, void * data)
 {
@@ -2502,6 +2537,15 @@ snprint_def_uid_attribute (char * buff, int len, void * data)
        return snprintf(buff, len, "\"%s\"", conf->uid_attribute);
 }
 
+static int
+snprint_def_getuid_callout (char * buff, int len, void * data)
+{
+       if (!conf->getuid)
+               return 0;
+
+       return snprintf(buff, len, "\"%s\"", conf->getuid);
+}
+
 static int
 snprint_def_prio (char * buff, int len, void * data)
 {
@@ -2805,6 +2849,7 @@ init_keywords(void)
        install_keyword("path_selector", &def_selector_handler, &snprint_def_selector);
        install_keyword("path_grouping_policy", &def_pgpolicy_handler, &snprint_def_path_grouping_policy);
        install_keyword("uid_attribute", &def_uid_attribute_handler, &snprint_def_uid_attribute);
+       install_keyword("getuid_callout", &def_getuid_callout_handler, &snprint_def_getuid_callout);
        install_keyword("prio", &def_prio_handler, &snprint_def_prio);
        install_keyword("prio_args", &def_prio_args_handler, &snprint_def_prio_args);
        install_keyword("features", &def_features_handler, &snprint_def_features);
@@ -2836,6 +2881,7 @@ init_keywords(void)
        __deprecated install_keyword("default_selector", &def_selector_handler, NULL);
        __deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
        __deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL);
+       __deprecated install_keyword("default_getuid_callout", &def_getuid_callout_handler, NULL);
        __deprecated install_keyword("default_features", &def_features_handler, NULL);
        __deprecated install_keyword("default_path_checker", &def_path_checker_handler, NULL);
 
@@ -2876,6 +2922,7 @@ init_keywords(void)
        install_keyword("product_blacklist", &bl_product_handler, &snprint_hw_bl_product);
        install_keyword("path_grouping_policy", &hw_pgpolicy_handler, &snprint_hw_path_grouping_policy);
        install_keyword("uid_attribute", &hw_uid_attribute_handler, &snprint_hw_uid_attribute);
+       install_keyword("getuid_callout", &hw_getuid_callout_handler, &snprint_hw_getuid_callout);
        install_keyword("path_selector", &hw_selector_handler, &snprint_hw_selector);
        install_keyword("path_checker", &hw_path_checker_handler, &snprint_hw_path_checker);
        install_keyword("checker", &hw_path_checker_handler, NULL);
index 6af5083..fcb8e4f 100644 (file)
@@ -20,6 +20,7 @@
 #include "structs.h"
 #include "config.h"
 #include "blacklist.h"
+#include "callout.h"
 #include "debug.h"
 #include "propsel.h"
 #include "sg_include.h"
@@ -974,9 +975,9 @@ static int
 get_uid (struct path * pp)
 {
        char *c;
-       const char *value;
+       const char *origin;
 
-       if (!pp->uid_attribute)
+       if (!pp->uid_attribute && !pp->getuid)
                select_getuid(pp);
 
        if (!pp->udev) {
@@ -985,23 +986,41 @@ get_uid (struct path * pp)
        }
 
        memset(pp->wwid, 0, WWID_SIZE);
-       value = udev_device_get_property_value(pp->udev, pp->uid_attribute);
-       if ((!value || strlen(value) == 0) && conf->dry_run == 2)
-               value = getenv(pp->uid_attribute);
-       if (value && strlen(value)) {
-               size_t len = WWID_SIZE;
-
-               if (strlen(value) + 1 > WWID_SIZE) {
-                       condlog(0, "%s: wwid overflow", pp->dev);
-               } else {
-                       len = strlen(value);
+       if (pp->getuid) {
+               char buff[CALLOUT_MAX_SIZE];
+
+               /* Use 'getuid' callout, deprecated */
+               condlog(1, "%s: using deprecated getuid callout", pp->dev);
+               if (apply_format(pp->getuid, &buff[0], pp)) {
+                       condlog(0, "error formatting uid callout command");
+                       memset(pp->wwid, 0, WWID_SIZE);
+               } else if (execute_program(buff, pp->wwid, WWID_SIZE)) {
+                       condlog(3, "error calling out %s", buff);
+                       memset(pp->wwid, 0, WWID_SIZE);
                }
-               strncpy(pp->wwid, value, len);
+               origin = "callout";
        } else {
-               condlog(3, "%s: no %s attribute", pp->dev,
-                       pp->uid_attribute);
+               const char *value;
+
+               value = udev_device_get_property_value(pp->udev,
+                                                      pp->uid_attribute);
+               if ((!value || strlen(value) == 0) && conf->dry_run == 2)
+                       value = getenv(pp->uid_attribute);
+               if (value && strlen(value)) {
+                       size_t len = WWID_SIZE;
+
+                       if (strlen(value) + 1 > WWID_SIZE) {
+                               condlog(0, "%s: wwid overflow", pp->dev);
+                       } else {
+                               len = strlen(value);
+                       }
+                       strncpy(pp->wwid, value, len);
+               } else {
+                       condlog(3, "%s: no %s attribute", pp->dev,
+                               pp->uid_attribute);
+               }
+               origin = "udev";
        }
-
        /* Strip any trailing blanks */
        c = strchr(pp->wwid, '\0');
        c--;
@@ -1009,8 +1028,8 @@ get_uid (struct path * pp)
                *c = '\0';
                c--;
        }
-       condlog(3, "%s: uid = %s (udev)", pp->dev,
-               *pp->wwid == '\0' ? "<empty>" : pp->wwid);
+       condlog(3, "%s: uid = %s (%s)", pp->dev,
+               *pp->wwid == '\0' ? "<empty>" : pp->wwid, origin);
        return 0;
 }
 
index a7e1fc2..19ef180 100644 (file)
@@ -371,12 +371,24 @@ select_getuid (struct path * pp)
                        pp->dev, pp->uid_attribute);
                return 0;
        }
+       if (pp->hwe && pp->hwe->getuid) {
+               pp->getuid = pp->hwe->getuid;
+               condlog(3, "%s: getuid = %s (deprecated) (controller setting)",
+                       pp->dev, pp->getuid);
+               return 0;
+       }
        if (conf->uid_attribute) {
                pp->uid_attribute = conf->uid_attribute;
                condlog(3, "%s: uid_attribute = %s (config file default)",
                        pp->dev, pp->uid_attribute);
                return 0;
        }
+       if (conf->getuid) {
+               pp->getuid = conf->getuid;
+               condlog(3, "%s: getuid = %s (deprecated) (config file default)",
+                       pp->dev, pp->getuid);
+               return 0;
+       }
        pp->uid_attribute = STRDUP(DEFAULT_UID_ATTRIBUTE);
        condlog(3, "%s: uid_attribute = %s (internal default)",
                pp->dev, pp->uid_attribute);
index 59387d6..fdeff23 100644 (file)
@@ -173,6 +173,7 @@ struct path {
        int pgindex;
        int detect_prio;
        char * uid_attribute;
+       char * getuid;
        struct prio prio;
        char * prio_args;
        struct checker checker;
index 72622b0..ef62219 100644 (file)
@@ -82,6 +82,7 @@ orphan_path (struct path * pp)
        pp->mpp = NULL;
        pp->dmstate = PSTATE_UNDEF;
        pp->uid_attribute = NULL;
+       pp->getuid = NULL;
        prio_put(&pp->prio);
        checker_put(&pp->checker);
        if (pp->fd >= 0)
index 09ed632..15ec468 100644 (file)
 #      path_grouping_policy    multibus
 #
 #      #
+#      # name    : uid_attribute
+#      # scope   : multipath & multipathd
+#      # desc    : the default udev attribute from which the path
+#      #           identifier should be generated.
+#      # default : ID_SERIAL
+#      #
+#      uid_attribute   "ID_SERIAL"
+#
+#      #
 #      # name    : getuid_callout
 #      # scope   : multipath & multipathd
 #      # desc    : the default program and args to callout to obtain a unique 
-#      #           path identifier. Absolute path required
+#      #           path identifier. This parameter is deprecated.
+#      #           This parameter is deprecated, superseded by uid_attribute
 #      # default : /lib/udev/scsi_id --whitelisted --device=/dev/%n
 #      #
 #      getuid_callout  "/lib/udev/scsi_id --whitelisted --device=/dev/%n"
index 70d15f3..ade9885 100644 (file)
@@ -144,6 +144,11 @@ The udev attribute providing a unique path
 identifier. Default value is
 .I ID_SERIAL
 .TP
+.B getuid_callout
+The default program and args to callout to obtain a unique path
+identifier. Should be specified with an absolute path.
+This parameter is deprecated; \fIuid_attribute\fR should be used instead.
+.TP
 .B prio
 The name of the path priority routine. The specified routine
 should return a numeric value specifying the relative priority