Don't print failure messages for callouts by default
[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                 return -1;
69
70
71         pid = fork();
72
73         switch(pid) {
74         case 0:
75                 /* child */
76                 close(STDOUT_FILENO);
77
78                 /* dup write side of pipe to STDOUT */
79                 if (dup(fds[1]) < 0)
80                         return -1;
81
82                 /* Ignore writes to stderr */
83                 null_fd = open("/dev/null", O_WRONLY);
84                 if (null_fd > 0) {
85                         close(STDERR_FILENO);
86                         dup(null_fd);
87                         close(null_fd);
88                 }
89
90                 retval = execv(argv[0], argv);
91
92                 exit(-1);
93         case -1:
94                 return -1;
95         default:
96                 /* parent reads from fds[0] */
97                 close(fds[1]);
98                 retval = 0;
99                 i = 0;
100                 while (1) {
101                         count = read(fds[0], value + i, len - i-1);
102                         if (count <= 0)
103                                 break;
104
105                         i += count;
106                         if (i >= len-1) {
107                                 retval = -1;
108                                 break;
109                         }
110                 }
111
112                 if (count < 0)
113                         retval = -1;
114
115                 if (i > 0 && value[i-1] == '\n')
116                         i--;
117                 value[i] = '\0';
118
119                 wait(&status);
120                 close(fds[0]);
121
122                 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
123                         retval = -1;
124         }
125         return retval;
126 }
127
128 extern int
129 apply_format (char * string, char * cmd, struct path * pp)
130 {
131         char * pos;
132         char * dst;
133         char * p;
134         int len;
135         int myfree;
136
137         if (!string)
138                 return 1;
139
140         if (!cmd)
141                 return 1;
142
143         dst = cmd;
144         p = dst;
145         pos = strchr(string, '%');
146         myfree = CALLOUT_MAX_SIZE;
147
148         if (!pos) {
149                 strcpy(dst, string);
150                 return 0;
151         }
152
153         len = (int) (pos - string) + 1;
154         myfree -= len;
155
156         if (myfree < 2)
157                 return 1;
158
159         snprintf(p, len, "%s", string);
160         p += len - 1;
161         pos++;
162
163         switch (*pos) {
164         case 'n':
165                 len = strlen(pp->dev) + 1;
166                 myfree -= len;
167
168                 if (myfree < 2)
169                         return 1;
170
171                 snprintf(p, len, "%s", pp->dev);
172                 p += len - 1;
173                 break;
174         case 'd':
175                 len = strlen(pp->dev_t) + 1;
176                 myfree -= len;
177
178                 if (myfree < 2)
179                         return 1;
180
181                 snprintf(p, len, "%s", pp->dev_t);
182                 p += len - 1;
183                 break;
184         default:
185                 break;
186         }
187         pos++;
188
189         if (!*pos)
190                 return 0;
191
192         len = strlen(pos) + 1;
193         myfree -= len;
194
195         if (myfree < 2)
196                 return 1;
197
198         snprintf(p, len, "%s", pos);
199         condlog(3, "reformated callout = %s", dst);
200         return 0;
201 }
202