Reland "Add optional signal forwarder and '-z' option to cli"

This is a reland of https://android-review.googlesource.com/#/c/365114/,
using NSIG instead of SIGUNUSED.

This reverts commit 7151582f0b847b62ec74c600dd6b99e8a0078c75.

Bug: None
Test: Build for ARM, MIPS, x86.
Change-Id: I5135c5c36fb4f98467790efaa0cba6d82e2ca2b6
diff --git a/libminijail.c b/libminijail.c
index 2e3e8b6..1da4e19 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -127,6 +127,7 @@
 		int reset_signal_mask : 1;
 		int close_open_fds : 1;
 		int new_session_keyring : 1;
+		int forward_signals : 1;
 	} flags;
 	uid_t uid;
 	gid_t gid;
@@ -169,6 +170,7 @@
 	j->flags.do_init = 0;
 	j->flags.pid_file = 0;
 	j->flags.cgroups = 0;
+	j->flags.forward_signals = 0;
 }
 
 /*
@@ -619,6 +621,12 @@
 	return 0;
 }
 
+int API minijail_forward_signals(struct minijail *j)
+{
+	j->flags.forward_signals = 1;
+	return 0;
+}
+
 int API minijail_mount_with_data(struct minijail *j, const char *src,
 				 const char *dest, const char *type,
 				 unsigned long flags, const char *data)
@@ -1504,6 +1512,42 @@
 	}
 }
 
+static pid_t forward_pid = -1;
+
+static void forward_signal(__attribute__((unused)) int nr,
+			   __attribute__((unused)) siginfo_t *siginfo,
+			   __attribute__((unused)) void *void_context)
+{
+	if (forward_pid != -1) {
+		kill(forward_pid, nr);
+	}
+}
+
+static void install_signal_handlers(void)
+{
+	struct sigaction act;
+
+	memset(&act, 0, sizeof(act));
+	act.sa_sigaction = &forward_signal;
+	act.sa_flags = SA_SIGINFO | SA_RESTART;
+
+	/* Handle all signals, except SIGCHLD. */
+	for (int nr = 1; nr < NSIG; nr++) {
+		/*
+		 * We don't care if we get EINVAL: that just means that we
+		 * can't handle this signal, so let's skip it and continue.
+		 */
+		sigaction(nr, &act, NULL);
+	}
+	/* Reset SIGCHLD's handler. */
+	signal(SIGCHLD, SIG_DFL);
+
+	/* Handle real-time signals. */
+	for (int nr = SIGRTMIN; nr <= SIGRTMAX; nr++) {
+		sigaction(nr, &act, NULL);
+	}
+}
+
 void API minijail_enter(const struct minijail *j)
 {
 	/*
@@ -2022,6 +2066,11 @@
 
 		j->initpid = child_pid;
 
+		if (j->flags.forward_signals) {
+			forward_pid = child_pid;
+			install_signal_handlers();
+		}
+
 		if (j->flags.pid_file)
 			write_pid_file_or_die(j);