2 * bpipe.c bi-directional pipe
4 * Kern Sibbald, November MMII
9 Copyright (C) 2002-2006 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[] = {
40 int num_execvp_errors = (int)(sizeof(execvp_errors)/sizeof(int));
45 #if !defined(HAVE_WIN32)
46 static void build_argc_argv(char *cmd, int *bargc, char *bargv[], int max_arg);
49 * Run an external program. Optionally wait a specified number
50 * of seconds. Program killed if wait exceeded. We open
51 * a bi-directional pipe so that the user can read from and
52 * write to the program.
54 BPIPE *open_bpipe(char *prog, int wait, const char *mode)
56 char *bargv[MAX_ARGV];
58 int readp[2], writep[2];
60 int mode_read, mode_write;
64 bpipe = (BPIPE *)malloc(sizeof(BPIPE));
65 memset(bpipe, 0, sizeof(BPIPE));
66 mode_read = (mode[0] == 'r');
67 mode_write = (mode[0] == 'w' || mode[1] == 'w');
68 /* Build arguments for running program. */
69 tprog = get_pool_memory(PM_FNAME);
70 pm_strcpy(tprog, prog);
71 build_argc_argv(tprog, &bargc, bargv, MAX_ARGV);
73 printf("argc=%d\n", bargc);
74 for (i=0; i<bargc; i++) {
75 printf("argc=%d argv=%s:\n", i, bargv[i]);
79 /* Each pipe is one way, write one end, read the other, so we need two */
80 if (mode_write && pipe(writep) == -1) {
83 free_pool_memory(tprog);
87 if (mode_read && pipe(readp) == -1) {
94 free_pool_memory(tprog);
98 /* Start worker process */
99 switch (bpipe->worker_pid = fork()) {
111 free_pool_memory(tprog);
118 dup2(writep[0], 0); /* Dup our write to his stdin */
121 close(readp[0]); /* Close unused child fds */
122 dup2(readp[1], 1); /* dup our read to his stdout */
123 dup2(readp[1], 2); /* and his stderr */
125 closelog(); /* close syslog if open */
126 for (i=3; i<=32; i++) { /* close any open file descriptors */
129 execvp(bargv[0], bargv); /* call the program */
130 /* Convert errno into an exit code for later analysis */
131 for (i=0; i< num_execvp_errors; i++) {
132 if (execvp_errors[i] == errno) {
133 exit(200 + i); /* exit code => errno */
136 exit(255); /* unknown errno */
138 default: /* parent */
141 free_pool_memory(tprog);
143 close(readp[1]); /* close unused parent fds */
144 bpipe->rfd = fdopen(readp[0], "r"); /* open file descriptor */
148 bpipe->wfd = fdopen(writep[1], "w");
150 bpipe->worker_stime = time(NULL);
153 bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
158 /* Close the write pipe only */
159 int close_wpipe(BPIPE *bpipe)
165 if (fclose(bpipe->wfd) != 0) {
174 * Close both pipes and free resources
176 * Returns: 0 on success
179 int close_bpipe(BPIPE *bpipe)
198 if (bpipe->wait == 0) {
199 wait_option = 0; /* wait indefinitely */
201 wait_option = WNOHANG; /* don't hang */
203 remaining_wait = bpipe->wait;
205 /* wait for worker child to exit */
207 Dmsg2(800, "Wait for %d opt=%d\n", bpipe->worker_pid, wait_option);
209 wpid = waitpid(bpipe->worker_pid, &chldstatus, wait_option);
210 } while (wpid == -1 && (errno == EINTR || errno == EAGAIN));
211 if (wpid == bpipe->worker_pid || wpid == -1) {
213 Dmsg3(800, "Got break wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
214 wpid==-1?strerror(errno):"none");
217 Dmsg3(800, "Got wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
218 wpid==-1?strerror(errno):"none");
219 if (remaining_wait > 0) {
220 bmicrosleep(1, 0); /* wait one second */
223 stat = ETIME; /* set error status */
225 break; /* don't wait any longer */
229 if (WIFEXITED(chldstatus)) { /* process exit()ed */
230 stat = WEXITSTATUS(chldstatus);
232 Dmsg1(800, "Non-zero status %d returned from child.\n", stat);
233 stat |= b_errno_exit; /* exit status returned */
235 Dmsg1(800, "child status=%d\n", stat & ~b_errno_exit);
236 } else if (WIFSIGNALED(chldstatus)) { /* process died */
238 stat = WTERMSIG(chldstatus);
240 stat = 1; /* fake child status */
242 Dmsg1(800, "Child died from signal %d\n", stat);
243 stat |= b_errno_signal; /* exit signal returned */
246 if (bpipe->timer_id) {
247 stop_child_timer(bpipe->timer_id);
250 Dmsg2(800, "returning stat=%d,%d\n", stat & ~(b_errno_exit|b_errno_signal), stat);
255 * Build argc and argv from a string
257 static void build_argc_argv(char *cmd, int *bargc, char *bargv[], int max_argv)
264 for (i=0; i<max_argv; i++)
269 while (*p && (*p == ' ' || *p == '\t'))
271 if (*p == '\"' || *p == '\'') {
276 while (*p && argc < MAX_ARGV) {
279 while (*q && *q != quote)
283 while (*q && *q != ' ')
290 while (*p && (*p == ' ' || *p == '\t'))
292 if (*p == '\"' || *p == '\'') {
300 #endif /* HAVE_WIN32 */
303 * Run an external program. Optionally wait a specified number
304 * of seconds. Program killed if wait exceeded. Optionally
305 * return the output from the program (normally a single line).
307 * If the watchdog kills the program, fgets returns, and ferror is set
308 * to 1 (=>SUCCESS), so we check if the watchdog killed the program.
310 * Contrary to my normal calling conventions, this program
312 * Returns: 0 on success
313 * non-zero on error == berrno status
315 int run_program(char *prog, int wait, POOLMEM *results)
321 mode = (char *)(results != NULL ? "r" : "");
322 bpipe = open_bpipe(prog, wait, mode);
328 int len = sizeof_pool_memory(results) - 1;
329 fgets(results, len, bpipe->rfd);
331 if (feof(bpipe->rfd)) {
334 stat1 = ferror(bpipe->rfd);
337 Dmsg2(150, "Run program fgets stat=%d ERR=%s\n", stat1, strerror(errno));
338 } else if (stat1 != 0) {
339 Dmsg1(150, "Run program fgets stat=%d\n", stat1);
340 if (bpipe->timer_id) {
341 Dmsg1(150, "Run program fgets killed=%d\n", bpipe->timer_id->killed);
342 /* NB: I'm not sure it is really useful for run_program. Without the
343 * following lines run_program would not detect if the program was killed
344 * by the watchdog. */
345 if (bpipe->timer_id->killed) {
347 pm_strcat(results, _("Program killed by Bacula watchdog (timeout)\n"));
354 stat2 = close_bpipe(bpipe);
355 stat1 = stat2 != 0 ? stat2 : stat1;
356 Dmsg1(150, "Run program returning %d\n", stat1);
361 * Run an external program. Optionally wait a specified number
362 * of seconds. Program killed if wait exceeded (it is done by the
363 * watchdog, as fgets is a blocking function).
365 * If the watchdog kills the program, fgets returns, and ferror is set
366 * to 1 (=>SUCCESS), so we check if the watchdog killed the program.
368 * Return the full output from the program (not only the first line).
370 * Contrary to my normal calling conventions, this program
372 * Returns: 0 on success
373 * non-zero on error == berrno status
376 int run_program_full_output(char *prog, int wait, POOLMEM *results)
383 const int bufsize = 32000;
385 if (results == NULL) {
386 return run_program(prog, wait, NULL);
389 sm_check(__FILE__, __LINE__, false);
391 tmp = get_pool_memory(PM_MESSAGE);
392 buf = (char *)malloc(bufsize+1);
395 bpipe = open_bpipe(prog, wait, mode);
403 sm_check(__FILE__, __LINE__, false);
407 fgets(buf, bufsize, bpipe->rfd);
410 if (feof(bpipe->rfd)) {
412 Dmsg1(900, "Run program fgets stat=%d\n", stat1);
415 stat1 = ferror(bpipe->rfd);
419 Dmsg2(200, "Run program fgets stat=%d ERR=%s\n", stat1, be.strerror());
421 } else if (stat1 != 0) {
422 Dmsg1(900, "Run program fgets stat=%d\n", stat1);
423 if (bpipe->timer_id && bpipe->timer_id->killed) {
424 Dmsg1(250, "Run program saw fgets killed=%d\n", bpipe->timer_id->killed);
430 * We always check whether the timer killed the program. We would see
431 * an eof even when it does so we just have to trust the killed flag
432 * and set the timer values to avoid edge cases where the program ends
433 * just as the timer kills it.
435 if (bpipe->timer_id && bpipe->timer_id->killed) {
436 Dmsg1(150, "Run program fgets killed=%d\n", bpipe->timer_id->killed);
437 pm_strcat(tmp, _("Program killed by Bacula watchdog (timeout)\n"));
440 int len = sizeof_pool_memory(results) - 1;
441 bstrncpy(results, tmp, len);
442 Dmsg3(1900, "resadr=0x%x reslen=%d res=%s\n", results, strlen(results), results);
443 stat2 = close_bpipe(bpipe);
444 stat1 = stat2 != 0 ? stat2 : stat1;
446 Dmsg1(900, "Run program returning %d\n", stat1);
447 free_pool_memory(tmp);