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>
This commit is contained in:
Denys Vlasenko 2009-09-04 02:21:13 +02:00
parent cfc216345e
commit ed1667e8ee
3 changed files with 69 additions and 28 deletions

View File

@ -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.

View File

@ -788,6 +788,27 @@ config FEATURE_TELNETD_STANDALONE
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

View File

@ -211,8 +211,10 @@ static size_t iac_safe_write(int fd, const char *buf, size_t count)
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 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
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 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
}
}
/* 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 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
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 */