Imported Upstream version 2.4.4p3
[debian/amanda] / common-src / pipespawn.c
1 #include "amanda.h"
2 #include "pipespawn.h"
3 #include "arglist.h"
4 #include "clock.h"
5
6 char skip_argument[1];
7
8 #ifdef STDC_HEADERS
9 int pipespawn(char *prog, int pipedef, int *stdinfd, int *stdoutfd,
10               int *stderrfd, ...)
11 #else
12 int pipespawn(prog, pipedef, stdinfd, stdoutfd, stderrfd, va_alist)
13 char *prog;
14 int pipedef;
15 int *stdinfd, *stdoutfd, *stderrfd;
16 va_dcl
17 #endif
18 {
19     va_list ap;
20     int argc;
21     char **argv;
22     int pid, i, inpipe[2], outpipe[2], errpipe[2], passwdpipe[2];
23     char *passwdvar = NULL;
24     int *passwdfd = NULL;
25     char number[NUM_STR_SIZE];
26     char *arg;
27     char *e;
28     int ch;
29     char **env;
30     char **newenv;
31
32     /*
33      * Log the command line and count the args.
34      */
35     dbprintf(("%s: spawning %s in pipeline\n", debug_prefix_time(NULL), prog));
36     dbprintf(("%s: argument list:", debug_prefix(NULL)));
37     arglist_start(ap, stderrfd);
38     if ((pipedef & PASSWD_PIPE) != 0) {
39         passwdvar = arglist_val(ap, char *);
40         passwdfd = arglist_val(ap, int *);
41     }
42     argc = 0;
43     while((arg = arglist_val(ap, char *)) != NULL) {
44         if (arg == skip_argument) {
45             continue;
46         }
47         argc++;
48         dbprintf((" "));
49         for(i = 0; (ch = arg[i]) != '\0' && isprint(ch) && ch != ' '; i++) {}
50         if(ch != '\0' || i == 0) {
51             dbprintf(("\""));
52         }
53         dbprintf(("%s", arg));
54         if(ch != '\0' || i == 0) {
55             dbprintf(("\""));
56         }
57     }
58     arglist_end(ap);
59     dbprintf(("\n"));
60
61     /*
62      * Create the pipes
63      */
64     if ((pipedef & STDIN_PIPE) != 0) {
65         if(pipe(inpipe) == -1) {
66             error("error [open pipe to %s: %s]", prog, strerror(errno));
67         }
68     }
69     if ((pipedef & STDOUT_PIPE) != 0) {
70         if(pipe(outpipe) == -1) {
71             error("error [open pipe to %s: %s]", prog, strerror(errno));
72         }
73     }
74     if ((pipedef & STDERR_PIPE) != 0) {
75         if(pipe(errpipe) == -1) {
76             error("error [open pipe to %s: %s]", prog, strerror(errno));
77         }
78     }
79     if ((pipedef & PASSWD_PIPE) != 0) {
80         if(pipe(passwdpipe) == -1) {
81             error("error [open pipe to %s: %s]", prog, strerror(errno));
82         }
83     }
84
85     /*
86      * Fork and set up the return or run the program.
87      */
88     switch(pid = fork()) {
89     case -1:
90         e = strerror(errno);
91         error("error [fork %s: %s]", prog, e);
92     default:    /* parent process */
93         if ((pipedef & STDIN_PIPE) != 0) {
94             aclose(inpipe[0]);          /* close input side of pipe */
95             *stdinfd = inpipe[1];
96         }
97         if ((pipedef & STDOUT_PIPE) != 0) {
98             aclose(outpipe[1]);         /* close output side of pipe */
99             *stdoutfd = outpipe[0];
100         }
101         if ((pipedef & STDERR_PIPE) != 0) {
102             aclose(errpipe[1]);         /* close output side of pipe */
103             *stderrfd = errpipe[0];
104         }
105         if ((pipedef & PASSWD_PIPE) != 0) {
106             aclose(passwdpipe[0]);      /* close input side of pipe */
107             *passwdfd = passwdpipe[1];
108         }
109         break;
110     case 0:             /* child process */
111         if ((pipedef & STDIN_PIPE) != 0) {
112             aclose(inpipe[1]);          /* close output side of pipe */
113         } else {
114             inpipe[0] = *stdinfd;
115         }
116         if ((pipedef & STDOUT_PIPE) != 0) {
117             aclose(outpipe[0]);         /* close input side of pipe */
118         } else {
119             outpipe[1] = *stdoutfd;
120         }
121         if ((pipedef & STDERR_PIPE) != 0) {
122             aclose(errpipe[0]);         /* close input side of pipe */
123         } else {
124             errpipe[1] = *stderrfd;
125         }
126         if ((pipedef & PASSWD_PIPE) != 0) {
127             aclose(passwdpipe[1]);      /* close output side of pipe */
128         }
129
130         /*
131          * Shift the pipes to the standard file descriptors as requested.
132          */
133         if(dup2(inpipe[0], 0) == -1) {
134             error("error [spawn %s: dup2 in: %s]", prog, strerror(errno));
135         }
136         if(dup2(outpipe[1], 1) == -1) {
137             error("error [spawn %s: dup2 out: %s]", prog, strerror(errno));
138         }
139         if(dup2(errpipe[1], 2) == -1) {
140             error("error [spawn %s: dup2 err: %s]", prog, strerror(errno));
141         }
142
143         /*
144          * Create the argument vector.
145          */
146         arglist_start(ap, stderrfd);
147         if ((pipedef & PASSWD_PIPE) != 0) {
148             passwdvar = arglist_val(ap, char *);
149             passwdfd = arglist_val(ap, int *);
150         }
151         argv = (char **)alloc((argc + 1) * sizeof(*argv));
152         i = 0;
153         while((argv[i] = arglist_val(ap, char *)) != NULL) {
154             if (argv[i] != skip_argument) {
155                 i++;
156             }
157         }
158         arglist_end(ap);
159
160         /*
161          * Get the "safe" environment.  If we are sending a password to
162          * the child via a pipe, add the environment variable for that.
163          */
164         env = safe_env();
165         if ((pipedef & PASSWD_PIPE) != 0) {
166             for(i = 0; env[i] != NULL; i++) {}
167             newenv = (char **)alloc((i + 1 + 1) * sizeof(*newenv));
168             ap_snprintf(number, sizeof(number), "%d", passwdpipe[0]);
169             newenv[0] = vstralloc(passwdvar, "=", number, NULL);
170             for(i = 0; (newenv[i + 1] = env[i]) != NULL; i++) {}
171             env = newenv;
172         }
173
174         execve(prog, argv, env);
175         e = strerror(errno);
176         error("error [exec %s: %s]", prog, e);
177         /* NOTREACHED */
178     }
179     return pid;
180 }
181
182 int pipespawnv(prog, pipedef, stdinfd, stdoutfd, stderrfd, my_argv)
183 char *prog;
184 int pipedef;
185 int *stdinfd, *stdoutfd, *stderrfd;
186 char **my_argv;
187 {
188     int argc;
189     int pid, i, inpipe[2], outpipe[2], errpipe[2], passwdpipe[2];
190     char *passwdvar = NULL;
191     int *passwdfd = NULL;
192     char number[NUM_STR_SIZE];
193     char **arg;
194     char *e;
195     int ch;
196     char **env;
197     char **newenv;
198
199     /*
200      * Log the command line and count the args.
201      */
202     dbprintf(("%s: spawning %s in pipeline\n", debug_prefix_time(NULL), prog));
203     dbprintf(("%s: argument list:", debug_prefix(NULL)));
204     if ((pipedef & PASSWD_PIPE) != 0) {
205         passwdvar = *my_argv++;
206         passwdfd = (int *)*my_argv++;
207     }
208     argc = 0;
209     for(arg = my_argv; *arg != NULL; arg++) {
210         if (*arg == skip_argument) {
211             continue;
212         }
213         argc++;
214         dbprintf((" "));
215         for(i = 0; (ch = (*arg)[i]) != '\0' && isprint(ch) && ch != ' '; i++) {}
216         if(ch != '\0' || i == 0) {
217             dbprintf(("\""));
218         }
219         dbprintf(("%s", *arg));
220         if(ch != '\0' || i == 0) {
221             dbprintf(("\""));
222         }
223     }
224     dbprintf(("\n"));
225
226     /*
227      * Create the pipes
228      */
229     if ((pipedef & STDIN_PIPE) != 0) {
230         if(pipe(inpipe) == -1) {
231             error("error [open pipe to %s: %s]", prog, strerror(errno));
232         }
233     }
234     if ((pipedef & STDOUT_PIPE) != 0) {
235         if(pipe(outpipe) == -1) {
236             error("error [open pipe to %s: %s]", prog, strerror(errno));
237         }
238     }
239     if ((pipedef & STDERR_PIPE) != 0) {
240         if(pipe(errpipe) == -1) {
241             error("error [open pipe to %s: %s]", prog, strerror(errno));
242         }
243     }
244     if ((pipedef & PASSWD_PIPE) != 0) {
245         if(pipe(passwdpipe) == -1) {
246             error("error [open pipe to %s: %s]", prog, strerror(errno));
247         }
248     }
249
250     /*
251      * Fork and set up the return or run the program.
252      */
253     switch(pid = fork()) {
254     case -1:
255         e = strerror(errno);
256         error("error [fork %s: %s]", prog, e);
257     default:    /* parent process */
258         if ((pipedef & STDIN_PIPE) != 0) {
259             aclose(inpipe[0]);          /* close input side of pipe */
260             *stdinfd = inpipe[1];
261         }
262         if ((pipedef & STDOUT_PIPE) != 0) {
263             aclose(outpipe[1]);         /* close output side of pipe */
264             *stdoutfd = outpipe[0];
265         }
266         if ((pipedef & STDERR_PIPE) != 0) {
267             aclose(errpipe[1]);         /* close output side of pipe */
268             *stderrfd = errpipe[0];
269         }
270         if ((pipedef & PASSWD_PIPE) != 0) {
271             aclose(passwdpipe[0]);      /* close input side of pipe */
272             *passwdfd = passwdpipe[1];
273         }
274         break;
275     case 0:             /* child process */
276         if ((pipedef & STDIN_PIPE) != 0) {
277             aclose(inpipe[1]);          /* close output side of pipe */
278         } else {
279             inpipe[0] = *stdinfd;
280         }
281         if ((pipedef & STDOUT_PIPE) != 0) {
282             aclose(outpipe[0]);         /* close input side of pipe */
283         } else {
284             outpipe[1] = *stdoutfd;
285         }
286         if ((pipedef & STDERR_PIPE) != 0) {
287             aclose(errpipe[0]);         /* close input side of pipe */
288         } else {
289             errpipe[1] = *stderrfd;
290         }
291
292         /*
293          * Shift the pipes to the standard file descriptors as requested.
294          */
295         if(dup2(inpipe[0], 0) == -1) {
296             error("error [spawn %s: dup2 in: %s]", prog, strerror(errno));
297         }
298         if(dup2(outpipe[1], 1) == -1) {
299             error("error [spawn %s: dup2 out: %s]", prog, strerror(errno));
300         }
301         if(dup2(errpipe[1], 2) == -1) {
302             error("error [spawn %s: dup2 err: %s]", prog, strerror(errno));
303         }
304
305         /*
306          * Get the "safe" environment.  If we are sending a password to
307          * the child via a pipe, add the environment variable for that.
308          */
309         env = safe_env();
310         if ((pipedef & PASSWD_PIPE) != 0) {
311             for(i = 0; env[i] != NULL; i++) {}
312             newenv = (char **)alloc((i + 1 + 1) * sizeof(*newenv));
313             ap_snprintf(number, sizeof(number), "%d", passwdpipe[0]);
314             newenv[0] = vstralloc(passwdvar, "=", number, NULL);
315             for(i = 0; (newenv[i + 1] = env[i]) != NULL; i++) {}
316             env = newenv;
317         }
318
319         execve(prog, my_argv, env);
320         e = strerror(errno);
321         error("error [exec %s: %s]", prog, e);
322         /* NOTREACHED */
323     }
324     return pid;
325 }