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