From cde7699c27ff22bed8d554d50e10a42ec0dba6d8 Mon Sep 17 00:00:00 2001 From: Werner Fink Date: Thu, 11 Feb 2016 13:35:26 +0100 Subject: sulogin: avoid shared memory area usemask but use waitid() for childs This small patch improves the console detection code and also avoids not existing device nodes due strdup() which is used in canonicalize_path(). Beside this now the code for emergeny mount does work if enabled at configure time. Signed-off-by: Werner Fink --- login-utils/sulogin.c | 104 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 78 insertions(+), 26 deletions(-) (limited to 'login-utils/sulogin.c') diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c index be52141c1..4b1e44b07 100644 --- a/login-utils/sulogin.c +++ b/login-utils/sulogin.c @@ -66,7 +66,6 @@ static unsigned int timeout; static int profile; static volatile uint32_t openfd; /* Remember higher file descriptors */ -static volatile uint32_t *usemask; struct sigaction saved_sigint; struct sigaction saved_sigtstp; @@ -109,7 +108,8 @@ static int plymouth_command(const char* arg) dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); - close(fd); + if (fd > 2) + close(fd); execl(cmd, cmd, arg, (char *) NULL); exit(127); } else if (pid > 0) { @@ -857,9 +857,12 @@ int main(int argc, char **argv) struct console *con; char *tty = NULL; struct passwd *pwd; - int c, status = 0; - int reconnect = 0; + struct timespec sigwait = {0, 50000000}; + siginfo_t status = {}; + sigset_t set = {}; + int c, reconnect = 0; int opt_e = 0; + int wait = 0; pid_t pid; static const struct option longopts[] = { @@ -985,9 +988,6 @@ int main(int argc, char **argv) tcinit(con); } ptr = (&consoles)->next; - usemask = (uint32_t*) mmap(NULL, sizeof(uint32_t), - PROT_READ|PROT_WRITE, - MAP_ANONYMOUS|MAP_SHARED, -1, 0); if (ptr->next == &consoles) { con = list_entry(ptr, struct console, entry); @@ -1033,9 +1033,7 @@ int main(int argc, char **argv) } if (doshell) { - *usemask |= (1<id); sushell(pwd); - *usemask &= ~(1<id); failed++; } @@ -1068,28 +1066,82 @@ int main(int argc, char **argv) } while (ptr != &consoles); - while ((pid = wait(&status))) { - if (errno == ECHILD) + do { + int ret; + + status.si_pid = 0; + ret = waitid(P_ALL, 0, &status, WEXITED); + + if (ret == 0) break; - if (pid < 0) - continue; - list_for_each(ptr, &consoles) { - con = list_entry(ptr, struct console, entry); - if (con->pid == pid) { - *usemask &= ~(1<id); + if (ret < 0) { + if (errno == ECHILD) + break; + if (errno == EINTR) continue; - } - if (kill(con->pid, 0) < 0) { - *usemask &= ~(1<id); + } + + errx(EXIT_FAILURE, _("Can not wait on su shell\n\n")); + + } while (1); + + list_for_each(ptr, &consoles) { + con = list_entry(ptr, struct console, entry); + + if (con->fd < 0) + continue; + if (con->pid < 0) + continue; + if (con->pid == status.si_pid) + con->pid = -1; + else { + kill(con->pid, SIGTERM); + wait++; + } + } + + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + + do { + int signum, ret; + + if (!wait) + break; + + status.si_pid = 0; + ret = waitid(P_ALL, 0, &status, WEXITED|WNOHANG); + + if (ret < 0) { + if (errno == ECHILD) + break; + if (errno == EINTR) continue; + } + + if (!ret && status.si_pid > 0) { + list_for_each(ptr, &consoles) { + con = list_entry(ptr, struct console, entry); + + if (con->fd < 0) + continue; + if (con->pid < 0) + continue; + if (con->pid == status.si_pid) { + con->pid = -1; + wait--; + } } - if (*usemask & (1<id)) - continue; - kill(con->pid, SIGHUP); - xusleep(50000); - kill(con->pid, SIGKILL); + continue; } - } + + signum = sigtimedwait(&set, NULL, &sigwait); + if (signum != SIGCHLD) { + if (signum < 0 && errno == EAGAIN) + break; + } + + } while (1); mask_signal(SIGCHLD, SIG_DFL, NULL); return EXIT_SUCCESS; -- cgit v1.2.3-55-g7522