hush: fixes and small shrink for HUSH_JOB!=y

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/shell/hush.c b/shell/hush.c
index bb95d63..132b974 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -805,9 +805,9 @@
 	unsigned special_sig_mask;
 #if ENABLE_HUSH_JOB
 	unsigned fatal_sig_mask;
-#define G_fatal_sig_mask G.fatal_sig_mask
+# define G_fatal_sig_mask G.fatal_sig_mask
 #else
-#define G_fatal_sig_mask 0
+# define G_fatal_sig_mask 0
 #endif
 	char **traps; /* char *traps[NSIG] */
 	sigset_t pending_set;
@@ -1414,6 +1414,9 @@
  * Standard says "When a subshell is entered, traps that are not being ignored
  * are set to the default actions". bash interprets it so that traps which
  * are set to '' (ignore) are NOT reset to defaults. We do the same.
+ *
+ * TODO: don't use signal() to install sighandlers: need to mask ALL signals
+ * while handler runs. I saw signal nesting in one strace, race window isn't small.
  */
 enum {
 	SPECIAL_INTERACTIVE_SIGS = 0
@@ -1486,12 +1489,13 @@
 		unsigned sigmask = (1 << sig);
 
 #if ENABLE_HUSH_JOB
-		/* sig is fatal? */
+		/* is sig fatal? */
 		if (G_fatal_sig_mask & sigmask)
 			handler = sigexit;
+		else
 #endif
 		/* sig has special handling? */
-		else if (G.special_sig_mask & sigmask) {
+		if (G.special_sig_mask & sigmask) {
 			handler = record_pending_signo;
 			/* TTIN/TTOU/TSTP can't be set to record_pending_signo
 			 * in order to ignore them: they will be raised
@@ -5604,9 +5608,6 @@
 	 * _inside_ group (just before echo 1), it works.
 	 *
 	 * I conclude it means we don't need to pass active traps here.
-	 * Even if we would use signal handlers instead of signal masking
-	 * in order to implement trap handling,
-	 * exec syscall below resets signals to SIG_DFL for us.
 	 */
 	*pp++ = (char *) "-c";
 	*pp++ = (char *) s;
@@ -5623,7 +5624,9 @@
 
  do_exec:
 	debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s);
-	switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
+	/* Don't propagate SIG_IGN to the child */
+	if (SPECIAL_JOBSTOP_SIGS != 0)
+		switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
 	execve(bb_busybox_exec_path, argv, pp);
 	/* Fallback. Useful for init=/bin/hush usage etc */
 	if (argv[0][0] == '/')
@@ -6277,7 +6280,9 @@
 static void execvp_or_die(char **argv)
 {
 	debug_printf_exec("execing '%s'\n", argv[0]);
-	switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
+	/* Don't propagate SIG_IGN to the child */
+	if (SPECIAL_JOBSTOP_SIGS != 0)
+		switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
 	execvp(argv[0], argv);
 	bb_perror_msg("can't execute '%s'", argv[0]);
 	_exit(127); /* bash compat */
@@ -6409,7 +6414,9 @@
 # endif
 			/* Re-exec ourselves */
 			debug_printf_exec("re-execing applet '%s'\n", argv[0]);
-			switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
+			/* Don't propagate SIG_IGN to the child */
+			if (SPECIAL_JOBSTOP_SIGS != 0)
+				switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS);
 			execv(bb_busybox_exec_path, argv);
 			/* If they called chroot or otherwise made the binary no longer
 			 * executable, fall through */