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