]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bpipe.c
kes When doing a label, pass the VolBytes back to the Director,
[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 HAVE_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
45 #if !defined(HAVE_WIN32)
46 static void build_argc_argv(char *cmd, int *bargc, char *bargv[], int max_arg);
47
48 /*
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.
53  */
54 BPIPE *open_bpipe(char *prog, int wait, const char *mode)
55 {
56    char *bargv[MAX_ARGV];
57    int bargc, i;
58    int readp[2], writep[2];
59    POOLMEM *tprog;
60    int mode_read, mode_write;
61    BPIPE *bpipe;
62    int save_errno;
63
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);
72 #ifdef  xxxxxx
73    printf("argc=%d\n", bargc);
74    for (i=0; i<bargc; i++) {
75       printf("argc=%d argv=%s:\n", i, bargv[i]);
76    }
77 #endif
78
79    /* Each pipe is one way, write one end, read the other, so we need two */
80    if (mode_write && pipe(writep) == -1) {
81       save_errno = errno;
82       free(bpipe);
83       free_pool_memory(tprog);
84       errno = save_errno;
85       return NULL;
86    }
87    if (mode_read && pipe(readp) == -1) {
88       save_errno = errno;
89       if (mode_write) {
90          close(writep[0]);
91          close(writep[1]);
92       }
93       free(bpipe);
94       free_pool_memory(tprog);
95       errno = save_errno;
96       return NULL;
97    }
98    /* Start worker process */
99    switch (bpipe->worker_pid = fork()) {
100    case -1:                           /* error */
101       save_errno = errno;
102       if (mode_write) {
103          close(writep[0]);
104          close(writep[1]);
105       }
106       if (mode_read) {
107          close(readp[0]);
108          close(readp[1]);
109       }
110       free(bpipe);
111       free_pool_memory(tprog);
112       errno = save_errno;
113       return NULL;
114
115    case 0:                            /* child */
116       if (mode_write) {
117          close(writep[1]);
118          dup2(writep[0], 0);          /* Dup our write to his stdin */
119       }
120       if (mode_read) {
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 */
124       }
125       closelog();                     /* close syslog if open */
126       for (i=3; i<=32; i++) {         /* close any open file descriptors */
127          close(i);
128       }
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 */
134          }
135       }
136       exit(255);                      /* unknown errno */
137
138    default:                           /* parent */
139       break;
140    }
141    free_pool_memory(tprog);
142    if (mode_read) {
143       close(readp[1]);                /* close unused parent fds */
144       bpipe->rfd = fdopen(readp[0], "r"); /* open file descriptor */
145    }
146    if (mode_write) {
147       close(writep[0]);
148       bpipe->wfd = fdopen(writep[1], "w");
149    }
150    bpipe->worker_stime = time(NULL);
151    bpipe->wait = wait;
152    if (wait > 0) {
153       bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
154    }
155    return bpipe;
156 }
157
158 /* Close the write pipe only */
159 int close_wpipe(BPIPE *bpipe)
160 {
161    int stat = 1;
162
163    if (bpipe->wfd) {
164       fflush(bpipe->wfd);
165       if (fclose(bpipe->wfd) != 0) {
166          stat = 0;
167       }
168       bpipe->wfd = NULL;
169    }
170    return stat;
171 }
172
173 /*
174  * Close both pipes and free resources
175  *
176  *  Returns: 0 on success
177  *           berrno on failure
178  */
179 int close_bpipe(BPIPE *bpipe)
180 {
181    int chldstatus = 0;
182    int stat = 0;
183    int wait_option;
184    int remaining_wait;
185    pid_t wpid = 0;
186
187
188    /* Close pipes */
189    if (bpipe->rfd) {
190       fclose(bpipe->rfd);
191       bpipe->rfd = NULL;
192    }
193    if (bpipe->wfd) {
194       fclose(bpipe->wfd);
195       bpipe->wfd = NULL;
196    }
197
198    if (bpipe->wait == 0) {
199       wait_option = 0;                /* wait indefinitely */
200    } else {
201       wait_option = WNOHANG;          /* don't hang */
202    }
203    remaining_wait = bpipe->wait;
204
205    /* wait for worker child to exit */
206    for ( ;; ) {
207       Dmsg2(800, "Wait for %d opt=%d\n", bpipe->worker_pid, wait_option);
208       do {
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) {
212          stat = errno;
213          Dmsg3(800, "Got break wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
214             wpid==-1?strerror(errno):"none");
215          break;
216       }
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 */
221          remaining_wait--;
222       } else {
223          stat = ETIME;                /* set error status */
224          wpid = -1;
225          break;                       /* don't wait any longer */
226       }
227    }
228    if (wpid > 0) {
229       if (WIFEXITED(chldstatus)) {    /* process exit()ed */
230          stat = WEXITSTATUS(chldstatus);
231          if (stat != 0) {
232             Dmsg1(800, "Non-zero status %d returned from child.\n", stat);
233             stat |= b_errno_exit;        /* exit status returned */
234          }
235          Dmsg1(800, "child status=%d\n", stat & ~b_errno_exit);
236       } else if (WIFSIGNALED(chldstatus)) {  /* process died */
237 #ifndef HAVE_WIN32
238          stat = WTERMSIG(chldstatus);
239 #else
240          stat = 1;                    /* fake child status */
241 #endif
242          Dmsg1(800, "Child died from signal %d\n", stat);
243          stat |= b_errno_signal;      /* exit signal returned */
244       }
245    }
246    if (bpipe->timer_id) {
247       stop_child_timer(bpipe->timer_id);
248    }
249    free(bpipe);
250    Dmsg2(800, "returning stat=%d,%d\n", stat & ~(b_errno_exit|b_errno_signal), stat);
251    return stat;
252 }
253
254 /*
255  * Build argc and argv from a string
256  */
257 static void build_argc_argv(char *cmd, int *bargc, char *bargv[], int max_argv)
258 {
259    int i;
260    char *p, *q, quote;
261    int argc = 0;
262
263    argc = 0;
264    for (i=0; i<max_argv; i++)
265       bargv[i] = NULL;
266
267    p = cmd;
268    quote = 0;
269    while  (*p && (*p == ' ' || *p == '\t'))
270       p++;
271    if (*p == '\"' || *p == '\'') {
272       quote = *p;
273       p++;
274    }
275    if (*p) {
276       while (*p && argc < MAX_ARGV) {
277          q = p;
278          if (quote) {
279             while (*q && *q != quote)
280             q++;
281             quote = 0;
282          } else {
283             while (*q && *q != ' ')
284             q++;
285          }
286          if (*q)
287             *(q++) = '\0';
288          bargv[argc++] = p;
289          p = q;
290          while (*p && (*p == ' ' || *p == '\t'))
291             p++;
292          if (*p == '\"' || *p == '\'') {
293             quote = *p;
294             p++;
295          }
296       }
297    }
298    *bargc = argc;
299 }
300 #endif /* HAVE_WIN32 */
301
302 /*
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).
306  *
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.
309  *
310  * Contrary to my normal calling conventions, this program
311  *
312  *  Returns: 0 on success
313  *           non-zero on error == berrno status
314  */
315 int run_program(char *prog, int wait, POOLMEM *results)
316 {
317    BPIPE *bpipe;
318    int stat1, stat2;
319    char *mode;
320
321    mode = (char *)(results != NULL ? "r" : "");
322    bpipe = open_bpipe(prog, wait, mode);
323    if (!bpipe) {
324       return ENOENT;
325    }
326    if (results) {
327       results[0] = 0;
328       int len = sizeof_pool_memory(results) - 1;
329       fgets(results, len, bpipe->rfd);
330       results[len] = 0;
331       if (feof(bpipe->rfd)) {
332          stat1 = 0;
333       } else {
334          stat1 = ferror(bpipe->rfd);
335       }
336       if (stat1 < 0) {
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) {
346                stat1 = ETIME;
347                pm_strcat(results, _("Program killed by Bacula watchdog (timeout)\n"));
348             }
349          }
350       }
351    } else {
352       stat1 = 0;
353    }
354    stat2 = close_bpipe(bpipe);
355    stat1 = stat2 != 0 ? stat2 : stat1;
356    Dmsg1(150, "Run program returning %d\n", stat1);
357    return stat1;
358 }
359
360 /*
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).
364  *
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.
367  *
368  *   Return the full output from the program (not only the first line).
369  *
370  * Contrary to my normal calling conventions, this program
371  *
372  *  Returns: 0 on success
373  *           non-zero on error == berrno status
374  *
375  */
376 int run_program_full_output(char *prog, int wait, POOLMEM *results)
377 {
378    BPIPE *bpipe;
379    int stat1, stat2;
380    char *mode;
381    POOLMEM* tmp;
382    char *buf;
383    const int bufsize = 32000;
384
385    if (results == NULL) {
386       return run_program(prog, wait, NULL);
387    }
388    
389    sm_check(__FILE__, __LINE__, false);
390
391    tmp = get_pool_memory(PM_MESSAGE);
392    buf = (char *)malloc(bufsize+1);
393    
394    mode = (char *)"r";
395    bpipe = open_bpipe(prog, wait, mode);
396    if (!bpipe) {
397       if (results) {
398          results[0] = 0;
399       }
400       return ENOENT;
401    }
402    
403    sm_check(__FILE__, __LINE__, false);
404    tmp[0] = 0;
405    while (1) {
406       buf[0] = 0;
407       fgets(buf, bufsize, bpipe->rfd);
408       buf[bufsize] = 0;
409       pm_strcat(tmp, buf);
410       if (feof(bpipe->rfd)) {
411          stat1 = 0;
412          Dmsg1(900, "Run program fgets stat=%d\n", stat1);
413          break;
414       } else {
415          stat1 = ferror(bpipe->rfd);
416       }
417       if (stat1 < 0) {
418          berrno be;
419          Dmsg2(200, "Run program fgets stat=%d ERR=%s\n", stat1, be.strerror());
420          break;
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);
425             break;
426          }
427       }
428    }
429    /*
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.
434     */
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"));
438       stat1 = ETIME;
439    }
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;
445    
446    Dmsg1(900, "Run program returning %d\n", stat1);
447    free_pool_memory(tmp);
448    free(buf);
449    return stat1;
450 }