diff -ru bsd-mailx-8.1.2-0.20081101cvs/extern.h bsd-mailx-8.1.2-0.20081101cvs-patched/extern.h
--- bsd-mailx-8.1.2-0.20081101cvs/extern.h 2009-10-07 17:27:33.000000000 +0300
+++ bsd-mailx-8.1.2-0.20081101cvs-patched/extern.h 2009-10-06 22:16:38.000000000 +0300
@@ -127,6 +127,7 @@
void fmt(char *, struct name *, FILE *, int);
int folders(void *);
int forward(char *, FILE *, char *, int);
+int add_child(pid_t);
void free_child(pid_t);
int from(void *);
off_t fsize(FILE *);
diff -ru bsd-mailx-8.1.2-0.20081101cvs/popen.c bsd-mailx-8.1.2-0.20081101cvs-patched/popen.c
--- bsd-mailx-8.1.2-0.20081101cvs/popen.c 2009-10-07 17:27:33.000000000 +0300
+++ bsd-mailx-8.1.2-0.20081101cvs-patched/popen.c 2009-10-07 19:19:46.000000000 +0300
@@ -407,6 +407,17 @@
}
/*
+ * Mark that we will wait for this child via SIGCHLD, or waitpid() manually, and we want its exit status stored.
+ */
+int
+add_child(pid_t pid) {
+ if (!findchild(pid, 0/* alloc if not present */))
+ return(-1); // this should never happen
+ else
+ return(0);
+}
+
+/*
* Mark a child as don't care.
*/
void
diff -ru bsd-mailx-8.1.2-0.20081101cvs/send.c bsd-mailx-8.1.2-0.20081101cvs-patched/send.c
--- bsd-mailx-8.1.2-0.20081101cvs/send.c 2009-10-07 17:27:33.000000000 +0300
+++ bsd-mailx-8.1.2-0.20081101cvs-patched/send.c 2009-10-07 19:18:15.000000000 +0300
@@ -357,6 +357,7 @@
struct name *to;
FILE *mtf;
int w;
+ sigset_t parent_nset, parent_oset;
/*
* Collect user's mail from standard input.
@@ -411,6 +412,15 @@
}
if ((cp = value("record")) != NULL)
(void)savemail(expand(cp), mtf);
+
+ /*
+ * Block the SIGCHLD signal temporarily, until we fork() a child and add its PID to the struct child "child" list.
+ * See: Bug#550116
+ */
+ sigemptyset(&parent_nset);
+ sigaddset(&parent_nset, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &parent_nset, &parent_oset);
+
/*
* Fork, set up the temporary mail file as standard
* input for "mail", and exec with the user list we generated
@@ -425,6 +435,12 @@
if (pid == 0) {
sigset_t nset;
+ /*
+ * Restore the original signal mask which we altered in the parent, just in case.
+ * See: Bug#550116
+ */
+ sigprocmask(SIG_SETMASK, &parent_oset, NULL);
+
sigemptyset(&nset);
sigaddset(&nset, SIGHUP);
sigaddset(&nset, SIGINT);
@@ -441,6 +457,18 @@
warn("%s", cp);
_exit(1);
}
+
+ /*
+ * Add the PID to the struct child "child" list or else the sigchild() handler may reap the child
+ * before we manage to reap it in wait_child().
+ * Then restore the original signal mask.
+ * See: Bug#550116
+ */
+ if (add_child(pid)) {
+ fprintf(stderr, "findchild() failed"); // this should never happen
+ }
+ sigprocmask(SIG_SETMASK, &parent_oset, NULL);
+
#ifndef DEBIAN
if (value("verbose") != NULL)
(void)wait_child(pid);