2 * bpipe.c bi-directional pipe
4 * Kern Sibbald, November MMII
9 Copyright (C) 2002-2005 Kern Sibbald
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 version 2 as amended with additional clauses defined in the
14 file LICENSE in the main source directory.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 the file LICENSE for additional details.
27 int execvp_errors[] = {EACCES, ENOEXEC, EFAULT, EINTR, E2BIG,
28 ENAMETOOLONG, ENOMEM, ETXTBSY, ENOENT};
29 int num_execvp_errors = (int)(sizeof(execvp_errors)/sizeof(int));
33 static void build_argc_argv(char *cmd, int *bargc, char *bargv[], int max_arg);
36 * Run an external program. Optionally wait a specified number
37 * of seconds. Program killed if wait exceeded. We open
38 * a bi-directional pipe so that the user can read from and
39 * write to the program.
41 BPIPE *open_bpipe(char *prog, int wait, const char *mode)
43 char *bargv[MAX_ARGV];
45 int readp[2], writep[2];
47 int mode_read, mode_write;
51 bpipe = (BPIPE *)malloc(sizeof(BPIPE));
52 memset(bpipe, 0, sizeof(BPIPE));
53 mode_read = (mode[0] == 'r');
54 mode_write = (mode[0] == 'w' || mode[1] == 'w');
55 /* Build arguments for running program. */
56 tprog = get_pool_memory(PM_FNAME);
57 pm_strcpy(tprog, prog);
58 build_argc_argv(tprog, &bargc, bargv, MAX_ARGV);
60 printf("argc=%d\n", bargc);
61 for (i=0; i<bargc; i++) {
62 printf("argc=%d argv=%s:\n", i, bargv[i]);
65 free_pool_memory(tprog);
67 /* Each pipe is one way, write one end, read the other, so we need two */
68 if (mode_write && pipe(writep) == -1) {
74 if (mode_read && pipe(readp) == -1) {
84 /* Start worker process */
85 switch (bpipe->worker_pid = fork()) {
103 dup2(writep[0], 0); /* Dup our write to his stdin */
106 close(readp[0]); /* Close unused child fds */
107 dup2(readp[1], 1); /* dup our read to his stdout */
108 dup2(readp[1], 2); /* and his stderr */
110 closelog(); /* close syslog if open */
111 for (i=3; i<=32; i++) { /* close any open file descriptors */
114 execvp(bargv[0], bargv); /* call the program */
115 /* Convert errno into an exit code for later analysis */
116 for (i=0; i< num_execvp_errors; i++) {
117 if (execvp_errors[i] == errno) {
118 exit(200 + i); /* exit code => errno */
121 exit(255); /* unknown errno */
125 default: /* parent */
129 close(readp[1]); /* close unused parent fds */
130 bpipe->rfd = fdopen(readp[0], "r"); /* open file descriptor */
134 bpipe->wfd = fdopen(writep[1], "w");
136 bpipe->worker_stime = time(NULL);
139 bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
144 /* Close the write pipe only */
145 int close_wpipe(BPIPE *bpipe)
151 if (fclose(bpipe->wfd) != 0) {
160 * Close both pipes and free resources
162 * Returns: 0 on success
165 int close_bpipe(BPIPE *bpipe)
184 if (bpipe->wait == 0) {
185 wait_option = 0; /* wait indefinitely */
187 wait_option = WNOHANG; /* don't hang */
189 remaining_wait = bpipe->wait;
191 /* wait for worker child to exit */
193 Dmsg2(800, "Wait for %d opt=%d\n", bpipe->worker_pid, wait_option);
195 wpid = waitpid(bpipe->worker_pid, &chldstatus, wait_option);
196 } while (wpid == -1 && (errno == EINTR || errno == EAGAIN));
197 if (wpid == bpipe->worker_pid || wpid == -1) {
199 Dmsg3(800, "Got break wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
200 wpid==-1?strerror(errno):"none");
203 Dmsg3(800, "Got wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
204 wpid==-1?strerror(errno):"none");
205 if (remaining_wait > 0) {
206 bmicrosleep(1, 0); /* wait one second */
209 stat = ETIME; /* set error status */
211 break; /* don't wait any longer */
215 if (WIFEXITED(chldstatus)) { /* process exit()ed */
216 stat = WEXITSTATUS(chldstatus);
218 Dmsg1(800, "Non-zero status %d returned from child.\n", stat);
219 stat |= b_errno_exit; /* exit status returned */
221 Dmsg1(800, "child status=%d\n", stat & ~b_errno_exit);
222 } else if (WIFSIGNALED(chldstatus)) { /* process died */
223 stat = WTERMSIG(chldstatus);
224 Dmsg1(800, "Child died from signale %d\n", stat);
225 stat |= b_errno_signal; /* exit signal returned */
228 if (bpipe->timer_id) {
229 stop_child_timer(bpipe->timer_id);
232 Dmsg1(800, "returning stat = %d\n", stat);
238 * Run an external program. Optionally wait a specified number
239 * of seconds. Program killed if wait exceeded. Optionally
240 * return the output from the program (normally a single line).
242 * Contrary to my normal calling conventions, this program
244 * Returns: 0 on success
245 * non-zero on error == berrno status
247 int run_program(char *prog, int wait, POOLMEM *results)
253 mode = (char *)(results != NULL ? "r" : "");
254 bpipe = open_bpipe(prog, wait, mode);
260 int len = sizeof_pool_memory(results) - 1;
261 fgets(results, len, bpipe->rfd);
263 if (feof(bpipe->rfd)) {
266 stat1 = ferror(bpipe->rfd);
269 Dmsg2(100, "Run program fgets stat=%d ERR=%s\n", stat1, strerror(errno));
270 } else if (stat1 != 0) {
271 Dmsg1(100, "Run program fgets stat=%d\n", stat1);
276 stat2 = close_bpipe(bpipe);
277 stat1 = stat2 != 0 ? stat2 : stat1;
278 Dmsg1(100, "Run program returning %d\n", stat1);
283 * Run an external program. Optionally wait a specified number
284 * of seconds. Program killed if wait exceeded (it is done by the
285 * watchdog, as fgets is a blocking function).
286 * Return the full output from the program (not only the first line).
288 * Contrary to my normal calling conventions, this program
290 * Returns: 0 on success
291 * non-zero on error == berrno status
294 int run_program_full_output(char *prog, int wait, POOLMEM *results)
301 if (results == NULL) {
302 return run_program(prog, wait, NULL);
305 sm_check(__FILE__, __LINE__, false);
307 tmp = get_pool_memory(PM_MESSAGE);
310 bpipe = open_bpipe(prog, wait, mode);
318 sm_check(__FILE__, __LINE__, false);
322 fgets(buf, sizeof(buf), bpipe->rfd);
324 if (feof(bpipe->rfd)) {
326 Dmsg1(900, "Run program fgets stat=%d\n", stat1);
329 stat1 = ferror(bpipe->rfd);
333 Dmsg2(200, "Run program fgets stat=%d ERR=%s\n", stat1, be.strerror());
335 } else if (stat1 != 0) {
336 Dmsg1(900, "Run program fgets stat=%d\n", stat1);
339 int len = sizeof_pool_memory(results) - 1;
340 bstrncpy(results, tmp, len);
341 Dmsg3(1900, "resadr=0x%x reslen=%d res=%s\n", results, strlen(results), results);
342 stat2 = close_bpipe(bpipe);
343 stat1 = stat2 != 0 ? stat2 : stat1;
345 Dmsg1(900, "Run program returning %d\n", stat);
346 free_pool_memory(tmp);
351 * Build argc and argv from a string
353 static void build_argc_argv(char *cmd, int *bargc, char *bargv[], int max_argv)
360 for (i=0; i<max_argv; i++)
365 while (*p && (*p == ' ' || *p == '\t'))
367 if (*p == '\"' || *p == '\'') {
372 while (*p && argc < MAX_ARGV) {
375 while (*q && *q != quote)
379 while (*q && *q != ' ')
386 while (*p && (*p == ' ' || *p == '\t'))
388 if (*p == '\"' || *p == '\'') {