summaryrefslogtreecommitdiffstats
path: root/login-utils/sulogin.c
diff options
context:
space:
mode:
authorWerner Fink2016-02-11 13:35:26 +0100
committerKarel Zak2016-02-12 11:19:21 +0100
commitcde7699c27ff22bed8d554d50e10a42ec0dba6d8 (patch)
treeb0730ea20d74c823c1f5025d9c7ad77740b38829 /login-utils/sulogin.c
parenttests: add test for loop option in fstab (diff)
downloadkernel-qcow2-util-linux-cde7699c27ff22bed8d554d50e10a42ec0dba6d8.tar.gz
kernel-qcow2-util-linux-cde7699c27ff22bed8d554d50e10a42ec0dba6d8.tar.xz
kernel-qcow2-util-linux-cde7699c27ff22bed8d554d50e10a42ec0dba6d8.zip
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 <werner@suse.de>
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;