Blob Blame History Raw
diff -up ./nss/lib/freebl/shvfy.c.block_sigchld ./nss/lib/freebl/shvfy.c
--- ./nss/lib/freebl/shvfy.c.block_sigchld	2014-10-23 10:38:01.494609227 -0700
+++ ./nss/lib/freebl/shvfy.c	2014-10-23 10:44:35.395609071 -0700
@@ -45,8 +45,50 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include <sys/wait.h>
 #include <sys/stat.h>
+#include <errno.h>
+
+#define __USE_POSIX199309 1 /* need to use posix signal handler */
+#include <signal.h>
+#include <sys/wait.h> /* must be after signal.h */
+
+
+/*
+ * handler to block our sigchld call to keep from confusing parent apps
+ */
+static struct sigaction parent_handler;
+static int child_pid = 0;
+
+static void
+handle_sigchld(int signum, siginfo_t *sinfo, void *utcx)
+{
+    int status;
+    int save_errno = errno;
+    int ret;
+
+    if ((signum == SIGCHLD) && (sinfo->si_pid == child_pid)) {
+	waitpid(sinfo->si_pid,&status, 0);
+	errno = save_errno;
+	return;
+    }
+
+
+    /* call parent, first set the parents mask */
+    ret = sigprocmask(SIG_BLOCK, &parent_handler.sa_mask, NULL);
+    errno = save_errno; /* restore previous errno. allow parent to change
+			 * errno if it needs to */
+    if (ret < 0) {
+	return;
+    }
+    /* now call the parent */
+    if (parent_handler.sa_flags & SA_SIGINFO) {
+	(*parent_handler.sa_sigaction)(signum, sinfo, utcx);
+    } else {
+	(*parent_handler.sa_handler)(signum);
+    }
+    /* libc/kernel should restore our mask as this point, so we don't
+     * need to restore the mask we set above. */
+}
 
 /*
  * This function returns an NSPR PRFileDesc * which the caller can read to
@@ -72,6 +114,8 @@ bl_OpenUnPrelink(const char *shName, int
     pid_t child;
     int argc = 0, argNext = 0;
     struct stat statBuf;
+    struct sigaction our_handler;
+    sigset_t inMask,outMask;
     int pipefd[2] = {-1,-1};
     int ret;
 
@@ -155,6 +199,25 @@ bl_OpenUnPrelink(const char *shName, int
 	goto loser;
     }
 
+    child_pid = 0;
+    our_handler.sa_flags = SA_SIGINFO;
+    our_handler.sa_sigaction = handle_sigchld;
+    sigemptyset(&our_handler.sa_mask);
+    ret = sigaction(SIGCHLD, &our_handler, &parent_handler);
+    if (ret < 0) {
+	goto loser;
+    }
+
+    /* don't accept a sigchild until we've set out child pid */
+    sigemptyset(&inMask);
+    sigemptyset(&outMask);
+    sigaddset(&inMask,SIGCHLD);
+    ret = sigprocmask(SIG_BLOCK, &inMask, &outMask);
+    if (ret < 0) {
+	sigaction(SIGCHLD, &parent_handler, NULL);
+	goto loser;
+    }
+
     /* use vfork() so we don't trigger the pthread_at_fork() handlers */
     child = vfork();
     if (child < 0) goto loser;
@@ -174,6 +237,8 @@ bl_OpenUnPrelink(const char *shName, int
 	/* avoid at_exit() handlers */
 	_exit(1); /* shouldn't reach here except on an error */
     }
+    child_pid = child;
+    sigprocmask(SIG_SETMASK, &outMask, 0); /* child is set,accept signals now */
     close(pipefd[1]);
     pipefd[1] = -1;
 
@@ -218,6 +283,9 @@ bl_CloseUnPrelink( PRFileDesc *file, int
     /* reap the child */
     if (pid) {
 	waitpid(pid, NULL, 0);
+	/* restore the parent handler */
+	sigaction(SIGCHLD, &parent_handler, NULL);
+	child_pid = 0;
     }
 }
 #endif