Associate the grandchild's pgrp with the tty instead of the child's
and just get suspend notifications via SIGCHLD instead of directly. This fixes a hang with programs that try to set terminal attributes and is more consistent with how the shell handles things.
This commit is contained in:
42
script.c
42
script.c
@@ -102,8 +102,6 @@ static void sync_winsize __P((int src, int dst));
|
|||||||
static void handler __P((int s));
|
static void handler __P((int s));
|
||||||
static void sigchild __P((int s));
|
static void sigchild __P((int s));
|
||||||
static void sigwinch __P((int s));
|
static void sigwinch __P((int s));
|
||||||
static void sigtstp __P((int s));
|
|
||||||
static void sigrepost __P((int s));
|
|
||||||
static int get_pty __P((int *master, int *slave));
|
static int get_pty __P((int *master, int *slave));
|
||||||
static void flush_output __P((struct script_buf *output, struct timeval *then,
|
static void flush_output __P((struct script_buf *output, struct timeval *then,
|
||||||
struct timeval *now, FILE *ofile, FILE *tfile));
|
struct timeval *now, FILE *ofile, FILE *tfile));
|
||||||
@@ -504,24 +502,10 @@ script_child(path, argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Setup signal handlers for child exit, and tty-related signals. */
|
/* Setup signal handler for child stop/exit */
|
||||||
zero_bytes(&sa, sizeof(sa));
|
zero_bytes(&sa, sizeof(sa));
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_flags = SA_RESTART;
|
sa.sa_flags = SA_RESTART;
|
||||||
|
|
||||||
/* These tty-related signals get relayed back to the parent. */
|
|
||||||
sa.sa_handler = sigtstp;
|
|
||||||
sigaction(SIGTSTP, &sa, NULL);
|
|
||||||
sigaction(SIGTTIN, &sa, NULL);
|
|
||||||
sigaction(SIGTTOU, &sa, NULL);
|
|
||||||
|
|
||||||
/* These signals just get posted to the grandchilds pgrp. */
|
|
||||||
sa.sa_handler = sigrepost;
|
|
||||||
sigaction(SIGQUIT, &sa, NULL);
|
|
||||||
sigaction(SIGINT, &sa, NULL);
|
|
||||||
|
|
||||||
/* Do not want child stop notifications. */
|
|
||||||
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
|
|
||||||
sa.sa_handler = sigchild;
|
sa.sa_handler = sigchild;
|
||||||
sigaction(SIGCHLD, &sa, NULL);
|
sigaction(SIGCHLD, &sa, NULL);
|
||||||
|
|
||||||
@@ -729,12 +713,16 @@ script_grandchild(path, argv, rbac_enabled)
|
|||||||
char *argv[];
|
char *argv[];
|
||||||
int rbac_enabled;
|
int rbac_enabled;
|
||||||
{
|
{
|
||||||
/* Also set process group here to avoid a race condition. */
|
pid_t self = getpid();
|
||||||
setpgid(0, getpid());
|
|
||||||
|
/* Also set our process group here to avoid a race condition. */
|
||||||
|
setpgid(0, self);
|
||||||
|
|
||||||
dup2(script_fds[SFD_SLAVE], STDIN_FILENO);
|
dup2(script_fds[SFD_SLAVE], STDIN_FILENO);
|
||||||
dup2(script_fds[SFD_SLAVE], STDOUT_FILENO);
|
dup2(script_fds[SFD_SLAVE], STDOUT_FILENO);
|
||||||
dup2(script_fds[SFD_SLAVE], STDERR_FILENO);
|
dup2(script_fds[SFD_SLAVE], STDERR_FILENO);
|
||||||
|
if (tcsetpgrp(STDIN_FILENO, self) != 0)
|
||||||
|
warning("tcsetpgrp");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close old fds and exec command.
|
* Close old fds and exec command.
|
||||||
@@ -744,6 +732,7 @@ script_grandchild(path, argv, rbac_enabled)
|
|||||||
close(script_fds[SFD_LOG]);
|
close(script_fds[SFD_LOG]);
|
||||||
close(script_fds[SFD_OUTPUT]);
|
close(script_fds[SFD_OUTPUT]);
|
||||||
close(script_fds[SFD_TIMING]);
|
close(script_fds[SFD_TIMING]);
|
||||||
|
|
||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
if (rbac_enabled)
|
if (rbac_enabled)
|
||||||
selinux_execv(path, argv);
|
selinux_execv(path, argv);
|
||||||
@@ -794,17 +783,22 @@ sigchild(signo)
|
|||||||
#ifdef sudo_waitpid
|
#ifdef sudo_waitpid
|
||||||
do {
|
do {
|
||||||
pid = sudo_waitpid(grandchild, &grandchild_status, WNOHANG);
|
pid = sudo_waitpid(grandchild, &grandchild_status, WNOHANG);
|
||||||
if (pid == grandchild) {
|
if (pid == grandchild)
|
||||||
alive = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
} while (pid > 0 || (pid == -1 && errno == EINTR));
|
} while (pid > 0 || (pid == -1 && errno == EINTR));
|
||||||
#else
|
#else
|
||||||
do {
|
do {
|
||||||
pid = wait(&grandchild_status);
|
pid = wait(&grandchild_status);
|
||||||
} while (pid == -1 && errno == EINTR);
|
} while (pid == -1 && errno == EINTR);
|
||||||
alive = 0;
|
|
||||||
#endif
|
#endif
|
||||||
|
if (pid == grandchild) {
|
||||||
|
if (WIFSTOPPED(grandchild_status)) {
|
||||||
|
suspended = 1;
|
||||||
|
signo = WSTOPSIG(grandchild_status);
|
||||||
|
} else {
|
||||||
|
alive = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
errno = serrno;
|
errno = serrno;
|
||||||
}
|
}
|
||||||
@@ -827,6 +821,8 @@ sigtstp(s)
|
|||||||
{
|
{
|
||||||
int serrno = errno;
|
int serrno = errno;
|
||||||
|
|
||||||
|
write(STDERR_FILENO, "sigtstp\n", 8);
|
||||||
|
|
||||||
/* Event loop needs to know which signal to relay to parent. */
|
/* Event loop needs to know which signal to relay to parent. */
|
||||||
signo = s;
|
signo = s;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user