summaryrefslogtreecommitdiffstats
path: root/login-utils/sulogin.c
diff options
context:
space:
mode:
Diffstat (limited to 'login-utils/sulogin.c')
-rw-r--r--login-utils/sulogin.c104
1 files changed, 78 insertions, 26 deletions
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<<con->id);
sushell(pwd);
- *usemask &= ~(1<<con->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<<con->id);
+ if (ret < 0) {
+ if (errno == ECHILD)
+ break;
+ if (errno == EINTR)
continue;
- }
- if (kill(con->pid, 0) < 0) {
- *usemask &= ~(1<<con->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<<con->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;