svn commit: trunk/busybox: include networking
vda at busybox.net
vda at busybox.net
Mon Oct 15 22:09:16 UTC 2007
Author: vda
Date: 2007-10-15 15:09:15 -0700 (Mon, 15 Oct 2007)
New Revision: 20262
Log:
telnetd: at Alexander Kriegisch <Alexander at kriegisch.name> insistence
add an option to close sessions as soon as child exits.
Maybe it should be a CONFIG option. OTOH, maybe it should be always on,
as it mimics, say, getty's behaviour.
function old new delta
handle_sigchld - 49 +49
telnetd_main 1312 1355 +43
.rodata 123429 123466 +37
packed_usage 22770 22806 +36
make_new_session 525 532 +7
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 4/0 up/down: 172/0) Total: 172 bytes
text data bss dec hex filename
676285 2538 12104 690927 a8aef busybox_old
676421 2538 12104 691063 a8b77 busybox_unstripped
Modified:
trunk/busybox/include/usage.h
trunk/busybox/networking/telnetd.c
Changeset:
Modified: trunk/busybox/include/usage.h
===================================================================
--- trunk/busybox/include/usage.h 2007-10-15 17:28:00 UTC (rev 20261)
+++ trunk/busybox/include/usage.h 2007-10-15 22:09:15 UTC (rev 20262)
@@ -3517,6 +3517,8 @@
"\n\nOptions:" \
"\n -l LOGIN Exec LOGIN on connect" \
"\n -f issue_file Display issue_file instead of /etc/issue" \
+ "\n -K Close connection as soon as login exits" \
+ "\n (normally wait until all programs close slave pty)" \
USE_FEATURE_TELNETD_STANDALONE( \
"\n -p PORT Port to listen to" \
"\n -b ADDR Address to bind to" \
Modified: trunk/busybox/networking/telnetd.c
===================================================================
--- trunk/busybox/networking/telnetd.c 2007-10-15 17:28:00 UTC (rev 20261)
+++ trunk/busybox/networking/telnetd.c 2007-10-15 22:09:15 UTC (rev 20262)
@@ -37,7 +37,7 @@
struct tsession {
struct tsession *next;
int sockfd_read, sockfd_write, ptyfd;
- /*int shell_pid;*/
+ int shell_pid;
/* two circular buffers */
/*char *buf1, *buf2;*/
@@ -265,7 +265,7 @@
}
if (pid > 0) {
/* Parent */
- /*ts->shell_pid = pid;*/
+ ts->shell_pid = pid;
return ts;
}
@@ -305,7 +305,8 @@
login_argv[0] = loginpath;
login_argv[1] = NULL;
execvp(loginpath, (char **)login_argv);
- /* Safer with vfork, and we shouldn't send this to the client anyway */
+ /* Safer with vfork, and we shouldn't send message
+ * to remote clients anyway */
_exit(1); /*bb_perror_msg_and_die("execv %s", loginpath);*/
}
@@ -357,7 +358,25 @@
#endif
+static void handle_sigchld(int sig)
+{
+ pid_t pid;
+ struct tsession *ts;
+ pid = waitpid(-1, &sig, WNOHANG);
+ if (pid > 0) {
+ ts = sessions;
+ while (ts) {
+ if (ts->shell_pid == pid) {
+ ts->shell_pid = -1;
+ return;
+ }
+ ts = ts->next;
+ }
+ }
+}
+
+
int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int telnetd_main(int argc, char **argv)
{
@@ -379,29 +398,35 @@
};
#endif
enum {
- OPT_INETD = (1 << 2) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
- OPT_PORT = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */
- OPT_FOREGROUND = (1 << 5) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
+ OPT_WATCHCHILD = (1 << 2), /* -K */
+ OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
+ OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */
+ OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
};
- /* If !STANDALONE, we accept (and ignore) -i, thus people
+ /* Even if !STANDALONE, we accept (and ignore) -i, thus people
* don't need to guess whether it's ok to pass -i to us */
- opt = getopt32(argv, "f:l:i" USE_FEATURE_TELNETD_STANDALONE("p:b:F"),
+ opt = getopt32(argv, "f:l:Ki" USE_FEATURE_TELNETD_STANDALONE("p:b:F"),
&issuefile, &loginpath
USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr));
+ if (!IS_INETD /*&& !re_execed*/) {
+ /* inform that we start in standalone mode?
+ * May be useful when people forget to give -i */
+ /*bb_error_msg("listening for connections");*/
+ if (!(opt & OPT_FOREGROUND)) {
+ /* DAEMON_CHDIR_ROOT was giving inconsistent
+ * behavior with/wthout -F, -i */
+ bb_daemonize_or_rexec(0 /*DAEMON_CHDIR_ROOT*/, argv);
+ }
+ }
/* Redirect log to syslog early, if needed */
if (IS_INETD || !(opt & OPT_FOREGROUND)) {
openlog(applet_name, 0, LOG_USER);
logmode = LOGMODE_SYSLOG;
}
- //if (opt & 1) // -f
- //if (opt & 2) // -l
USE_FEATURE_TELNETD_STANDALONE(
- if (opt & OPT_PORT) // -p
+ if (opt & OPT_PORT)
portnbr = xatou16(opt_portnbr);
- //if (opt & 8) // -b
- //if (opt & 0x10) // -F
- //if (opt & 0x20) // -i
);
/* Used to check access(loginpath, X_OK) here. Pointless.
@@ -413,12 +438,8 @@
if (!sessions) /* pty opening or vfork problem, exit */
return 1; /* make_new_session prints error message */
} else {
-//vda: inform that we start in standalone mode?
master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
xlisten(master_fd, 1);
- if (!(opt & OPT_FOREGROUND))
-//vda: NOMMU?
- bb_daemonize(DAEMON_CHDIR_ROOT);
}
#else
sessions = make_new_session();
@@ -429,6 +450,9 @@
/* We don't want to die if just one session is broken */
signal(SIGPIPE, SIG_IGN);
+ if (opt & OPT_WATCHCHILD)
+ signal(SIGCHLD, handle_sigchld);
+
/*
This is how the buffers are used. The arrows indicate the movement
of data.
@@ -450,14 +474,6 @@
again:
FD_ZERO(&rdfdset);
FD_ZERO(&wrfdset);
- if (!IS_INETD) {
- FD_SET(master_fd, &rdfdset);
- /* This is needed because free_session() does not
- * take into account master_fd when it finds new
- * maxfd among remaining fd's: */
- if (master_fd > maxfd)
- maxfd = master_fd;
- }
/* Select on the master socket, all telnet sockets and their
* ptys if there is room in their session buffers.
@@ -465,16 +481,29 @@
* before each select. Can be a problem with 500+ connections. */
ts = sessions;
while (ts) {
- if (ts->size1 > 0) /* can write to pty */
- FD_SET(ts->ptyfd, &wrfdset);
- if (ts->size1 < BUFSIZE) /* can read from socket */
- FD_SET(ts->sockfd_read, &rdfdset);
- if (ts->size2 > 0) /* can write to socket */
- FD_SET(ts->sockfd_write, &wrfdset);
- if (ts->size2 < BUFSIZE) /* can read from pty */
- FD_SET(ts->ptyfd, &rdfdset);
- ts = ts->next;
+ struct tsession *next = ts->next; /* in case we free ts. */
+ if (ts->shell_pid == -1) {
+ free_session(ts);
+ } else {
+ if (ts->size1 > 0) /* can write to pty */
+ FD_SET(ts->ptyfd, &wrfdset);
+ if (ts->size1 < BUFSIZE) /* can read from socket */
+ FD_SET(ts->sockfd_read, &rdfdset);
+ if (ts->size2 > 0) /* can write to socket */
+ FD_SET(ts->sockfd_write, &wrfdset);
+ if (ts->size2 < BUFSIZE) /* can read from pty */
+ FD_SET(ts->ptyfd, &rdfdset);
+ }
+ ts = next;
}
+ if (!IS_INETD) {
+ FD_SET(master_fd, &rdfdset);
+ /* This is needed because free_session() does not
+ * take into account master_fd when it finds new
+ * maxfd among remaining fd's */
+ if (master_fd > maxfd)
+ maxfd = master_fd;
+ }
count = select(maxfd + 1, &rdfdset, &wrfdset, NULL, NULL);
if (count < 0)
More information about the busybox-cvs
mailing list