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