diff -rup /tmp/fetchmail-6.3.21//daemon.c ./daemon.c --- /tmp/fetchmail-6.3.21//daemon.c 2011-08-21 15:34:58.000000000 +0200 +++ ./daemon.c 2012-02-19 21:10:16.200367846 +0100 @@ -53,9 +53,7 @@ #include "fetchmail.h" #include "tunable.h" -static RETSIGTYPE -sigchld_handler (int sig) -/* process SIGCHLD to obtain the exit code of the terminating process */ +int wait_for_child(pid_t who) { #if defined(HAVE_WAITPID) /* the POSIX way */ int status; @@ -70,13 +68,23 @@ sigchld_handler (int sig) int status; #endif - while ((pid = wait3(&status, WNOHANG, 0)) > 0) + while ((pid = wait4(who, &status, WNOHANG, 0)) > 0) continue; /* swallow 'em up. */ #else /* Zooks! Nothing to do but wait(), and hope we don't block... */ int status; wait(&status); #endif + + return (int)status; +} + +static RETSIGTYPE +sigchld_handler (int sig) +/* process SIGCHLD to obtain the exit code of the terminating process */ +{ + wait_for_child(-1); + lastsig = SIGCHLD; (void)sig; } diff -rup /tmp/fetchmail-6.3.21//fetchmail.c ./fetchmail.c --- /tmp/fetchmail-6.3.21//fetchmail.c 2011-08-21 15:34:58.000000000 +0200 +++ ./fetchmail.c 2012-02-19 21:13:05.279377301 +0100 @@ -1393,11 +1393,24 @@ static RETSIGTYPE terminate_poll(int sig #endif /* POP3_ENABLE */ } +extern pid_t mda_pid; + static RETSIGTYPE terminate_run(int sig) /* to be executed on normal or signal-induced termination */ { struct query *ctl; + /* + * kill explicitly the MDA process so that it dies *before* fetchmail + * otherwise an uncomplete message might be delivered generating garbage + * in the maildir/mailbox + */ + if( (sig == SIGINT || sig == SIGTERM ) && mda_pid != 0) + { + report(stdout, GT_("killing MDA with PID %d\n"), mda_pid); + kill(mda_pid, sig); + } + terminate_poll(sig); /* diff -rup /tmp/fetchmail-6.3.21//sink.c ./sink.c --- /tmp/fetchmail-6.3.21//sink.c 2012-02-19 17:57:37.000000000 +0100 +++ ./sink.c 2012-02-19 21:11:07.518370716 +0100 @@ -632,6 +632,7 @@ static int handle_smtp_report_without_bo /* these are shared by open_sink and stuffline */ static FILE *sinkfp; +pid_t mda_pid = 0; int stuffline(struct query *ctl, char *buf) /* ship a line to the given control block's output sink (SMTP server or MDA) */ @@ -1102,6 +1103,7 @@ static int open_mda_sink(struct query *c struct idlist *idp; int length = 0, fromlen = 0, nameslen = 0; char *names = NULL, *before, *after, *from = NULL; + int mda_pipe[2]; (void)bad_addresses; xfree(ctl->destaddr); @@ -1219,7 +1221,7 @@ static int open_mda_sink(struct query *c if (outlevel >= O_DEBUG) - report(stdout, GT_("about to deliver with: %s\n"), before); + report(stdout, GT_("about to deliver with: '%s'\n"), before); #ifdef HAVE_SETEUID /* @@ -1235,7 +1237,29 @@ static int open_mda_sink(struct query *c } #endif /* HAVE_SETEUID */ - sinkfp = popen(before, "w"); + if(pipe(mda_pipe) != 0) { + report(stderr, GT_("Cannot create a pipe for the MDA: %s\n"), strerror(errno)); + return PS_IOERR; + } + + /* save client's (MDA) PID in a global var for a clean shutdown in the fetchmail signal handler */ + mda_pid = fork(); + if(mda_pid < 0) { + report(stderr, GT_("Unable to fork for the MDA dispatching: %s\n"), strerror(errno)); + return PS_IOERR; + } + else if(mda_pid == 0) { /* child */ + /* close the write-end of the pipe connecting the stdin of the mda process to the read-end */ + close(mda_pipe[1]); + dup2(mda_pipe[0], STDIN_FILENO); + + execl("/bin/sh", "sh", "-c", before, NULL); + report(stderr, GT_("Unable to exec the MDA: %s\n"), strerror(errno)); + return PS_IOERR; + } + + close(mda_pipe[0]); + sinkfp = fdopen(mda_pipe[1], "w"); free(before); before = NULL; @@ -1249,6 +1273,7 @@ static int open_mda_sink(struct query *c if (!sinkfp) { + mda_pid = 0; report(stderr, GT_("MDA open failed\n")); return(PS_IOERR); } @@ -1338,8 +1363,10 @@ void release_sink(struct query *ctl) { if (sinkfp) { - pclose(sinkfp); + fclose(sinkfp); // send EOF to the pipe sinkfp = (FILE *)NULL; + wait_for_child(mda_pid); + mda_pid = 0; } deal_with_sigchld(); /* Restore SIGCHLD handling to reap zombies */ } @@ -1381,11 +1408,12 @@ int close_sink(struct query *ctl, struct { if (ferror(sinkfp)) err = 1, e2 = errno; - if ((fflush(sinkfp))) + if (fclose(sinkfp)) // send EOF to the pipe err = 1, e2 = errno; errno = 0; - rc = pclose(sinkfp); + rc = wait_for_child(mda_pid); + mda_pid = 0; e = errno; sinkfp = (FILE *)NULL; } @@ -1404,8 +1432,8 @@ int close_sink(struct query *ctl, struct GT_("MDA returned nonzero status %d\n"), WEXITSTATUS(rc)); } else { report(stderr, - GT_("Strange: MDA pclose returned %d and errno %d/%s, cannot handle at %s:%d\n"), - rc, e, strerror(e), __FILE__, __LINE__); + GT_("Unexpected error %d/%s waiting for MDA process, cannot handle at %s:%d\n"), + e, strerror(e), __FILE__, __LINE__); } return(FALSE);