*/
/*
- Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+ Copyright (C) 2002-2004 Kern Sibbald and John Walker
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
* a bi-directional pipe so that the user can read from and
* write to the program.
*/
-BPIPE *open_bpipe(char *prog, int wait, char *mode)
+BPIPE *open_bpipe(char *prog, int wait, const char *mode)
{
char *bargv[MAX_ARGV];
- int bargc;
+ int bargc, i;
int readp[2], writep[2];
POOLMEM *tprog;
int mode_read, mode_write;
build_argc_argv(mp_chr(tprog), &bargc, bargv, MAX_ARGV);
#ifdef xxxxxx
printf("argc=%d\n", bargc);
- int i;
for (i=0; i<bargc; i++) {
printf("argc=%d argv=%s:\n", i, bargv[i]);
}
return NULL;
}
if (mode_read && pipe(readp) == -1) {
+ if (mode_write) {
+ close(writep[0]);
+ close(writep[1]);
+ }
free(bpipe);
return NULL;
}
/* Start worker process */
switch (bpipe->worker_pid = fork()) {
case -1: /* error */
+ if (mode_write) {
+ close(writep[0]);
+ close(writep[1]);
+ }
+ if (mode_read) {
+ close(readp[0]);
+ close(readp[1]);
+ }
free(bpipe);
return NULL;
dup2(readp[1], 1); /* dup our read to his stdout */
dup2(readp[1], 2); /* and his stderr */
}
+ closelog(); /* close syslog if open */
+ for (i=3; i<=32; i++) { /* close any open file descriptors */
+ close(i);
+ }
execvp(bargv[0], bargv); /* call the program */
exit(errno); /* shouldn't get here */
return stat;
}
-/* Close both pipes and free resources */
+/*
+ * Close both pipes and free resources
+ *
+ * Returns: 0 on success
+ * errno on failure
+ */
int close_bpipe(BPIPE *bpipe)
{
int chldstatus = 0;
/* wait for worker child to exit */
for ( ;; ) {
- wpid = waitpid(bpipe->worker_pid, &chldstatus, wait_option);
- if (wpid == bpipe->worker_pid || (wpid == -1 && errno != EINTR)) {
+ Dmsg2(200, "Wait for %d opt=%d\n", bpipe->worker_pid, wait_option);
+ do {
+ wpid = waitpid(bpipe->worker_pid, &chldstatus, wait_option);
+ } while (wpid == -1 && (errno == EINTR || errno == EAGAIN));
+ if (wpid == bpipe->worker_pid || wpid == -1) {
+ Dmsg3(200, "Got break wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
+ wpid==-1?strerror(errno):"none");
break;
}
+ Dmsg3(200, "Got wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
+ wpid==-1?strerror(errno):"none");
if (remaining_wait > 0) {
bmicrosleep(1, 0); /* wait one second */
remaining_wait--;
} else {
- stat = 1; /* set error status */
- errno = ETIME; /* set timed out */
+ stat = ETIME; /* set error status */
wpid = -1;
break; /* don't wait any longer */
}
if (wpid > 0) {
if (WIFEXITED(chldstatus)) { /* process exit()ed */
stat = WEXITSTATUS(chldstatus);
+ if (stat != 0) {
+ Dmsg1(100, "Non-zero status %s returned from child.\n", stat);
+ stat = ECHILD;
+ }
+ Dmsg1(200, "child status=%d\n", stat);
} else if (WIFSIGNALED(chldstatus)) { /* process died */
- stat = 1;
- }
- if (stat != 0) {
- errno = ECHILD; /* set child errno */
+ stat = ECHILD;
+ Dmsg0(200, "Signaled\n");
}
}
if (bpipe->timer_id) {
stop_child_timer(bpipe->timer_id);
}
free(bpipe);
-#ifdef HAVE_FREEBSD_OS
- stat = 0; /* kludge because FreeBSD doesn't seem to return valid status */
-#endif
+ Dmsg1(200, "returning stat = %d\n", stat);
return stat;
}
* Contrary to my normal calling conventions, this program
*
* Returns: 0 on success
- * non-zero on error
+ * non-zero on error == errno
*/
int run_program(char *prog, int wait, POOLMEM *results)
{
mode = (char *)(results != NULL ? "r" : "");
bpipe = open_bpipe(prog, wait, mode);
if (!bpipe) {
- return 0;
+ return ENOENT;
}
if (results) {
mp_chr(results)[0] = 0;
- stat1 = fgets(mp_chr(results), sizeof_pool_memory(results), bpipe->rfd) == NULL;
+ fgets(mp_chr(results), sizeof_pool_memory(results), bpipe->rfd);
+ if (feof(bpipe->rfd)) {
+ stat1 = 0;
+ } else {
+ stat1 = ferror(bpipe->rfd);
+ }
+ if (stat1 < 0) {
+ Dmsg2(100, "Run program fgets stat=%d ERR=%s\n", stat1, strerror(errno));
+ } else if (stat1 != 0) {
+ Dmsg1(100, "Run program fgets stat=%d\n", stat1);
+ }
} else {
stat1 = 0;
}
stat2 = close_bpipe(bpipe);
- return stat2 != 0 ? stat2 : stat1;
+ stat1 = stat2 != 0 ? stat2 : stat1;
+ Dmsg1(100, "Run program returning %d\n", stat1);
+ return stat1;
}