[libmultipath] move apply_format() from discovery.c to callout.c
[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 <sys/wait.h>
14 #include <errno.h>
15
16 #include "vector.h"
17 #include "structs.h"
18 #include "debug.h"
19
20 #define PROGRAM_SIZE    100
21 #define FIELD_PROGRAM
22
23 #define strfieldcpy(to, from) \
24 do { \
25         to[sizeof(to)-1] = '\0'; \
26         strncpy(to, from, sizeof(to)-1); \
27 } while (0)
28
29 int execute_program(char *path, char *value, int len)
30 {
31         int retval;
32         int count;
33         int status;
34         int fds[2];
35         pid_t pid;
36         char *pos;
37         char arg[PROGRAM_SIZE];
38         char *argv[sizeof(arg) / 2];
39         int i;
40
41         i = 0;
42
43         if (strchr(path, ' ')) {
44                 strfieldcpy(arg, path);
45                 pos = arg;
46                 while (pos != NULL) {
47                         if (pos[0] == '\'') {
48                                 /* don't separate if in apostrophes */
49                                 pos++;
50                                 argv[i] = strsep(&pos, "\'");
51                                 while (pos[0] == ' ')
52                                         pos++;
53                         } else {
54                                 argv[i] = strsep(&pos, " ");
55                         }
56                         i++;
57                 }
58         } else {
59                 argv[i++] = path;
60         }
61         argv[i] =  NULL;
62
63         retval = pipe(fds);
64
65         if (retval != 0)
66                 return -1;
67
68
69         pid = fork();
70
71         switch(pid) {
72         case 0:
73                 /* child */
74                 close(STDOUT_FILENO);
75
76                 /* dup write side of pipe to STDOUT */
77                 dup(fds[1]);
78
79                 retval = execv(argv[0], argv);
80
81                 exit(-1);
82         case -1:
83                 return -1;
84         default:
85                 /* parent reads from fds[0] */
86                 close(fds[1]);
87                 retval = 0;
88                 i = 0;
89                 while (1) {
90                         count = read(fds[0], value + i, len - i-1);
91                         if (count <= 0)
92                                 break;
93
94                         i += count;
95                         if (i >= len-1) {
96                                 retval = -1;
97                                 break;
98                         }
99                 }
100
101                 if (count < 0)
102                         retval = -1;
103
104                 if (i > 0 && value[i-1] == '\n')
105                         i--;
106                 value[i] = '\0';
107
108                 wait(&status);
109                 close(fds[0]);
110
111                 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
112                         retval = -1;
113         }
114         return retval;
115 }
116
117 extern int
118 apply_format (char * string, char * cmd, struct path * pp)
119 {
120         char * pos;
121         char * dst;
122         char * p;
123         int len;
124         int myfree;
125
126         if (!string)
127                 return 1;
128
129         if (!cmd)
130                 return 1;
131
132         dst = cmd;
133         p = dst;
134         pos = strchr(string, '%');
135         myfree = CALLOUT_MAX_SIZE;
136
137         if (!pos) {
138                 strcpy(dst, string);
139                 return 0;
140         }
141
142         len = (int) (pos - string) + 1;
143         myfree -= len;
144
145         if (myfree < 2)
146                 return 1;
147
148         snprintf(p, len, "%s", string);
149         p += len - 1;
150         pos++;
151
152         switch (*pos) {
153         case 'n':
154                 len = strlen(pp->dev) + 1;
155                 myfree -= len;
156
157                 if (myfree < 2)
158                         return 1;
159
160                 snprintf(p, len, "%s", pp->dev);
161                 p += len - 1;
162                 break;
163         case 'd':
164                 len = strlen(pp->dev_t) + 1;
165                 myfree -= len;
166
167                 if (myfree < 2)
168                         return 1;
169
170                 snprintf(p, len, "%s", pp->dev_t);
171                 p += len - 1;
172                 break;
173         default:
174                 break;
175         }
176         pos++;
177
178         if (!*pos)
179                 return 0;
180
181         len = strlen(pos) + 1;
182         myfree -= len;
183
184         if (myfree < 2)
185                 return 1;
186
187         snprintf(p, len, "%s", pos);
188         condlog(3, "reformated callout = %s", dst);
189         return 0;
190 }
191