struct command_status *cstat);
static void forward_signals(int fd);
static void schedule_signal(int signo);
+#ifdef SA_SIGINFO
+static void handler_nofwd(int s, siginfo_t *info, void *context);
+#endif
/*
* Like execve(2) but falls back to running through /bin/sh
sa.sa_handler = handler;
sigaction(SIGALRM, &sa, NULL);
sigaction(SIGCHLD, &sa, NULL);
- sigaction(SIGHUP, &sa, NULL);
- sigaction(SIGINT, &sa, NULL);
sigaction(SIGPIPE, &sa, NULL);
- sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
sigaction(SIGUSR2, &sa, NULL);
+ /*
+ * When not running the command in a pty, we do not want to
+ * forward signals generated by the kernel that the child will
+ * already have received either by virtue of being in the
+ * controlling tty's process group (SIGINT, SIGQUIT) or because
+ * the session is terminating (SIGHUP).
+ */
+#ifdef SA_SIGINFO
+ if (!log_io) {
+ sa.sa_flags |= SA_SIGINFO;
+ sa.sa_sigaction = handler_nofwd;
+ }
+#endif
+ sigaction(SIGHUP, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGQUIT, &sa, NULL);
+
/* Max fd we will be selecting on. */
maxfd = MAX(sv[0], signal_pipe[0]);
/* shut up glibc */;
}
+#ifdef SA_SIGINFO
+/*
+ * Generic handler for signals passed from parent -> child.
+ * The other end of signal_pipe is checked in the main event loop.
+ * This version is for the non-pty case and does not forward
+ * signals that are generated by the kernel.
+ */
+static void
+handler_nofwd(int s, siginfo_t *info, void *context)
+{
+ unsigned char signo = (unsigned char)s;
+
+ /* Only forward user-generated signals. */
+ if (info->si_code <= 0) {
+ /*
+ * The pipe is non-blocking, if we overflow the kernel's pipe
+ * buffer we drop the signal. This is not a problem in practice.
+ */
+ if (write(signal_pipe[1], &signo, sizeof(signo)) == -1)
+ /* shut up glibc */;
+ }
+}
+#endif /* SA_SIGINFO */
+
/*
* Open a pipe and make both ends non-blocking.
* Returns 0 on success and -1 on error.