Ash + telnetd: telnet client hangs after exit
Ralf Friedl
Ralf.Friedl at online.de
Mon Nov 5 11:55:55 UTC 2007
Hi
I found some more problems with the current telnetd code (I'm sorry that
I didn't notice them earlier).
The bigger problem is that without the option -K, telnetd will never
wait for its children, leaving them as zombies.
A minor problem is that it is possible, although unlikely, that two
children exit at the same time. Or more exactly, it is possible that one
child exits, which raises SIGCHLD for telnetd. If another child exits
after the first, but before the signal was delivered, the signal handler
will be called only once, not twice for the two children.
If the system is heavy loaded, maybe parts of telnetd paged out, this
time may be log enough for this to happen.
It is unlikely to happen with telnetd, but I already had this problem
with a mail server in real life. The solution is to loop in the signal
handler until wait finds no more children.
I also changed the argument to waitpid from &sig to NULL because "man
waitpid" says: "If status is not NULL, wait or waitpid store ...",
because the status is not used.
Regards
Ralf Friedl
--- networking/telnetd.c
+++ networking/telnetd.c
@@ -384,13 +384,17 @@
pid_t pid;
struct tsession *ts;
- pid = waitpid(-1, &sig, WNOHANG);
- if (pid > 0) {
+ for (;;) {
+ pid = waitpid(-1, NULL, WNOHANG);
+ if (pid <= 0)
+ break;
+ if (!(option_mask32 & OPT_WATCHCHILD))
+ continue;
ts = sessions;
while (ts) {
if (ts->shell_pid == pid) {
ts->shell_pid = -1;
- return;
+ break;
}
ts = ts->next;
}
@@ -464,8 +468,7 @@
/* We don't want to die if just one session is broken */
signal(SIGPIPE, SIG_IGN);
- if (opt & OPT_WATCHCHILD)
- signal(SIGCHLD, handle_sigchld);
+ signal(SIGCHLD, handle_sigchld);
/*
This is how the buffers are used. The arrows indicate the movement
More information about the busybox
mailing list