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