diff options
author | Willy Tarreau <w@1wt.eu> | 2007-09-25 23:09:18 +0200 |
---|---|---|
committer | Willy Tarreau <w@1wt.eu> | 2007-09-25 23:09:18 +0200 |
commit | f490b1e587ee4efe721fbe1dfa3d16e4347dadb7 (patch) | |
tree | 0c399a2bee417dee322d6cd4fb03f6e5fe347503 /init/init.c | |
parent | [RELEASE] flxutils-0.1.30 (diff) | |
download | flxutils-f490b1e587ee4efe721fbe1dfa3d16e4347dadb7.tar.xz |
init: fix controlling tty for execve()
The forked processes used to set up a controlling tty. But this
did not properly work because they had to switch from a different
session than the parent's, leading to lots of output being lost
when the process exited and the session terminated. The solution
was to use 2 processes, one to perform the work, and the other
one to maintain the session the time needed for the chars to
reach the tty.
Diffstat (limited to 'init/init.c')
-rw-r--r-- | init/init.c | 45 |
1 files changed, 40 insertions, 5 deletions
diff --git a/init/init.c b/init/init.c index e8a0662..a9874ac 100644 --- a/init/init.c +++ b/init/init.c @@ -1711,20 +1711,54 @@ int main(int argc, char **argv, char **envp) { res = fork(); if (res == 0) { char **exec_args; - + /* OK, here's the problem : + * PID 1 has its own session ID 0, and we cannot change it. + * It cannot either set controlling TTYs and such. So we have + * to create a new session. But data written from another session + * does get flushed when the session is closed. To solve this + * problem, we have to create 2 processes for each fork(), one + * to do the real work, and the other one to maintain the session + * open, and to wait for the flush (nearly immediate). + */ setsid(); + setpgrp(); + tcsetpgrp(0, getpgrp()); ioctl(0, TIOCSCTTY, 1); // become the controlling tty, allow Ctrl-C exec_args = cfg_args + 1; if (token == TOK_RX) { chroot(*exec_args); + /* FIXME: no chdir("/") ??? */ exec_args++; } - /* FIXME: no chdir("/") ??? */ - execve(exec_args[0], exec_args, envp); - print("<E>xec(child) : execve() failed\n"); - return 1; + res = fork(); + if (res == 0) { + execve(exec_args[0], exec_args, envp); + print("<E>xec(child) : execve() failed\n"); + //printf("after execve(%s)!\n", exec_args[0]); + exit(1); + } + else if (res > 0) { + int ret, rem; + int status; + + ret = waitpid(res, &status, 0); + //printf("waitpid returned %d,0x%08x\n", ret, status); + + /* wait for the stdout queue to flush */ + while (1) { + if (ioctl(0, TIOCOUTQ, &rem) < 0) + break; + if (rem == 0) + break; + sched_yield(); + } + + exit(((ret == -1) || !WIFEXITED(status)) ? + 1 : WEXITSTATUS(status)); + } + exit(1); } else if (res > 0) { int ret; @@ -1947,3 +1981,4 @@ int main(int argc, char **argv, char **envp) { } return 0; } + |