Merge branch 'master' of git://git.kernel.org/pub/scm/linux/storage/multipath-tools/
[platform/upstream/multipath-tools.git] / libmultipath / callout.c
1 /*
2  * Source: copy of the udev package source file
3  *
4  * Copyrights of the source file apply
5  * Copyright (c) 2004 Christophe Varoqui
6  */
7 #include <stdio.h>
8 #include <sys/stat.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <sys/types.h>
12 #include <stdlib.h>
13 #include <fcntl.h>
14 #include <sys/wait.h>
15 #include <errno.h>
16
17 #include "checkers.h"
18 #include "vector.h"
19 #include "structs.h"
20 #include "debug.h"
21
22 #define PROGRAM_SIZE    100
23 #define FIELD_PROGRAM
24
25 #define strfieldcpy(to, from) \
26 do { \
27         to[sizeof(to)-1] = '\0'; \
28         strncpy(to, from, sizeof(to)-1); \
29 } while (0)
30
31 int execute_program(char *path, char *value, int len)
32 {
33         int retval;
34         int count;
35         int status;
36         int fds[2], null_fd;
37         pid_t pid;
38         char *pos;
39         char arg[PROGRAM_SIZE];
40         char *argv[sizeof(arg) / 2];
41         int i;
42
43         i = 0;
44
45         if (strchr(path, ' ')) {
46                 strfieldcpy(arg, path);
47                 pos = arg;
48                 while (pos != NULL) {
49                         if (pos[0] == '\'') {
50                                 /* don't separate if in apostrophes */
51                                 pos++;
52                                 argv[i] = strsep(&pos, "\'");
53                                 while (pos[0] == ' ')
54                                         pos++;
55                         } else {
56                                 argv[i] = strsep(&pos, " ");
57                         }
58                         i++;
59                 }
60         } else {
61                 argv[i++] = path;
62         }
63         argv[i] =  NULL;
64
65         retval = pipe(fds);
66
67         if (retval != 0) {
68                 condlog(0, "error creating pipe for callout: %s", strerror(errno));
69                 return -1;
70         }
71
72         pid = fork();
73
74         switch(pid) {
75         case 0:
76                 /* child */
77                 close(STDOUT_FILENO);
78
79                 /* dup write side of pipe to STDOUT */
80                 if (dup(fds[1]) < 0)
81                         return -1;
82
83                 /* Ignore writes to stderr */
84                 null_fd = open("/dev/null", O_WRONLY);
85                 if (null_fd > 0) {
86                         close(STDERR_FILENO);
87                         dup(null_fd);
88                         close(null_fd);
89                 }
90
91                 retval = execv(argv[0], argv);
92                 condlog(0, "error execing %s : %s", argv[0], strerror(errno));
93                 exit(-1);
94         case -1:
95                 condlog(0, "fork failed: %s", strerror(errno));
96                 close(fds[0]);
97                 close(fds[1]);
98                 return -1;
99         default:
100                 /* parent reads from fds[0] */
101                 close(fds[1]);
102                 retval = 0;
103                 i = 0;
104                 while (1) {
105                         count = read(fds[0], value + i, len - i-1);
106                         if (count <= 0)
107                                 break;
108
109                         i += count;
110                         if (i >= len-1) {
111                                 condlog(0, "not enough space for response from %s", argv[0]);
112                                 retval = -1;
113                                 break;
114                         }
115                 }
116
117                 if (count < 0) {
118                         condlog(0, "no response from %s", argv[0]);
119                         retval = -1;
120                 }
121
122                 if (i > 0 && value[i-1] == '\n')
123                         i--;
124                 value[i] = '\0';
125
126                 wait(&status);
127                 close(fds[0]);
128
129                 retval = -1;
130                 if (WIFEXITED(status)) {
131                         status = WEXITSTATUS(status);
132                         if (status == 0)
133                                 retval = 0;
134                         else
135                                 condlog(0, "%s exitted with %d", argv[0], status);
136                 }
137                 else if (WIFSIGNALED(status))
138                         condlog(0, "%s was terminated by signal %d", argv[0], WTERMSIG(status));
139                 else
140                         condlog(0, "%s terminated abnormally", argv[0]);
141         }
142         return retval;
143 }
144
145 extern int
146 apply_format (char * string, char * cmd, struct path * pp)
147 {
148         char * pos;
149         char * dst;
150         char * p;
151         int len;
152         int myfree;
153
154         if (!string)
155                 return 1;
156
157         if (!cmd)
158                 return 1;
159
160         dst = cmd;
161         p = dst;
162         pos = strchr(string, '%');
163         myfree = CALLOUT_MAX_SIZE;
164
165         if (!pos) {
166                 strcpy(dst, string);
167                 return 0;
168         }
169
170         len = (int) (pos - string) + 1;
171         myfree -= len;
172
173         if (myfree < 2)
174                 return 1;
175
176         snprintf(p, len, "%s", string);
177         p += len - 1;
178         pos++;
179
180         switch (*pos) {
181         case 'n':
182                 len = strlen(pp->dev) + 1;
183                 myfree -= len;
184
185                 if (myfree < 2)
186                         return 1;
187
188                 snprintf(p, len, "%s", pp->dev);
189                 p += len - 1;
190                 break;
191         case 'd':
192                 len = strlen(pp->dev_t) + 1;
193                 myfree -= len;
194
195                 if (myfree < 2)
196                         return 1;
197
198                 snprintf(p, len, "%s", pp->dev_t);
199                 p += len - 1;
200                 break;
201         default:
202                 break;
203         }
204         pos++;
205
206         if (!*pos)
207                 return 0;
208
209         len = strlen(pos) + 1;
210         myfree -= len;
211
212         if (myfree < 2)
213                 return 1;
214
215         snprintf(p, len, "%s", pos);
216         condlog(3, "reformated callout = %s", dst);
217         return 0;
218 }
219