]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/bpipe.c
Use the command line utility dropdb instead of the psql command
[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 /*
10    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License as
14    published by the Free Software Foundation; either version 2 of
15    the License, or (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20    General Public License for more details.
21
22    You should have received a copy of the GNU General Public
23    License along with this program; if not, write to the Free
24    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25    MA 02111-1307, USA.
26
27  */
28
29 #include "bacula.h"
30 #include "jcr.h"
31
32
33 #define MAX_ARGV 100
34 static void build_argc_argv(char *cmd, int *bargc, char *bargv[], int max_arg);
35
36
37
38 /*
39  * Run an external program. Optionally wait a specified number
40  *   of seconds. Program killed if wait exceeded. We open
41  *   a bi-directional pipe so that the user can read from and
42  *   write to the program. 
43  */
44 BPIPE *open_bpipe(char *prog, int wait, char *mode)
45 {
46    char *bargv[MAX_ARGV];
47    int bargc;
48    int readp[2], writep[2];
49    POOLMEM *tprog;
50    int mode_read, mode_write;
51    BPIPE *bpipe;
52
53    bpipe = (BPIPE *)malloc(sizeof(BPIPE));
54    memset(bpipe, 0, sizeof(BPIPE));
55    mode_read = (mode[0] == 'r');
56    mode_write = (mode[0] == 'w' || mode[1] == 'w');
57    /* Build arguments for running program. */
58    tprog = get_pool_memory(PM_FNAME);
59    pm_strcpy(&tprog, prog);
60    build_argc_argv(mp_chr(tprog), &bargc, bargv, MAX_ARGV);
61 #ifdef  xxxxxx
62    printf("argc=%d\n", bargc);
63    int i;
64    for (i=0; i<bargc; i++) {
65       printf("argc=%d argv=%s:\n", i, bargv[i]);
66    }
67 #endif
68    free_pool_memory(tprog);
69
70    /* Each pipe is one way, write one end, read the other, so we need two */
71    if (mode_write && pipe(writep) == -1) {
72       free(bpipe);
73       return NULL;
74    }
75    if (mode_read && pipe(readp) == -1) {
76       free(bpipe);
77       return NULL;
78    }
79    /* Start worker process */
80    switch (bpipe->worker_pid = fork()) {
81    case -1:                           /* error */
82       free(bpipe);
83       return NULL;
84
85    case 0:                            /* child */
86       if (mode_write) {
87          close(writep[1]);
88          dup2(writep[0], 0);          /* Dup our write to his stdin */
89       }
90       if (mode_read) {
91          close(readp[0]);             /* Close unused child fds */
92          dup2(readp[1], 1);           /* dup our read to his stdout */
93          dup2(readp[1], 2);           /*   and his stderr */
94       }
95       for (int i=3; i<=32; i++) {     /* close any open file descriptors */
96          close(i);
97       }
98       execvp(bargv[0], bargv);        /* call the program */
99       exit(errno);                    /* shouldn't get here */
100
101    default:                           /* parent */
102       break;
103    }
104    if (mode_read) {
105       close(readp[1]);                /* close unused parent fds */
106       bpipe->rfd = fdopen(readp[0], "r"); /* open file descriptor */
107    }
108    if (mode_write) {
109       close(writep[0]);
110       bpipe->wfd = fdopen(writep[1], "w");
111    }
112    bpipe->worker_stime = time(NULL);
113    bpipe->wait = wait;
114    if (wait > 0) {
115       bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
116    }
117    return bpipe;
118 }
119
120 /* Close the write pipe only */
121 int close_wpipe(BPIPE *bpipe)
122 {
123    int stat = 1;
124
125    if (bpipe->wfd) {
126       fflush(bpipe->wfd);
127       if (fclose(bpipe->wfd) != 0) {
128          stat = 0;
129       }
130       bpipe->wfd = NULL;
131    }
132    return stat;
133 }
134
135 /* 
136  * Close both pipes and free resources   
137  *
138  *  Returns: 0 on success
139  *           errno on failure
140  */
141 int close_bpipe(BPIPE *bpipe) 
142 {
143    int chldstatus = 0;
144    int stat = 0;    
145    int wait_option;
146    int remaining_wait;
147    pid_t wpid = 0;
148
149
150    /* Close pipes */
151    if (bpipe->rfd) {
152       fclose(bpipe->rfd);
153       bpipe->rfd = NULL;
154    }
155    if (bpipe->wfd) {
156       fclose(bpipe->wfd);
157       bpipe->wfd = NULL;
158    }
159
160    if (bpipe->wait == 0) {
161       wait_option = 0;                /* wait indefinitely */
162    } else {
163       wait_option = WNOHANG;          /* don't hang */
164    }
165    remaining_wait = bpipe->wait;
166
167    /* wait for worker child to exit */
168    for ( ;; ) {
169       Dmsg2(200, "Wait for %d opt=%d\n", bpipe->worker_pid, wait_option);
170       do {
171          wpid = waitpid(bpipe->worker_pid, &chldstatus, wait_option);
172       } while (wpid == -1 && (errno == EINTR || errno == EAGAIN));
173       if (wpid == bpipe->worker_pid || wpid == -1) {
174          Dmsg3(200, "Got break wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
175             wpid==-1?strerror(errno):"none");
176          break;
177       }
178       Dmsg3(200, "Got wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
179             wpid==-1?strerror(errno):"none");
180       if (remaining_wait > 0) {
181          bmicrosleep(1, 0);            /* wait one second */
182          remaining_wait--;
183       } else {
184          stat = ETIME;                /* set error status */
185          wpid = -1;
186          break;                       /* don't wait any longer */
187       }
188    }
189    if (wpid > 0) {
190       if (WIFEXITED(chldstatus)) {           /* process exit()ed */
191          stat = WEXITSTATUS(chldstatus);
192          if (stat != 0) {
193             stat = ECHILD;
194          }
195          Dmsg1(200, "status =%d\n", stat);
196       } else if (WIFSIGNALED(chldstatus)) {  /* process died */
197          stat = ECHILD;
198          Dmsg0(200, "Signaled\n");
199       }
200    }  
201    if (bpipe->timer_id) {
202       stop_child_timer(bpipe->timer_id);
203    }
204    free(bpipe);
205    Dmsg1(200, "returning stat = %d\n", stat);
206    return stat;
207 }
208
209
210 /*
211  * Run an external program. Optionally wait a specified number
212  *   of seconds. Program killed if wait exceeded. Optionally
213  *   return the output from the program (normally a single line).
214  *
215  * Contrary to my normal calling conventions, this program 
216  *
217  *  Returns: 0 on success
218  *           non-zero on error == errno
219  */
220 int run_program(char *prog, int wait, POOLMEM *results)
221 {
222    BPIPE *bpipe;
223    int stat1, stat2;
224    char *mode;
225
226    mode = (char *)(results != NULL ? "r" : "");
227    bpipe = open_bpipe(prog, wait, mode);
228    if (!bpipe) {
229       return ENOENT;
230    }
231    if (results) {
232       mp_chr(results)[0] = 0;
233       stat1 = fgets(mp_chr(results), sizeof_pool_memory(results), bpipe->rfd) == NULL;
234    } else {
235       stat1 = 0;
236    }
237    stat2 = close_bpipe(bpipe);
238    return stat2 != 0 ? stat2 : stat1; 
239 }
240
241
242 /*
243  * Build argc and argv from a string
244  */
245 static void build_argc_argv(char *cmd, int *bargc, char *bargv[], int max_argv)
246 {
247    int i;       
248    char *p, *q, quote;
249    int argc = 0;
250
251    argc = 0;
252    for (i=0; i<max_argv; i++)
253       bargv[i] = NULL;
254
255    p = cmd;
256    quote = 0;
257    while  (*p && (*p == ' ' || *p == '\t'))
258       p++;
259    if (*p == '\"' || *p == '\'') {
260       quote = *p;
261       p++;
262    }
263    if (*p) {
264       while (*p && argc < MAX_ARGV) {
265          q = p;
266          if (quote) {
267             while (*q && *q != quote)
268             q++;
269             quote = 0;
270          } else {
271             while (*q && *q != ' ')
272             q++;
273          }
274          if (*q)
275             *(q++) = '\0';
276          bargv[argc++] = p;
277          p = q;
278          while (*p && (*p == ' ' || *p == '\t'))
279             p++;
280          if (*p == '\"' || *p == '\'') {
281             quote = *p;
282             p++;
283          }
284       }
285    }
286    *bargc = argc;
287 }