ppgrp = getpgrp(); /* parent's process group */
/*
- * XXX - should only send SIGCONT when command pgrp != parent pgrp
- * OR we were suspended by a user (not kernel or tty) signal.
+ * Handle suspend/restore of sudo and the command.
+ * In most cases, the command will be in the same process group as
+ * sudo and job control will "just work". However, if the command
+ * changes its process group ID and does not change it back (or is
+ * kill by SIGSTOP which is not catchable), we need to resume the
+ * command manually. Also, if SIGTSTP is sent directly to sudo,
+ * we need to suspend the command, and then suspend ourself, restoring
+ * the default SIGTSTP handler temporarily.
+ *
+ * XXX - currently we send SIGCONT upon resume in some cases where
+ * we don't need to (e.g. command pgrp == parent pgrp).
*/
zero_bytes(&sa, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_handler = handler;
#endif
sigaction(SIGCONT, &sa, NULL);
+#ifdef SA_SIGINFO
+ sa.sa_sigaction = handler_user_only;
+#endif
+ sigaction(SIGTSTP, &sa, NULL);
cmnd_pid = fork();
switch (cmnd_pid) {
* with SIGTTOU while the command continues to run.
*/
#ifdef HAVE_TCSETPGRP
+ sigaction_t sa, osa;
pid_t saved_pgrp = (pid_t)-1;
+ int signo = WSTOPSIG(status);
int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0);
if (fd != -1) {
if ((saved_pgrp = tcgetpgrp(fd)) == ppgrp)
saved_pgrp = -1;
}
#endif /* HAVE_TCSETPGRP */
- if (kill(getpid(), WSTOPSIG(status)) != 0)
- warning("kill(%d, %d)", getpid(), WSTOPSIG(status));
+ if (signo == SIGTSTP) {
+ zero_bytes(&sa, sizeof(sa));
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGTSTP, &sa, NULL);
+ }
+ if (kill(getpid(), signo) != 0)
+ warning("kill(%d, %d)", getpid(), signo);
+ if (signo == SIGTSTP)
+ sigaction(SIGTSTP, &osa, NULL);
#ifdef HAVE_TCSETPGRP
if (fd != -1) {
/*