Imported Upstream version 0.6.1
[platform/upstream/multipath-tools.git] / libmultipath / callout.c
index c2ba2a4..d671b0c 100644 (file)
 #include <unistd.h>
 #include <sys/types.h>
 #include <stdlib.h>
+#include <fcntl.h>
 #include <sys/wait.h>
 #include <errno.h>
 
-#define PROGRAM_SIZE   100
-#define FIELD_PROGRAM
-
-#define strfieldcpy(to, from) \
-do { \
-       to[sizeof(to)-1] = '\0'; \
-       strncpy(to, from, sizeof(to)-1); \
-} while (0)
+#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];
+       int fds[2], null_fd;
        pid_t pid;
        char *pos;
-       char arg[PROGRAM_SIZE];
-       char *argv[sizeof(arg) / 2];
+       char arg[CALLOUT_MAX_SIZE];
+       int argc = sizeof(arg) / 2;
+       char *argv[argc + 1];
        int i;
 
        i = 0;
 
        if (strchr(path, ' ')) {
-               strfieldcpy(arg, path);
+               strlcpy(arg, path, sizeof(arg));
                pos = arg;
-               while (pos != NULL) {
+               while (pos != NULL && i < argc) {
                        if (pos[0] == '\'') {
                                /* don't separate if in apostrophes */
                                pos++;
@@ -58,9 +57,10 @@ int execute_program(char *path, char *value, int len)
 
        retval = pipe(fds);
 
-       if (retval != 0)
+       if (retval != 0) {
+               condlog(0, "error creating pipe for callout: %s", strerror(errno));
                return -1;
-
+       }
 
        pid = fork();
 
@@ -70,12 +70,24 @@ int execute_program(char *path, char *value, int len)
                close(STDOUT_FILENO);
 
                /* dup write side of pipe to STDOUT */
-               dup(fds[1]);
+               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] */
@@ -89,13 +101,16 @@ int execute_program(char *path, char *value, int len)
 
                        i += count;
                        if (i >= len-1) {
+                               condlog(0, "not enough space for response from %s", argv[0]);
                                retval = -1;
                                break;
                        }
                }
 
-               if (count < 0)
+               if (count < 0) {
+                       condlog(0, "no response from %s", argv[0]);
                        retval = -1;
+               }
 
                if (i > 0 && value[i-1] == '\n')
                        i--;
@@ -104,8 +119,100 @@ int execute_program(char *path, char *value, int len)
                wait(&status);
                close(fds[0]);
 
-               if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
-                       retval = -1;
+               retval = -1;
+               if (WIFEXITED(status)) {
+                       status = WEXITSTATUS(status);
+                       if (status == 0)
+                               retval = 0;
+                       else
+                               condlog(0, "%s exited 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) {
+               condlog(3, "formatted callout = %s", dst);
+               return 0;
+       }
+
+       len = strlen(pos) + 1;
+       myfree -= len;
+
+       if (myfree < 2)
+               return 1;
+
+       snprintf(p, len, "%s", pos);
+       condlog(3, "reformatted callout = %s", dst);
+       return 0;
+}