]> Pileus Git - ~andy/fetchmail/blob - contrib/fetchmail-mda-fork.patch
Park Fabio Rossi's contribution, needs review.
[~andy/fetchmail] / contrib / fetchmail-mda-fork.patch
1 diff -rup /tmp/fetchmail-6.3.21//daemon.c ./daemon.c
2 --- /tmp/fetchmail-6.3.21//daemon.c     2011-08-21 15:34:58.000000000 +0200
3 +++ ./daemon.c  2012-02-19 21:10:16.200367846 +0100
4 @@ -53,9 +53,7 @@
5  #include "fetchmail.h"
6  #include "tunable.h"
7  
8 -static RETSIGTYPE
9 -sigchld_handler (int sig)
10 -/* process SIGCHLD to obtain the exit code of the terminating process */
11 +int wait_for_child(pid_t who)
12  {
13  #if    defined(HAVE_WAITPID)                           /* the POSIX way */
14      int status;
15 @@ -70,13 +68,23 @@ sigchld_handler (int sig)
16      int status;
17  #endif
18  
19 -    while ((pid = wait3(&status, WNOHANG, 0)) > 0)
20 +    while ((pid = wait4(who, &status, WNOHANG, 0)) > 0)
21         continue; /* swallow 'em up. */
22  #else  /* Zooks! Nothing to do but wait(), and hope we don't block... */
23      int status;
24  
25      wait(&status);
26  #endif
27 +
28 +    return (int)status;
29 +}
30 +
31 +static RETSIGTYPE
32 +sigchld_handler (int sig)
33 +/* process SIGCHLD to obtain the exit code of the terminating process */
34 +{
35 +    wait_for_child(-1);
36 +
37      lastsig = SIGCHLD;
38      (void)sig;
39  }
40 diff -rup /tmp/fetchmail-6.3.21//fetchmail.c ./fetchmail.c
41 --- /tmp/fetchmail-6.3.21//fetchmail.c  2011-08-21 15:34:58.000000000 +0200
42 +++ ./fetchmail.c       2012-02-19 21:13:05.279377301 +0100
43 @@ -1393,11 +1393,24 @@ static RETSIGTYPE terminate_poll(int sig
44  #endif /* POP3_ENABLE */
45  }
46  
47 +extern pid_t mda_pid;
48 +
49  static RETSIGTYPE terminate_run(int sig)
50  /* to be executed on normal or signal-induced termination */
51  {
52      struct query       *ctl;
53  
54 +    /* 
55 +     * kill explicitly the MDA process so that it dies *before* fetchmail
56 +        * otherwise an uncomplete message might be delivered generating garbage
57 +        * in the maildir/mailbox
58 +     */
59 +    if( (sig == SIGINT || sig == SIGTERM ) && mda_pid != 0)
60 +    {
61 +      report(stdout, GT_("killing MDA with PID %d\n"), mda_pid);
62 +      kill(mda_pid, sig);
63 +    }
64 +
65      terminate_poll(sig);
66  
67      /* 
68 diff -rup /tmp/fetchmail-6.3.21//sink.c ./sink.c
69 --- /tmp/fetchmail-6.3.21//sink.c       2012-02-19 17:57:37.000000000 +0100
70 +++ ./sink.c    2012-02-19 21:11:07.518370716 +0100
71 @@ -632,6 +632,7 @@ static int handle_smtp_report_without_bo
72  
73  /* these are shared by open_sink and stuffline */
74  static FILE *sinkfp;
75 +pid_t mda_pid = 0;
76  
77  int stuffline(struct query *ctl, char *buf)
78  /* ship a line to the given control block's output sink (SMTP server or MDA) */
79 @@ -1102,6 +1103,7 @@ static int open_mda_sink(struct query *c
80      struct     idlist *idp;
81      int        length = 0, fromlen = 0, nameslen = 0;
82      char       *names = NULL, *before, *after, *from = NULL;
83 +    int mda_pipe[2];
84  
85      (void)bad_addresses;
86      xfree(ctl->destaddr);
87 @@ -1219,7 +1221,7 @@ static int open_mda_sink(struct query *c
88  
89  
90      if (outlevel >= O_DEBUG)
91 -       report(stdout, GT_("about to deliver with: %s\n"), before);
92 +       report(stdout, GT_("about to deliver with: '%s'\n"), before);
93  
94  #ifdef HAVE_SETEUID
95      /*
96 @@ -1235,7 +1237,29 @@ static int open_mda_sink(struct query *c
97      }
98  #endif /* HAVE_SETEUID */
99  
100 -    sinkfp = popen(before, "w");
101 +    if(pipe(mda_pipe) != 0) {
102 +       report(stderr, GT_("Cannot create a pipe for the MDA: %s\n"), strerror(errno));
103 +       return PS_IOERR;
104 +    }
105 +
106 +       /* save client's (MDA) PID in a global var for a clean shutdown in the fetchmail signal handler */
107 +    mda_pid = fork();
108 +    if(mda_pid < 0) {
109 +       report(stderr, GT_("Unable to fork for the MDA dispatching: %s\n"), strerror(errno));
110 +       return PS_IOERR;
111 +    }
112 +       else if(mda_pid == 0) { /* child */
113 +       /* close the write-end of the pipe connecting the stdin of the mda process to the read-end */
114 +       close(mda_pipe[1]);
115 +       dup2(mda_pipe[0], STDIN_FILENO);
116 +
117 +       execl("/bin/sh", "sh", "-c", before, NULL);
118 +       report(stderr, GT_("Unable to exec the MDA: %s\n"), strerror(errno));
119 +       return PS_IOERR;
120 +    }
121 +
122 +    close(mda_pipe[0]);
123 +    sinkfp = fdopen(mda_pipe[1], "w");
124      free(before);
125      before = NULL;
126  
127 @@ -1249,6 +1273,7 @@ static int open_mda_sink(struct query *c
128  
129      if (!sinkfp)
130      {
131 +       mda_pid = 0;
132         report(stderr, GT_("MDA open failed\n"));
133         return(PS_IOERR);
134      }
135 @@ -1338,8 +1363,10 @@ void release_sink(struct query *ctl)
136      {
137         if (sinkfp)
138         {
139 -           pclose(sinkfp);
140 +           fclose(sinkfp); // send EOF to the pipe
141             sinkfp = (FILE *)NULL;
142 +               wait_for_child(mda_pid);
143 +               mda_pid = 0;
144         }
145         deal_with_sigchld(); /* Restore SIGCHLD handling to reap zombies */
146      }
147 @@ -1381,11 +1408,12 @@ int close_sink(struct query *ctl, struct
148         {
149             if (ferror(sinkfp))
150                 err = 1, e2 = errno;
151 -           if ((fflush(sinkfp)))
152 +           if (fclose(sinkfp)) // send EOF to the pipe
153                 err = 1, e2 = errno;
154  
155             errno = 0;
156 -           rc = pclose(sinkfp);
157 +               rc = wait_for_child(mda_pid);
158 +               mda_pid = 0;
159             e = errno;
160             sinkfp = (FILE *)NULL;
161         }
162 @@ -1404,8 +1432,8 @@ int close_sink(struct query *ctl, struct
163                         GT_("MDA returned nonzero status %d\n"), WEXITSTATUS(rc));
164             } else {
165                 report(stderr,
166 -                       GT_("Strange: MDA pclose returned %d and errno %d/%s, cannot handle at %s:%d\n"),
167 -                       rc, e, strerror(e), __FILE__, __LINE__);
168 +                       GT_("Unexpected error %d/%s waiting for MDA process, cannot handle at %s:%d\n"),
169 +                       e, strerror(e), __FILE__, __LINE__);
170             }
171  
172             return(FALSE);