telnetd: add -w ("inetd wait") option. Can  be configured off.

gcc fils to fully optimize it out when it's off:

function                                             old     new   delta
telnetd_main                                        1527    1548     +21
packed_usage                                       26596   26587      -9

but nevertheless it's a useful (and so far single) example
how to write "inetd wait" tcp service.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/include/usage.h b/include/usage.h
index ba77490..9fa1b9e 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -1468,11 +1468,11 @@
      "\n	-m		Get baud rate from modem's CONNECT status message" \
      "\n	-w		Wait for a CR or LF before sending /etc/issue" \
      "\n	-n		Do not prompt the user for a login name" \
-     "\n	-f issue_file	Display issue_file instead of /etc/issue" \
-     "\n	-l login_app	Invoke login_app instead of /bin/login" \
-     "\n	-t timeout	Terminate after timeout if no username is read" \
-     "\n	-I initstring	Init string to send before anything else" \
-     "\n	-H login_host	Log login_host into the utmp file as the hostname" \
+     "\n	-f ISSUE_FILE	Display ISSUE_FILE instead of /etc/issue" \
+     "\n	-l LOGIN	Invoke LOGIN instead of /bin/login" \
+     "\n	-t SEC		Terminate after SEC if no username is read" \
+     "\n	-I INITSTR	Send INITSTR before anything else" \
+     "\n	-H HOST		Log HOST into the utmp file as the hostname" \
 
 #define grep_trivial_usage \
        "[-HhrilLnqvso" \
@@ -4415,14 +4415,18 @@
 	IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" \
      "\nOptions:" \
      "\n	-l LOGIN	Exec LOGIN on connect" \
-     "\n	-f issue_file	Display issue_file instead of /etc/issue" \
+     "\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)" \
 	IF_FEATURE_TELNETD_STANDALONE( \
      "\n	-p PORT		Port to listen on" \
-     "\n	-b ADDR		Address to bind to" \
+     "\n	-b ADDR[:PORT]	Address to bind to" \
      "\n	-F		Run in foreground" \
-     "\n	-i		Run as inetd subservice" \
+     "\n	-i		Run as inetd service" \
+	IF_FEATURE_TELNETD_INETD_WAIT( \
+     "\n	-w SEC		Run as inetd service in wait mode, linger time SEC" \
+     "\n	-S		Log to syslog (implied by -i or without -F and -w)" \
+	) \
 	)
 
 /* "test --help" does not print help (POSIX compat), only "[ --help" does.
diff --git a/networking/Config.in b/networking/Config.in
index 83522ff..59e88e0 100644
--- a/networking/Config.in
+++ b/networking/Config.in
@@ -788,6 +788,27 @@
 	help
 	  Selecting this will make telnetd able to run standalone.
 
+config FEATURE_TELNETD_INETD_WAIT
+	bool "Support -w SEC option (inetd wait mode)"
+	default n
+	depends on FEATURE_TELNETD_STANDALONE
+	help
+	  This option allows you to run telnetd in "inet wait" mode.
+	  Example inetd.conf line (note "wait", not usual "nowait"):
+
+	  telnet stream tcp wait root /bin/telnetd telnetd -w10
+
+	  In this example, inetd passes _listening_ socket_ as fd 0
+	  to telnetd when connection appears.
+	  telnetd will wait for connections until all existing
+	  connections are closed, and no new connections
+	  appear during 10 seconds. Then it exits, and inetd continues
+	  to listen for new connections.
+
+	  This option is rarely used. "tcp nowait" is much more usual
+	  way of running tcp services, including telnetd.
+	  You most probably want to say N here.
+
 config TFTP
 	bool "tftp"
 	default n
diff --git a/networking/telnetd.c b/networking/telnetd.c
index 540387f..2a0ace5 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -211,8 +211,10 @@
 enum {
 	OPT_WATCHCHILD = (1 << 2), /* -K */
 	OPT_INETD      = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
-	OPT_PORT       = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */
+	OPT_PORT       = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p PORT */
 	OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
+	OPT_SYSLOG     = (1 << 7) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -S */
+	OPT_WAIT       = (1 << 8) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -w SEC */
 };
 
 static struct tsession *
@@ -438,24 +440,29 @@
 	struct tsession *ts;
 #if ENABLE_FEATURE_TELNETD_STANDALONE
 #define IS_INETD (opt & OPT_INETD)
-	int master_fd = master_fd; /* be happy, gcc */
-	unsigned portnbr = 23;
+	int master_fd = master_fd; /* for compiler */
+	int sec_linger = sec_linger;
 	char *opt_bindaddr = NULL;
 	char *opt_portnbr;
 #else
 	enum {
 		IS_INETD = 1,
 		master_fd = -1,
-		portnbr = 23,
 	};
 #endif
 	INIT_G();
 
+	/* -w NUM, and implies -F. -w and -i don't mix */
+	IF_FEATURE_TELNETD_INETD_WAIT(opt_complementary = "wF:w+:i--w:w--i";)
 	/* 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:Ki" IF_FEATURE_TELNETD_STANDALONE("p:b:F"),
+	opt = getopt32(argv, "f:l:Ki"
+			IF_FEATURE_TELNETD_STANDALONE("p:b:F")
+			IF_FEATURE_TELNETD_INETD_WAIT("Sw:"),
 			&G.issuefile, &G.loginpath
-			IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr));
+			IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr)
+			IF_FEATURE_TELNETD_INETD_WAIT(, &sec_linger)
+	);
 	if (!IS_INETD /*&& !re_execed*/) {
 		/* inform that we start in standalone mode?
 		 * May be useful when people forget to give -i */
@@ -467,32 +474,30 @@
 		}
 	}
 	/* Redirect log to syslog early, if needed */
-	if (IS_INETD || !(opt & OPT_FOREGROUND)) {
+	if (IS_INETD || (opt & OPT_SYSLOG) || !(opt & OPT_FOREGROUND)) {
 		openlog(applet_name, LOG_PID, LOG_DAEMON);
 		logmode = LOGMODE_SYSLOG;
 	}
-	IF_FEATURE_TELNETD_STANDALONE(
-		if (opt & OPT_PORT)
-			portnbr = xatou16(opt_portnbr);
-	);
-
-	/* Used to check access(G.loginpath, X_OK) here. Pointless.
-	 * exec will do this for us for free later. */
-
 #if ENABLE_FEATURE_TELNETD_STANDALONE
 	if (IS_INETD) {
 		G.sessions = make_new_session(0);
 		if (!G.sessions) /* pty opening or vfork problem, exit */
-			return 1; /* make_new_session prints error message */
+			return 1; /* make_new_session printed error message */
 	} else {
-		master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
-		xlisten(master_fd, 1);
+		master_fd = 0;
+		if (!(opt & OPT_WAIT)) {
+			unsigned portnbr = 23;
+			if (opt & OPT_PORT)
+				portnbr = xatou16(opt_portnbr);
+			master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
+			xlisten(master_fd, 1);
+		}
 		close_on_exec_on(master_fd);
 	}
 #else
 	G.sessions = make_new_session();
 	if (!G.sessions) /* pty opening or vfork problem, exit */
-		return 1; /* make_new_session prints error message */
+		return 1; /* make_new_session printed error message */
 #endif
 
 	/* We don't want to die if just one session is broken */
@@ -556,7 +561,18 @@
 			G.maxfd = master_fd;
 	}
 
-	count = select(G.maxfd + 1, &rdfdset, &wrfdset, NULL, NULL);
+	{
+		struct timeval tv;
+		struct timeval *tv_ptr = NULL;
+		if ((opt & OPT_WAIT) && !G.sessions) {
+			tv.tv_sec = sec_linger;
+			tv.tv_usec = 0;
+			tv_ptr = &tv;
+		}
+		count = select(G.maxfd + 1, &rdfdset, &wrfdset, NULL, tv_ptr);
+	}
+	if (count == 0) /* "telnetd -w SEC" timed out */
+		return 0;
 	if (count < 0)
 		goto again; /* EINTR or ENOMEM */