Git init
[external/ifupdown.git] / execute.c
1 #line 2076 "ifupdown.nw"
2 #include <stdio.h>
3 #include <ctype.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <assert.h>
7
8 #include "header.h"
9 #line 2698 "ifupdown.nw"
10 #include <errno.h>
11 #line 2884 "ifupdown.nw"
12 #include <stdarg.h>
13 #line 2907 "ifupdown.nw"
14 #include <unistd.h>
15 #include <sys/wait.h>
16 #line 2160 "ifupdown.nw"
17 static char **environ = NULL;
18 #line 2137 "ifupdown.nw"
19 static int check(char *str);
20 #line 2167 "ifupdown.nw"
21 static void set_environ(interface_defn *iface, char *mode, char *phase);
22 #line 2245 "ifupdown.nw"
23 static char *setlocalenv(char *format, char *name, char *value);
24 #line 2358 "ifupdown.nw"
25 static int doit(char *str);
26 #line 2525 "ifupdown.nw"
27 static char *parse(char *command, interface_defn *ifd);
28 #line 2572 "ifupdown.nw"
29 void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t strlen);
30 #line 2779 "ifupdown.nw"
31 int strncmpz(char *l, char *r, size_t llen);
32 #line 2796 "ifupdown.nw"
33 char *get_var(char *id, size_t idlen, interface_defn *ifd);
34 #line 2888 "ifupdown.nw"
35 static int popen2(FILE **in, FILE **out, char *command, ...);
36 #line 2141 "ifupdown.nw"
37 static int check(char *str) {
38         return str != NULL;
39 }
40 #line 2173 "ifupdown.nw"
41 static void set_environ(interface_defn *iface, char *mode, char *phase) {
42         
43 #line 2202 "ifupdown.nw"
44 char **environend;
45 #line 2175 "ifupdown.nw"
46         int i;
47         const int n_env_entries = iface->n_options + 8;
48
49         
50 #line 2215 "ifupdown.nw"
51 if (environ != NULL) {
52         char **ppch;
53         for (ppch = environ; *ppch; ppch++) {
54                 free(*ppch);
55                 *ppch = NULL;
56         }
57         free(environ);
58         environ = NULL;
59 }
60 #line 2209 "ifupdown.nw"
61 environ = malloc(sizeof(char*) * (n_env_entries + 1 /* for final NULL */));
62 environend = environ; 
63 *environend = NULL;
64
65 #line 2180 "ifupdown.nw"
66         for (i = 0; i < iface->n_options; i++) {
67                 
68 #line 2229 "ifupdown.nw"
69 if (strcmp(iface->option[i].name, "pre-up") == 0
70     || strcmp(iface->option[i].name, "up") == 0
71     || strcmp(iface->option[i].name, "down") == 0
72     || strcmp(iface->option[i].name, "post-down") == 0)
73 {
74         continue;
75 }
76
77 #line 2183 "ifupdown.nw"
78                 
79 #line 2251 "ifupdown.nw"
80 *(environend++) = setlocalenv("IF_%s=%s", iface->option[i].name,
81                               iface->option[i].value);
82 *environend = NULL;
83 #line 2184 "ifupdown.nw"
84         }
85
86         
87 #line 2257 "ifupdown.nw"
88 *(environend++) = setlocalenv("%s=%s", "IFACE", iface->real_iface);
89 *environend = NULL;
90 #line 2187 "ifupdown.nw"
91         
92 #line 2262 "ifupdown.nw"
93 *(environend++) = setlocalenv("%s=%s", "LOGICAL", iface->logical_iface);
94 *environend = NULL;
95 #line 2188 "ifupdown.nw"
96         
97 #line 2287 "ifupdown.nw"
98 *(environend++) = setlocalenv("%s=%s", "ADDRFAM", iface->address_family->name);
99 *environend = NULL;
100 #line 2189 "ifupdown.nw"
101         
102 #line 2292 "ifupdown.nw"
103 *(environend++) = setlocalenv("%s=%s", "METHOD", iface->method->name);
104 *environend = NULL;
105
106 #line 2191 "ifupdown.nw"
107         
108 #line 2267 "ifupdown.nw"
109 *(environend++) = setlocalenv("%s=%s", "MODE", mode);
110 *environend = NULL;
111 #line 2192 "ifupdown.nw"
112         
113 #line 2272 "ifupdown.nw"
114 *(environend++) = setlocalenv("%s=%s", "PHASE", phase); 
115 *environend = NULL;
116 #line 2193 "ifupdown.nw"
117         
118 #line 2282 "ifupdown.nw"
119 *(environend++) = setlocalenv("%s=%s", "VERBOSITY", verbose ? "1" : "0");
120 *environend = NULL;
121 #line 2194 "ifupdown.nw"
122         
123 #line 2277 "ifupdown.nw"
124 *(environend++) = setlocalenv("%s=%s", "PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
125 *environend = NULL;
126 #line 2195 "ifupdown.nw"
127 }
128 #line 2299 "ifupdown.nw"
129 static char *setlocalenv(char *format, char *name, char *value) {
130         char *result;
131
132         
133 #line 2317 "ifupdown.nw"
134 result = malloc(strlen(format)   /* -4 for the two %s's */
135                 + strlen(name) 
136                 + strlen(value) 
137                 + 1);
138 if (!result) {
139         perror("malloc");
140         exit(1);
141 }
142
143 #line 2304 "ifupdown.nw"
144         sprintf(result, format, name, value);
145
146         
147 #line 2333 "ifupdown.nw"
148 {
149         char *here, *there;
150
151         for(here = there = result; *there != '=' && *there; there++) {
152                 if (*there == '-') *there = '_';
153                 if (isalpha(*there)) *there = toupper(*there);
154
155                 if (isalnum(*there) || *there == '_') {
156                         *here = *there;
157                         here++;
158                 }
159         }
160         memmove(here, there, strlen(there) + 1);
161 }
162
163 #line 2308 "ifupdown.nw"
164         return result;
165 }
166 #line 2362 "ifupdown.nw"
167 static int doit(char *str) {
168         assert(str);
169
170         if (verbose || no_act) {
171                 fprintf(stderr, "%s\n", str);
172         }
173         if (!no_act) {
174                 pid_t child;
175                 int status;
176
177                 fflush(NULL);
178                 switch(child = fork()) {
179                     case -1: /* failure */
180                         return 0;
181                     case 0: /* child */
182                         execle("/bin/sh", "/bin/sh", "-c", str, NULL, environ);
183                         exit(127);
184                     default: /* parent */
185                         break;
186                 }
187                 waitpid(child, &status, 0);
188                 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
189                         return 0;
190         }
191         return 1;
192 }
193 #line 2408 "ifupdown.nw"
194 int execute_all(interface_defn *ifd, execfn *exec, char *opt) {
195         int i;
196         char buf[100];
197         for (i = 0; i < ifd->n_options; i++) {
198                 if (strcmp(ifd->option[i].name, opt) == 0) {
199                         if (!(*exec)(ifd->option[i].value)) {
200                                 return 0;
201                         }
202                 }
203         }
204
205         snprintf(buf, sizeof(buf), "run-parts %s /etc/network/if-%s.d",
206                 verbose ? "--verbose" : "", opt);
207
208         (*exec)(buf); 
209
210         return 1;
211 }
212 #line 2438 "ifupdown.nw"
213 int iface_up(interface_defn *iface) {
214         if (!iface->method->up(iface,check)) return -1;
215
216         set_environ(iface, "start", "pre-up");
217         if (!execute_all(iface,doit,"pre-up")) return 0;
218
219         if (!iface->method->up(iface,doit)) return 0;
220
221         set_environ(iface, "start", "post-up");
222         if (!execute_all(iface,doit,"up")) return 0;
223
224         return 1;
225 }
226 #line 2454 "ifupdown.nw"
227 int iface_down(interface_defn *iface) {
228         if (!iface->method->down(iface,check)) return -1;
229
230         set_environ(iface, "stop", "pre-down");
231         if (!execute_all(iface,doit,"down")) return 0;
232
233         if (!iface->method->down(iface,doit)) return 0;
234
235         set_environ(iface, "stop", "post-down");
236         if (!execute_all(iface,doit,"post-down")) return 0;
237
238         return 1;
239 }
240 #line 2483 "ifupdown.nw"
241 int execute(char *command, interface_defn *ifd, execfn *exec) { 
242         char *out;
243         int ret;
244
245         out = parse(command, ifd);
246         if (!out) { return 0; }
247
248         ret = (*exec)(out);
249
250         free(out);
251         return ret;
252 }
253 #line 2529 "ifupdown.nw"
254 static char *parse(char *command, interface_defn *ifd) {
255         
256 #line 2554 "ifupdown.nw"
257 char *result = NULL;
258 size_t pos = 0, len = 0;
259 #line 2648 "ifupdown.nw"
260 size_t old_pos[MAX_OPT_DEPTH] = {0};
261 int okay[MAX_OPT_DEPTH] = {1};
262 int opt_depth = 1;
263
264 #line 2532 "ifupdown.nw"
265         while(*command) {
266                 switch(*command) {
267                         
268 #line 2602 "ifupdown.nw"
269 default:
270         addstr(&result, &len, &pos, command, 1);
271         command++;
272         break;
273 #line 2615 "ifupdown.nw"
274 case '\\':
275         if (command[1]) {
276                 addstr(&result, &len, &pos, command+1, 1);
277                 command += 2;
278         } else {
279                 addstr(&result, &len, &pos, command, 1);
280                 command++;
281         }
282         break;
283 #line 2663 "ifupdown.nw"
284 case '[':
285         if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) {
286                 old_pos[opt_depth] = pos;
287                 okay[opt_depth] = 1;
288                 opt_depth++;
289                 command += 2;
290         } else {
291                 addstr(&result, &len, &pos, "[", 1);
292                 command++;
293         }
294         break;
295 #line 2677 "ifupdown.nw"
296 case ']':
297         if (command[1] == ']' && opt_depth > 1) {
298                 opt_depth--;
299                 if (!okay[opt_depth]) {
300                         pos = old_pos[opt_depth];
301                         result[pos] = '\0';
302                 }
303                 command += 2;
304         } else {
305                 addstr(&result, &len, &pos, "]", 1);
306                 command++;
307         }
308         break;
309 #line 2732 "ifupdown.nw"
310 case '%':
311 {
312         
313 #line 2757 "ifupdown.nw"
314 char *nextpercent;
315 #line 2735 "ifupdown.nw"
316         char *varvalue;
317
318         
319 #line 2761 "ifupdown.nw"
320 command++;
321 nextpercent = strchr(command, '%');
322 if (!nextpercent) {
323         errno = EUNBALPER;
324         free(result);
325         return NULL;
326 }
327
328 #line 2739 "ifupdown.nw"
329         
330 #line 2820 "ifupdown.nw"
331 varvalue = get_var(command, nextpercent - command, ifd);
332
333 #line 2741 "ifupdown.nw"
334         if (varvalue) {
335                 addstr(&result, &len, &pos, varvalue, strlen(varvalue));
336         } else {
337                 okay[opt_depth - 1] = 0;
338         }
339
340         
341 #line 2771 "ifupdown.nw"
342 command = nextpercent + 1;
343
344 #line 2749 "ifupdown.nw"
345         break;
346 }
347 #line 2535 "ifupdown.nw"
348                 }
349         }
350
351         
352 #line 2707 "ifupdown.nw"
353 if (opt_depth > 1) {
354         errno = EUNBALBRACK;
355         free(result);
356         return NULL;
357 }
358
359 if (!okay[0]) {
360         errno = EUNDEFVAR;
361         free(result);
362         return NULL;
363 }
364
365 #line 2540 "ifupdown.nw"
366         
367 #line 2561 "ifupdown.nw"
368 return result;
369 #line 2541 "ifupdown.nw"
370 }
371 #line 2576 "ifupdown.nw"
372 void addstr(char **buf, size_t *len, size_t *pos, char *str, size_t strlen) {
373         assert(*len >= *pos);
374         assert(*len == 0 || (*buf)[*pos] == '\0');
375
376         if (*pos + strlen >= *len) {
377                 char *newbuf;
378                 newbuf = realloc(*buf, *len * 2 + strlen + 1);
379                 if (!newbuf) {
380                         perror("realloc");
381                         exit(1); /* a little ugly */
382                 }
383                 *buf = newbuf;
384                 *len = *len * 2 + strlen + 1;
385         }
386
387         while (strlen-- >= 1) {
388                 (*buf)[(*pos)++] = *str;
389                 str++;
390         }
391         (*buf)[*pos] = '\0';
392 }
393 #line 2783 "ifupdown.nw"
394 int strncmpz(char *l, char *r, size_t llen) {
395         int i = strncmp(l, r, llen);
396         if (i == 0)
397                 return -r[llen];
398         else
399                 return i;
400 }
401 #line 2800 "ifupdown.nw"
402 char *get_var(char *id, size_t idlen, interface_defn *ifd) {
403         int i;
404
405         if (strncmpz(id, "iface", idlen) == 0) {
406                 return ifd->real_iface;
407         } else {
408                 for (i = 0; i < ifd->n_options; i++) {
409                         if (strncmpz(id, ifd->option[i].name, idlen) == 0) {
410                                 return ifd->option[i].value;
411                         }
412                 }
413         }
414
415         return NULL;
416 }
417 #line 2839 "ifupdown.nw"
418 int run_mapping(char *physical, char *logical, int len, mapping_defn *map) {
419         FILE *in, *out;
420         int i, status;
421         pid_t pid;
422
423         
424 #line 2898 "ifupdown.nw"
425 pid = popen2(&in, &out, map->script, physical, NULL);
426 if (pid == 0) {
427         return 0;
428 }
429 #line 2845 "ifupdown.nw"
430         
431 #line 2857 "ifupdown.nw"
432 for (i = 0; i < map->n_mappings; i++) {
433         fprintf(in, "%s\n", map->mapping[i]);
434 }
435 fclose(in);
436 #line 2846 "ifupdown.nw"
437         
438 #line 2864 "ifupdown.nw"
439 waitpid(pid, &status, 0);
440 #line 2847 "ifupdown.nw"
441         
442 #line 2868 "ifupdown.nw"
443 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
444         if (fgets(logical, len, out)) {
445                 char *pch = logical + strlen(logical) - 1;
446                 while (pch >= logical && isspace(*pch)) 
447                         *(pch--) = '\0';
448         }
449 }
450 fclose(out);    
451
452 #line 2849 "ifupdown.nw"
453         return 1;
454 }
455 #line 2912 "ifupdown.nw"
456 static int popen2(FILE **in, FILE **out, char *command, ...) {
457         va_list ap;
458         char *argv[11] = {command};
459         int argc;
460         int infd[2], outfd[2];
461         pid_t pid;
462
463         argc = 1;
464         va_start(ap, command);
465         while((argc < 10) && (argv[argc] = va_arg(ap, char*))) {
466                 argc++;
467         }
468         argv[argc] = NULL; /* make sure */
469         va_end(ap);
470
471         if (pipe(infd) != 0) return 0;
472         if (pipe(outfd) != 0) {
473                 close(infd[0]); close(infd[1]);
474                 return 0;
475         }
476
477         fflush(NULL);
478         switch(pid = fork()) {
479                 case -1: /* failure */
480                         close(infd[0]); close(infd[1]);
481                         close(outfd[0]); close(outfd[1]);
482                         return 0;
483                 case 0: /* child */
484                         dup2(infd[0], 0);
485                         dup2(outfd[1], 1);
486                         close(infd[0]); close(infd[1]);
487                         close(outfd[0]); close(outfd[1]);
488                         execvp(command, argv);
489                         exit(127);
490                 default: /* parent */
491                         *in = fdopen(infd[1], "w");
492                         *out = fdopen(outfd[0], "r");
493                         close(infd[0]); close(outfd[1]);
494                         return pid;
495         }
496         /* unreached */
497 }