aboutsummaryrefslogtreecommitdiff
path: root/init/init.c
diff options
context:
space:
mode:
authorWilly Tarreau <w@1wt.eu>2007-09-25 23:09:18 +0200
committerWilly Tarreau <w@1wt.eu>2007-09-25 23:09:18 +0200
commitf490b1e587ee4efe721fbe1dfa3d16e4347dadb7 (patch)
tree0c399a2bee417dee322d6cd4fb03f6e5fe347503 /init/init.c
parent[RELEASE] flxutils-0.1.30 (diff)
downloadflxutils-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.c45
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;
}
+