d960c97803a089b4bbceea7d4cb4f3f3ed5ff7f6
[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 /*
9  * this used to be a function in it's own write but became a wrapper around
10  * pipespawnv to eliminate redundancy...
11  */
12 #ifdef STDC_HEADERS
13 int pipespawn(char *prog, int pipedef, int *stdinfd, int *stdoutfd,
14               int *stderrfd, ...)
15 #else
16 int pipespawn(prog, pipedef, stdinfd, stdoutfd, stderrfd, va_alist)
17 char *prog;
18 int pipedef;
19 int *stdinfd, *stdoutfd, *stderrfd;
20 va_dcl
21 #endif
22 {
23     va_list ap;
24     int argc = 0, pid, i;
25     char **argv;
26
27     /* count args */
28     arglist_start(ap, stderrfd);
29     while(arglist_val(ap, char *) != NULL) {
30         argc++;
31     }
32     arglist_end(ap);
33
34     /*
35      * Create the argument vector.
36      */
37     arglist_start(ap, stderrfd);
38     argv = (char **)alloc((argc + 1) * sizeof(*argv));
39     i = 0;
40     while((argv[i] = arglist_val(ap, char *)) != NULL) {
41         if (argv[i] != skip_argument) {
42             i++;
43         }
44     }
45     arglist_end(ap);
46
47     pid = pipespawnv_passwd(prog, pipedef, stdinfd, stdoutfd, stderrfd, NULL, NULL, argv);
48     amfree(argv);
49     return pid;
50 }
51
52 int pipespawnv(prog, pipedef, stdinfd, stdoutfd, stderrfd, my_argv)
53 char *prog;
54 int pipedef;
55 int *stdinfd, *stdoutfd, *stderrfd;
56 char **my_argv;
57 {
58     return pipespawnv_passwd(prog, pipedef, stdinfd, stdoutfd, stderrfd,
59         NULL, NULL, my_argv);
60 }
61
62 int pipespawnv_passwd(prog, pipedef, stdinfd, stdoutfd, stderrfd, passwdvar, passwdfd, my_argv)
63 char *prog;
64 int pipedef;
65 int *stdinfd, *stdoutfd, *stderrfd;
66 char *passwdvar;
67 int *passwdfd;
68 char **my_argv;
69 {
70     int argc;
71     int pid, i, inpipe[2], outpipe[2], errpipe[2], passwdpipe[2];
72     char number[NUM_STR_SIZE];
73     char **arg;
74     char *e;
75     int ch;
76     char **env;
77     char **newenv;
78
79     /*
80      * Log the command line and count the args.
81      */
82     dbprintf(("%s: spawning %s in pipeline\n", debug_prefix_time(NULL), prog));
83     dbprintf(("%s: argument list:", debug_prefix(NULL)));
84     if ((pipedef & PASSWD_PIPE) != 0) {
85         passwdvar = *my_argv++;
86         passwdfd = (int *)*my_argv++;
87     }
88     argc = 0;
89     for(arg = my_argv; *arg != NULL; arg++) {
90         if (*arg == skip_argument) {
91             continue;
92         }
93         argc++;
94         dbprintf((" "));
95         for(i = 0; (ch = (*arg)[i]) != '\0' && isprint(ch) && ch != ' '; i++) {}
96         if(ch != '\0' || i == 0) {
97             dbprintf(("\""));
98         }
99         dbprintf(("%s", *arg));
100         if(ch != '\0' || i == 0) {
101             dbprintf(("\""));
102         }
103     }
104     dbprintf(("\n"));
105
106     /*
107      * Create the pipes
108      */
109     if ((pipedef & STDIN_PIPE) != 0) {
110         if(pipe(inpipe) == -1) {
111             error("error [open pipe to %s: %s]", prog, strerror(errno));
112         }
113     }
114     if ((pipedef & STDOUT_PIPE) != 0) {
115         if(pipe(outpipe) == -1) {
116             error("error [open pipe to %s: %s]", prog, strerror(errno));
117         }
118     }
119     if ((pipedef & STDERR_PIPE) != 0) {
120         if(pipe(errpipe) == -1) {
121             error("error [open pipe to %s: %s]", prog, strerror(errno));
122         }
123     }
124     if ((pipedef & PASSWD_PIPE) != 0) {
125         if(pipe(passwdpipe) == -1) {
126             error("error [open pipe to %s: %s]", prog, strerror(errno));
127         }
128     }
129
130     /*
131      * Fork and set up the return or run the program.
132      */
133     switch(pid = fork()) {
134     case -1:
135         e = strerror(errno);
136         error("error [fork %s: %s]", prog, e);
137     default:    /* parent process */
138         if ((pipedef & STDIN_PIPE) != 0) {
139             aclose(inpipe[0]);          /* close input side of pipe */
140             *stdinfd = inpipe[1];
141         }
142         if ((pipedef & STDOUT_PIPE) != 0) {
143             aclose(outpipe[1]);         /* close output side of pipe */
144             *stdoutfd = outpipe[0];
145         }
146         if ((pipedef & STDERR_PIPE) != 0) {
147             aclose(errpipe[1]);         /* close output side of pipe */
148             *stderrfd = errpipe[0];
149         }
150         if ((pipedef & PASSWD_PIPE) != 0) {
151             aclose(passwdpipe[0]);      /* close input side of pipe */
152             *passwdfd = passwdpipe[1];
153         }
154         break;
155     case 0:             /* child process */
156         if ((pipedef & STDIN_PIPE) != 0) {
157             aclose(inpipe[1]);          /* close output side of pipe */
158         } else {
159             inpipe[0] = *stdinfd;
160         }
161         if ((pipedef & STDOUT_PIPE) != 0) {
162             aclose(outpipe[0]);         /* close input side of pipe */
163         } else {
164             outpipe[1] = *stdoutfd;
165         }
166         if ((pipedef & STDERR_PIPE) != 0) {
167             aclose(errpipe[0]);         /* close input side of pipe */
168         } else {
169             errpipe[1] = *stderrfd;
170         }
171         if ((pipedef & PASSWD_PIPE) != 0) { 
172             aclose(passwdpipe[1]);      /* close output side of pipe */
173         }
174
175         /*
176          * Shift the pipes to the standard file descriptors as requested.
177          */
178         if(dup2(inpipe[0], 0) == -1) {
179             error("error [spawn %s: dup2 in: %s]", prog, strerror(errno));
180         }
181         if(dup2(outpipe[1], 1) == -1) {
182             error("error [spawn %s: dup2 out: %s]", prog, strerror(errno));
183         }
184         if(dup2(errpipe[1], 2) == -1) {
185             error("error [spawn %s: dup2 err: %s]", prog, strerror(errno));
186         }
187
188         /*
189          * Get the "safe" environment.  If we are sending a password to
190          * the child via a pipe, add the environment variable for that.
191          */
192         env = safe_env();
193         if ((pipedef & PASSWD_PIPE) != 0) {
194             for(i = 0; env[i] != NULL; i++) {}
195             newenv = (char **)alloc((i + 1 + 1) * sizeof(*newenv));
196             snprintf(number, sizeof(number), "%d", passwdpipe[0]);
197             newenv[0] = vstralloc(passwdvar, "=", number, NULL);
198             for(i = 0; (newenv[i + 1] = env[i]) != NULL; i++) {}
199             amfree(env);
200             env = newenv;
201         }
202
203         execve(prog, my_argv, env);
204         e = strerror(errno);
205         error("error [exec %s: %s]", prog, e);
206         /* NOTREACHED */
207     }
208     return pid;
209 }