]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bpipe.c
- Remove xpg4 lib from FreeBSD build as it is no longer needed and
[bacula/bacula] / bacula / src / lib / bpipe.c
1 /*
2  *   bpipe.c bi-directional pipe
3  *
4  *    Kern Sibbald, November MMII
5  *
6  *   Version $Id$
7  */
8 /*
9    Copyright (C) 2002-2006 Kern Sibbald
10
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.
15
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.
20
21  */
22
23
24 #include "bacula.h"
25 #include "jcr.h"
26
27 int execvp_errors[] = {
28         EACCES,
29         ENOEXEC,
30         EFAULT,
31         EINTR,
32         E2BIG,
33         ENAMETOOLONG,
34         ENOMEM,
35 #ifndef WIN32
36         ETXTBSY,
37 #endif
38         ENOENT
39 };
40 int num_execvp_errors = (int)(sizeof(execvp_errors)/sizeof(int));
41
42
43 #define MAX_ARGV 100
44 static void build_argc_argv(char *cmd, int *bargc, char *bargv[], int max_arg);
45
46 /*
47  * Run an external program. Optionally wait a specified number
48  *   of seconds. Program killed if wait exceeded. We open
49  *   a bi-directional pipe so that the user can read from and
50  *   write to the program.
51  */
52 BPIPE *open_bpipe(char *prog, int wait, const char *mode)
53 {
54    char *bargv[MAX_ARGV];
55    int bargc, i;
56    int readp[2], writep[2];
57    POOLMEM *tprog;
58    int mode_read, mode_write;
59    BPIPE *bpipe;
60    int save_errno;
61
62    bpipe = (BPIPE *)malloc(sizeof(BPIPE));
63    memset(bpipe, 0, sizeof(BPIPE));
64    mode_read = (mode[0] == 'r');
65    mode_write = (mode[0] == 'w' || mode[1] == 'w');
66    /* Build arguments for running program. */
67    tprog = get_pool_memory(PM_FNAME);
68    pm_strcpy(tprog, prog);
69    build_argc_argv(tprog, &bargc, bargv, MAX_ARGV);
70 #ifdef  xxxxxx
71    printf("argc=%d\n", bargc);
72    for (i=0; i<bargc; i++) {
73       printf("argc=%d argv=%s:\n", i, bargv[i]);
74    }
75 #endif
76
77    /* Each pipe is one way, write one end, read the other, so we need two */
78    if (mode_write && pipe(writep) == -1) {
79       save_errno = errno;
80       free(bpipe);
81       errno = save_errno;
82       free_pool_memory(tprog);
83       return NULL;
84    }
85    if (mode_read && pipe(readp) == -1) {
86       save_errno = errno;
87       if (mode_write) {
88          close(writep[0]);
89          close(writep[1]);
90       }
91       free(bpipe);
92       errno = save_errno;
93       free_pool_memory(tprog);
94       return NULL;
95    }
96    /* Start worker process */
97    switch (bpipe->worker_pid = fork()) {
98    case -1:                           /* error */
99       save_errno = errno;
100       if (mode_write) {
101          close(writep[0]);
102          close(writep[1]);
103       }
104       if (mode_read) {
105          close(readp[0]);
106          close(readp[1]);
107       }
108       free(bpipe);
109       errno = save_errno;
110       free_pool_memory(tprog);
111       return NULL;
112
113    case 0:                            /* child */
114       if (mode_write) {
115          close(writep[1]);
116          dup2(writep[0], 0);          /* Dup our write to his stdin */
117       }
118       if (mode_read) {
119          close(readp[0]);             /* Close unused child fds */
120          dup2(readp[1], 1);           /* dup our read to his stdout */
121          dup2(readp[1], 2);           /*   and his stderr */
122       }
123       closelog();                     /* close syslog if open */
124       for (i=3; i<=32; i++) {         /* close any open file descriptors */
125          close(i);
126       }
127       execvp(bargv[0], bargv);        /* call the program */
128       /* Convert errno into an exit code for later analysis */
129       for (i=0; i< num_execvp_errors; i++) {
130          if (execvp_errors[i] == errno) {
131             exit(200 + i);            /* exit code => errno */
132          }
133       }
134       exit(255);                      /* unknown errno */
135
136    default:                           /* parent */
137       break;
138    }
139    free_pool_memory(tprog);
140    if (mode_read) {
141       close(readp[1]);                /* close unused parent fds */
142       bpipe->rfd = fdopen(readp[0], "r"); /* open file descriptor */
143    }
144    if (mode_write) {
145       close(writep[0]);
146       bpipe->wfd = fdopen(writep[1], "w");
147    }
148    bpipe->worker_stime = time(NULL);
149    bpipe->wait = wait;
150    if (wait > 0) {
151       bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
152    }
153    return bpipe;
154 }
155
156 /* Close the write pipe only */
157 int close_wpipe(BPIPE *bpipe)
158 {
159    int stat = 1;
160
161    if (bpipe->wfd) {
162       fflush(bpipe->wfd);
163       if (fclose(bpipe->wfd) != 0) {
164          stat = 0;
165       }
166       bpipe->wfd = NULL;
167    }
168    return stat;
169 }
170
171 /*
172  * Close both pipes and free resources
173  *
174  *  Returns: 0 on success
175  *           berrno on failure
176  */
177 int close_bpipe(BPIPE *bpipe)
178 {
179    int chldstatus = 0;
180    int stat = 0;
181    int wait_option;
182    int remaining_wait;
183    pid_t wpid = 0;
184
185
186    /* Close pipes */
187    if (bpipe->rfd) {
188       fclose(bpipe->rfd);
189       bpipe->rfd = NULL;
190    }
191    if (bpipe->wfd) {
192       fclose(bpipe->wfd);
193       bpipe->wfd = NULL;
194    }
195
196    if (bpipe->wait == 0) {
197       wait_option = 0;                /* wait indefinitely */
198    } else {
199       wait_option = WNOHANG;          /* don't hang */
200    }
201    remaining_wait = bpipe->wait;
202
203    /* wait for worker child to exit */
204    for ( ;; ) {
205       Dmsg2(800, "Wait for %d opt=%d\n", bpipe->worker_pid, wait_option);
206       do {
207          wpid = waitpid(bpipe->worker_pid, &chldstatus, wait_option);
208       } while (wpid == -1 && (errno == EINTR || errno == EAGAIN));
209       if (wpid == bpipe->worker_pid || wpid == -1) {
210          stat = errno;
211          Dmsg3(800, "Got break wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
212             wpid==-1?strerror(errno):"none");
213          break;
214       }
215       Dmsg3(800, "Got wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
216             wpid==-1?strerror(errno):"none");
217       if (remaining_wait > 0) {
218          bmicrosleep(1, 0);           /* wait one second */
219          remaining_wait--;
220       } else {
221          stat = ETIME;                /* set error status */
222          wpid = -1;
223          break;                       /* don't wait any longer */
224       }
225    }
226    if (wpid > 0) {
227       if (WIFEXITED(chldstatus)) {    /* process exit()ed */
228          stat = WEXITSTATUS(chldstatus);
229          if (stat != 0) {
230             Dmsg1(800, "Non-zero status %d returned from child.\n", stat);
231             stat |= b_errno_exit;        /* exit status returned */
232          }
233          Dmsg1(800, "child status=%d\n", stat & ~b_errno_exit);
234       } else if (WIFSIGNALED(chldstatus)) {  /* process died */
235 #ifndef WIN32
236          stat = WTERMSIG(chldstatus);
237 #else
238 #warning "WTERMSIG undefined in Win32 !!!"
239 #endif
240          Dmsg1(800, "Child died from signal %d\n", stat);
241          stat |= b_errno_signal;      /* exit signal returned */
242       }
243    }
244    if (bpipe->timer_id) {
245       stop_child_timer(bpipe->timer_id);
246    }
247    free(bpipe);
248    Dmsg1(800, "returning stat = %d\n", stat);
249    return stat;
250 }
251
252
253 /*
254  * Run an external program. Optionally wait a specified number
255  *   of seconds. Program killed if wait exceeded. Optionally
256  *   return the output from the program (normally a single line).
257  *
258  *   If the watchdog kills the program, fgets returns, and ferror is set
259  *   to 1 (=>SUCCESS), so we check if the watchdog killed the program.
260  *
261  * Contrary to my normal calling conventions, this program
262  *
263  *  Returns: 0 on success
264  *           non-zero on error == berrno status
265  */
266 int run_program(char *prog, int wait, POOLMEM *results)
267 {
268    BPIPE *bpipe;
269    int stat1, stat2;
270    char *mode;
271
272    mode = (char *)(results != NULL ? "r" : "");
273    bpipe = open_bpipe(prog, wait, mode);
274    if (!bpipe) {
275       return ENOENT;
276    }
277    if (results) {
278       results[0] = 0;
279       int len = sizeof_pool_memory(results) - 1;
280       fgets(results, len, bpipe->rfd);
281       results[len] = 0;
282       if (feof(bpipe->rfd)) {
283          stat1 = 0;
284       } else {
285          stat1 = ferror(bpipe->rfd);
286       }
287       if (stat1 < 0) {
288          Dmsg2(150, "Run program fgets stat=%d ERR=%s\n", stat1, strerror(errno));
289       } else if (stat1 != 0) {
290          Dmsg1(150, "Run program fgets stat=%d\n", stat1);
291          if (bpipe->timer_id) {
292             Dmsg1(150, "Run program fgets killed=%d\n", bpipe->timer_id->killed);
293             /* NB: I'm not sure it is really useful for run_program. Without the
294              * following lines run_program would not detect if the program was killed
295              * by the watchdog. */
296             if (bpipe->timer_id->killed) {
297                stat1 = ETIME;
298                pm_strcat(results, _("Program killed by Bacula watchdog (timeout)\n"));
299             }
300          }
301       }
302    } else {
303       stat1 = 0;
304    }
305    stat2 = close_bpipe(bpipe);
306    stat1 = stat2 != 0 ? stat2 : stat1;
307    Dmsg1(150, "Run program returning %d\n", stat1);
308    return stat1;
309 }
310
311 /*
312  * Run an external program. Optionally wait a specified number
313  *   of seconds. Program killed if wait exceeded (it is done by the 
314  *   watchdog, as fgets is a blocking function).
315  *
316  *   If the watchdog kills the program, fgets returns, and ferror is set
317  *   to 1 (=>SUCCESS), so we check if the watchdog killed the program.
318  *
319  *   Return the full output from the program (not only the first line).
320  *
321  * Contrary to my normal calling conventions, this program
322  *
323  *  Returns: 0 on success
324  *           non-zero on error == berrno status
325  *
326  */
327 int run_program_full_output(char *prog, int wait, POOLMEM *results)
328 {
329    BPIPE *bpipe;
330    int stat1, stat2;
331    char *mode;
332    POOLMEM* tmp;
333    char *buf;
334    const int bufsize = 32000;
335
336    if (results == NULL) {
337       return run_program(prog, wait, NULL);
338    }
339    
340    sm_check(__FILE__, __LINE__, false);
341
342    tmp = get_pool_memory(PM_MESSAGE);
343    buf = (char *)malloc(bufsize+1);
344    
345    mode = (char *)"r";
346    bpipe = open_bpipe(prog, wait, mode);
347    if (!bpipe) {
348       if (results) {
349          results[0] = 0;
350       }
351       return ENOENT;
352    }
353    
354    sm_check(__FILE__, __LINE__, false);
355    tmp[0] = 0;
356    while (1) {
357       buf[0] = 0;
358       fgets(buf, bufsize, bpipe->rfd);
359       buf[bufsize] = 0;
360       pm_strcat(tmp, buf);
361       if (feof(bpipe->rfd)) {
362          stat1 = 0;
363          Dmsg1(900, "Run program fgets stat=%d\n", stat1);
364          break;
365       } else {
366          stat1 = ferror(bpipe->rfd);
367       }
368       if (stat1 < 0) {
369          berrno be;
370          Dmsg2(200, "Run program fgets stat=%d ERR=%s\n", stat1, be.strerror());
371          break;
372       } else if (stat1 != 0) {
373          Dmsg1(900, "Run program fgets stat=%d\n", stat1);
374          if (bpipe->timer_id) {
375             Dmsg1(150, "Run program fgets killed=%d\n", bpipe->timer_id->killed);
376             if (bpipe->timer_id->killed) {
377                pm_strcat(tmp, _("Program killed by Bacula watchdog (timeout)\n"));
378                stat1 = ETIME;
379                break;
380             }
381          }
382       }
383    }
384    int len = sizeof_pool_memory(results) - 1;
385    bstrncpy(results, tmp, len);
386    Dmsg3(1900, "resadr=0x%x reslen=%d res=%s\n", results, strlen(results), results);
387    stat2 = close_bpipe(bpipe);
388    stat1 = stat2 != 0 ? stat2 : stat1;
389    
390    Dmsg1(900, "Run program returning %d\n", stat1);
391    free_pool_memory(tmp);
392    free(buf);
393    return stat1;
394 }
395
396 /*
397  * Build argc and argv from a string
398  */
399 static void build_argc_argv(char *cmd, int *bargc, char *bargv[], int max_argv)
400 {
401    int i;
402    char *p, *q, quote;
403    int argc = 0;
404
405    argc = 0;
406    for (i=0; i<max_argv; i++)
407       bargv[i] = NULL;
408
409    p = cmd;
410    quote = 0;
411    while  (*p && (*p == ' ' || *p == '\t'))
412       p++;
413    if (*p == '\"' || *p == '\'') {
414       quote = *p;
415       p++;
416    }
417    if (*p) {
418       while (*p && argc < MAX_ARGV) {
419          q = p;
420          if (quote) {
421             while (*q && *q != quote)
422             q++;
423             quote = 0;
424          } else {
425             while (*q && *q != ' ')
426             q++;
427          }
428          if (*q)
429             *(q++) = '\0';
430          bargv[argc++] = p;
431          p = q;
432          while (*p && (*p == ' ' || *p == '\t'))
433             p++;
434          if (*p == '\"' || *p == '\'') {
435             quote = *p;
436             p++;
437          }
438       }
439    }
440    *bargc = argc;
441 }