2 * bpipe.c bi-directional pipe
4 * Kern Sibbald, November MMII
10 Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of
15 the License, or (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public
23 License along with this program; if not, write to the Free
24 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
34 static void build_argc_argv(char *cmd, int *bargc, char *bargv[], int max_arg);
39 * Run an external program. Optionally wait a specified number
40 * of seconds. Program killed if wait exceeded. We open
41 * a bi-directional pipe so that the user can read from and
42 * write to the program.
44 BPIPE *open_bpipe(char *prog, int wait, char *mode)
46 char *bargv[MAX_ARGV];
48 int readp[2], writep[2];
50 int mode_read, mode_write;
53 bpipe = (BPIPE *)malloc(sizeof(BPIPE));
54 memset(bpipe, 0, sizeof(BPIPE));
55 mode_read = (mode[0] == 'r');
56 mode_write = (mode[0] == 'w' || mode[1] == 'w');
57 /* Build arguments for running program. */
58 tprog = get_pool_memory(PM_FNAME);
59 pm_strcpy(&tprog, prog);
60 build_argc_argv(mp_chr(tprog), &bargc, bargv, MAX_ARGV);
62 printf("argc=%d\n", bargc);
64 for (i=0; i<bargc; i++) {
65 printf("argc=%d argv=%s:\n", i, bargv[i]);
68 free_pool_memory(tprog);
70 /* Each pipe is one way, write one end, read the other, so we need two */
71 if (mode_write && pipe(writep) == -1) {
75 if (mode_read && pipe(readp) == -1) {
79 /* Start worker process */
80 switch (bpipe->worker_pid = fork()) {
88 dup2(writep[0], 0); /* Dup our write to his stdin */
91 close(readp[0]); /* Close unused child fds */
92 dup2(readp[1], 1); /* dup our read to his stdout */
93 dup2(readp[1], 2); /* and his stderr */
95 for (int i=3; i<=32; i++) { /* close any open file descriptors */
98 execvp(bargv[0], bargv); /* call the program */
99 exit(errno); /* shouldn't get here */
101 default: /* parent */
105 close(readp[1]); /* close unused parent fds */
106 bpipe->rfd = fdopen(readp[0], "r"); /* open file descriptor */
110 bpipe->wfd = fdopen(writep[1], "w");
112 bpipe->worker_stime = time(NULL);
115 bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
120 /* Close the write pipe only */
121 int close_wpipe(BPIPE *bpipe)
127 if (fclose(bpipe->wfd) != 0) {
135 /* Close both pipes and free resources */
136 int close_bpipe(BPIPE *bpipe)
155 if (bpipe->wait == 0) {
156 wait_option = 0; /* wait indefinitely */
158 wait_option = WNOHANG; /* don't hang */
160 remaining_wait = bpipe->wait;
162 /* wait for worker child to exit */
164 Dmsg2(200, "Wait for %d opt=%d\n", bpipe->worker_pid, wait_option);
166 wpid = waitpid(bpipe->worker_pid, &chldstatus, wait_option);
167 } while (wpid == -1 && (errno == EINTR || errno == EAGAIN));
168 if (wpid == bpipe->worker_pid || wpid == -1) {
169 Dmsg3(200, "Got break wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
170 wpid==-1?strerror(errno):"none");
173 Dmsg3(200, "Got wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
174 wpid==-1?strerror(errno):"none");
175 if (remaining_wait > 0) {
176 bmicrosleep(1, 0); /* wait one second */
179 stat = 1; /* set error status */
180 errno = ETIME; /* set timed out */
182 break; /* don't wait any longer */
186 if (WIFEXITED(chldstatus)) { /* process exit()ed */
187 stat = WEXITSTATUS(chldstatus);
188 Dmsg1(200, "status =%d\n", stat);
189 } else if (WIFSIGNALED(chldstatus)) { /* process died */
191 Dmsg0(200, "Signaled\n");
194 errno = ECHILD; /* set child errno */
197 if (bpipe->timer_id) {
198 stop_child_timer(bpipe->timer_id);
201 Dmsg1(200, "returning stat = %d\n", stat);
207 * Run an external program. Optionally wait a specified number
208 * of seconds. Program killed if wait exceeded. Optionally
209 * return the output from the program (normally a single line).
211 * Contrary to my normal calling conventions, this program
213 * Returns: 0 on success
216 int run_program(char *prog, int wait, POOLMEM *results)
222 mode = (char *)(results != NULL ? "r" : "");
223 bpipe = open_bpipe(prog, wait, mode);
228 mp_chr(results)[0] = 0;
229 stat1 = fgets(mp_chr(results), sizeof_pool_memory(results), bpipe->rfd) == NULL;
233 stat2 = close_bpipe(bpipe);
234 return stat2 != 0 ? stat2 : stat1;
239 * Build argc and argv from a string
241 static void build_argc_argv(char *cmd, int *bargc, char *bargv[], int max_argv)
248 for (i=0; i<max_argv; i++)
253 while (*p && (*p == ' ' || *p == '\t'))
255 if (*p == '\"' || *p == '\'') {
260 while (*p && argc < MAX_ARGV) {
263 while (*q && *q != quote)
267 while (*q && *q != ' ')
274 while (*p && (*p == ' ' || *p == '\t'))
276 if (*p == '\"' || *p == '\'') {