}
}
- num_totty = totty - ptr0;
+ num_totty = totty - ptr0;
*pnum_totty = num_totty;
/* the difference between ptr and totty is number of iacs
we removed from the stream. Adjust buf1 accordingly. */
static struct tsession *
make_new_session(
- USE_FEATURE_TELNETD_STANDALONE(int sock_r, int sock_w)
+ USE_FEATURE_TELNETD_STANDALONE(int sock)
SKIP_FEATURE_TELNETD_STANDALONE(void)
) {
const char *login_argv[2];
bb_error_msg("can't create pty");
return NULL;
}
- if (fd > maxfd) maxfd = fd;
+ if (fd > maxfd)
+ maxfd = fd;
ts->ptyfd = fd;
ndelay_on(fd);
#if ENABLE_FEATURE_TELNETD_STANDALONE
- if (sock_w > maxfd) maxfd = sock_w;
- ts->sockfd_write = sock_w;
- ndelay_on(sock_w);
- if (sock_r > maxfd) maxfd = sock_r;
- ts->sockfd_read = sock_r;
- ndelay_on(sock_r);
+ ts->sockfd_read = sock;
+ ndelay_on(sock);
+ if (!sock) { /* We are called with fd 0 - we are in inetd mode */
+ sock++; /* so use fd 1 for output */
+ ndelay_on(sock);
+ }
+ ts->sockfd_write = sock;
+ if (sock > maxfd)
+ maxfd = sock;
#else
- ts->sockfd_write = 1;
/* ts->sockfd_read = 0; - done by xzalloc */
+ ts->sockfd_write = 1;
ndelay_on(0);
ndelay_on(1);
#endif
if (pid < 0) {
free(ts);
close(fd);
- /* sock_r and sock_w will be closed by caller */
+ /* sock will be closed by caller */
bb_perror_msg("vfork");
return NULL;
}
_exit(1); /*bb_perror_msg_and_die("execv %s", loginpath);*/
}
+/* Must match getopt32 string */
+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_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
+};
+
#if ENABLE_FEATURE_TELNETD_STANDALONE
static void
{
struct tsession *t = sessions;
+ if (option_mask32 & OPT_INETD)
+ exit(0);
+
/* Unlink this telnet session from the session list */
if (t == ts)
sessions = ts->next;
t->next = ts->next;
}
+#if 0
/* It was said that "normal" telnetd just closes ptyfd,
* doesn't send SIGKILL. When we close ptyfd,
* kernel sends SIGHUP to processes having slave side opened. */
- /*kill(ts->shell_pid, SIGKILL);
- wait4(ts->shell_pid, NULL, 0, NULL);*/
+ kill(ts->shell_pid, SIGKILL);
+ wait4(ts->shell_pid, NULL, 0, NULL);
+#endif
close(ts->ptyfd);
close(ts->sockfd_read);
- /* error if ts->sockfd_read == ts->sockfd_write. So what? ;) */
- close(ts->sockfd_write);
+ /* We do not need to close(ts->sockfd_write), it's the same
+ * as sockfd_read unless we are in inetd mode. But in inetd mode
+ * we do not reach this */
free(ts);
/* Scan all sessions and find new maxfd */
- ts = sessions;
maxfd = 0;
+ ts = sessions;
while (ts) {
if (maxfd < ts->ptyfd)
maxfd = ts->ptyfd;
if (maxfd < ts->sockfd_read)
maxfd = ts->sockfd_read;
+#if 0
+ /* Again, sockfd_write == sockfd_read here */
if (maxfd < ts->sockfd_write)
maxfd = ts->sockfd_write;
+#endif
ts = ts->next;
}
}
#else /* !FEATURE_TELNETD_STANDALONE */
-/* Never actually called */
-void free_session(struct tsession *ts);
+/* Used in main() only, thus exits. */
+#define free_session(ts) return 0
#endif
portnbr = 23,
};
#endif
- 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_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
- };
-
/* 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" USE_FEATURE_TELNETD_STANDALONE("p:b:F"),
/*bb_error_msg("listening for connections");*/
if (!(opt & OPT_FOREGROUND)) {
/* DAEMON_CHDIR_ROOT was giving inconsistent
- * behavior with/wthout -F, -i */
+ * behavior with/without -F, -i */
bb_daemonize_or_rexec(0 /*DAEMON_CHDIR_ROOT*/, argv);
}
}
#if ENABLE_FEATURE_TELNETD_STANDALONE
if (IS_INETD) {
- sessions = make_new_session(0, 1);
+ sessions = make_new_session(0);
if (!sessions) /* pty opening or vfork problem, exit */
return 1; /* make_new_session prints error message */
} else {
while (ts) {
struct tsession *next = ts->next; /* in case we free ts. */
if (ts->shell_pid == -1) {
+ /* Child died ad we detected that */
free_session(ts);
} else {
if (ts->size1 > 0) /* can write to pty */
if (fd < 0)
goto again;
/* Create a new session and link it into our active list */
- new_ts = make_new_session(fd, fd);
+ new_ts = make_new_session(fd);
if (new_ts) {
new_ts->next = sessions;
sessions = new_ts;
if (count < 0) {
if (errno == EAGAIN)
goto skip1;
- if (IS_INETD)
- return 0;
- free_session(ts);
- ts = next;
- continue;
+ goto kill_session;
}
ts->size1 -= count;
ts->wridx1 += count;
if (count < 0) {
if (errno == EAGAIN)
goto skip2;
- if (IS_INETD)
- return 0;
- free_session(ts);
- ts = next;
- continue;
+ goto kill_session;
}
ts->size2 -= count;
ts->wridx2 += count;
/* Should not be needed, but... remove_iacs is actually buggy
* (it cannot process iacs which wrap around buffer's end)!
* Since properly fixing it requires writing bigger code,
- * we will rely instead on this code making it virtually impossible
+ * we rely instead on this code making it virtually impossible
* to have wrapped iac (people don't type at 2k/second).
* It also allows for bigger reads in common case. */
if (ts->size1 == 0) {
if (count <= 0) {
if (count < 0 && errno == EAGAIN)
goto skip3;
- if (IS_INETD)
- return 0;
- free_session(ts);
- ts = next;
- continue;
+ goto kill_session;
}
/* Ignore trailing NUL if it is there */
if (!TS_BUF1[ts->rdidx1 + count - 1]) {
- if (!--count)
- goto skip3;
+ --count;
}
ts->size1 += count;
ts->rdidx1 += count;
if (count <= 0) {
if (count < 0 && errno == EAGAIN)
goto skip4;
- if (IS_INETD)
- return 0;
- free_session(ts);
- ts = next;
- continue;
+ goto kill_session;
}
ts->size2 += count;
ts->rdidx2 += count;
}
skip4:
ts = next;
+ continue;
+ kill_session:
+ free_session(ts);
+ ts = next;
}
+
goto again;
}