nc: remove a bit of bloat

inetd: more NOMMU fixes
rx: shrink
devfsd: minor shrink
vlock: shrink
tcpudp: narrow down window where we have no wildcard socket

parse_one_line                                      1015    1102     +87
init_ring                                              -      53     +53
xzalloc_lsa                                            -      48     +48
read_byte                                             51      50      -1
rearm_alarm                                           28      25      -3
nc_main                                             1028    1000     -28
initring                                              53       -     -53
vlock_main                                           583     496     -87
reread_config_file                                  1089     991     -98
rx_main                                             1046     912    -134
------------------------------------------------------------------------------
(add/remove: 2/1 grow/shrink: 1/6 up/down: 188/-404)         Total: -216 bytes
   text    data     bss     dec     hex filename
 800120     661    7428  808209   c5511 busybox_old
 799796     661    7428  807885   c53cd busybox_unstripped
This commit is contained in:
Denis Vlasenko 2008-03-12 23:13:50 +00:00
parent 4e6d5117b8
commit 4cf1d08fc2
7 changed files with 302 additions and 295 deletions

View File

@ -339,16 +339,17 @@ int tcpudpsvd_main(int argc, char **argv)
* 1) we have to do it before fork() * 1) we have to do it before fork()
* 2) order is important - is it right now? */ * 2) order is important - is it right now? */
/* Make plain write/send work for this socket by supplying default /* Open new non-connected UDP socket for further clients... */
sock = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0);
setsockopt_reuseaddr(sock);
/* Make plain write/send work for old socket by supplying default
* destination address. This also restricts incoming packets * destination address. This also restricts incoming packets
* to ones coming from this remote IP. */ * to ones coming from this remote IP. */
xconnect(0, &remote.u.sa, sa_len); xconnect(0, &remote.u.sa, sa_len);
/* hole? at this point we have no wildcard udp socket... /* hole? at this point we have no wildcard udp socket...
* can this cause clients to get "port unreachable" icmp? * can this cause clients to get "port unreachable" icmp?
* Yup, time window is very small, but it exists (is it?) */ * Yup, time window is very small, but it exists (is it?) */
/* Open new non-connected UDP socket for further clients */ /* ..."open new socket", continued */
sock = xsocket(lsa->u.sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
setsockopt_reuseaddr(sock);
xbind(sock, &lsa->u.sa, sa_len); xbind(sock, &lsa->u.sa, sa_len);
socket_want_pktinfo(sock); socket_want_pktinfo(sock);
@ -377,7 +378,6 @@ int tcpudpsvd_main(int argc, char **argv)
goto again; goto again;
} }
if (pid != 0) { if (pid != 0) {
/* parent */ /* parent */
cnum++; cnum++;
@ -467,7 +467,7 @@ int tcpudpsvd_main(int argc, char **argv)
argv += 2; argv += 2;
#ifdef SSLSVD #ifdef SSLSVD
strcpy(id, utoa(pid); strcpy(id, utoa(pid));
ssl_io(0, argv); ssl_io(0, argv);
#else #else
BB_EXECVP(argv[0], argv); BB_EXECVP(argv[0], argv);

View File

@ -82,13 +82,8 @@ void sig_pause(void)
/* Assuming the sig is fatal */ /* Assuming the sig is fatal */
void kill_myself_with_sig(int sig) void kill_myself_with_sig(int sig)
{ {
sigset_t set;
signal(sig, SIG_DFL); signal(sig, SIG_DFL);
sig_unblock(sig);
sigemptyset(&set);
sigaddset(&set, sig);
sigprocmask(SIG_UNBLOCK, &set, NULL);
raise(sig); raise(sig);
_exit(1); /* Should not reach it */ _exit(1); /* Should not reach it */
} }

View File

@ -1,5 +1,4 @@
/* vi: set sw=4 ts=4: */ /* vi: set sw=4 ts=4: */
/* /*
* vlock implementation for busybox * vlock implementation for busybox
* *
@ -16,27 +15,25 @@
/* Fixed by Erik Andersen to do passwords the tinylogin way... /* Fixed by Erik Andersen to do passwords the tinylogin way...
* It now works with md5, sha1, etc passwords. */ * It now works with md5, sha1, etc passwords. */
#include "libbb.h"
#include <sys/vt.h> #include <sys/vt.h>
#include "libbb.h"
enum { vfd = 3 };
/* static unsigned long o_lock_all; */
static void release_vt(int signo) static void release_vt(int signo)
{ {
ioctl(vfd, VT_RELDISP, (unsigned long) !option_mask32 /*!o_lock_all*/); /* If -a, param is 0, which means:
* "no, kernel, we don't allow console switch away from us!" */
ioctl(STDIN_FILENO, VT_RELDISP, (unsigned long) !option_mask32);
} }
static void acquire_vt(int signo) static void acquire_vt(int signo)
{ {
ioctl(vfd, VT_RELDISP, VT_ACKACQ); /* ACK to kernel that switch to console is successful */
ioctl(STDIN_FILENO, VT_RELDISP, VT_ACKACQ);
} }
int vlock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int vlock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int vlock_main(int argc, char **argv) int vlock_main(int argc, char **argv)
{ {
sigset_t sig;
struct sigaction sa; struct sigaction sa;
struct vt_mode vtm; struct vt_mode vtm;
struct termios term; struct termios term;
@ -48,49 +45,48 @@ int vlock_main(int argc, char **argv)
uid = getuid(); uid = getuid();
pw = getpwuid(uid); pw = getpwuid(uid);
if (pw == NULL) if (pw == NULL)
bb_error_msg_and_die("unknown uid %d", uid); bb_error_msg_and_die("unknown uid %d", (int)uid);
if (argc > 2) { opt_complementary = "=0"; /* no params! */
bb_show_usage(); getopt32(argv, "a");
}
/*o_lock_all = */getopt32(argv, "a"); /* Ignore some signals so that we don't get killed by them */
bb_signals(0
+ (1 << SIGTSTP)
+ (1 << SIGTTIN)
+ (1 << SIGTTOU)
+ (1 << SIGHUP )
+ (1 << SIGCHLD) /* paranoia :) */
+ (1 << SIGQUIT)
+ (1 << SIGINT )
, SIG_IGN);
/* Avoid using statics - use constant fd */ /* We will use SIGUSRx for console switch control: */
xmove_fd(xopen(CURRENT_TTY, O_RDWR), vfd); /* 1: set handlers */
xioctl(vfd, VT_GETMODE, &vtm); sigemptyset(&sa.sa_mask);
/* mask a bunch of signals */
sigprocmask(SIG_SETMASK, NULL, &sig);
sigdelset(&sig, SIGUSR1);
sigdelset(&sig, SIGUSR2);
sigaddset(&sig, SIGTSTP);
sigaddset(&sig, SIGTTIN);
sigaddset(&sig, SIGTTOU);
sigaddset(&sig, SIGHUP);
sigaddset(&sig, SIGCHLD);
sigaddset(&sig, SIGQUIT);
sigaddset(&sig, SIGINT);
sigemptyset(&(sa.sa_mask));
sa.sa_flags = SA_RESTART; sa.sa_flags = SA_RESTART;
sa.sa_handler = release_vt; sa.sa_handler = release_vt;
sigaction(SIGUSR1, &sa, NULL); sigaction(SIGUSR1, &sa, NULL);
sa.sa_handler = acquire_vt; sa.sa_handler = acquire_vt;
sigaction(SIGUSR2, &sa, NULL); sigaction(SIGUSR2, &sa, NULL);
/* 2: unmask them */
sigprocmask(SIG_SETMASK, NULL, &sa.sa_mask);
sigdelset(&sa.sa_mask, SIGUSR1);
sigdelset(&sa.sa_mask, SIGUSR2);
sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL);
/* need to handle some signals so that we don't get killed by them */ /* Revert stdin/out to our controlling tty
sa.sa_handler = SIG_IGN; * (or die if we have none) */
sigaction(SIGHUP, &sa, NULL); xmove_fd(xopen(CURRENT_TTY, O_RDWR), STDIN_FILENO);
sigaction(SIGQUIT, &sa, NULL); xdup2(STDIN_FILENO, STDOUT_FILENO);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTSTP, &sa, NULL);
xioctl(STDIN_FILENO, VT_GETMODE, &vtm);
ovtm = vtm; ovtm = vtm;
/* "console switches are controlled by us, not kernel!" */
vtm.mode = VT_PROCESS; vtm.mode = VT_PROCESS;
vtm.relsig = SIGUSR1; vtm.relsig = SIGUSR1;
vtm.acqsig = SIGUSR2; vtm.acqsig = SIGUSR2;
ioctl(vfd, VT_SETMODE, &vtm); ioctl(STDIN_FILENO, VT_SETMODE, &vtm);
tcgetattr(STDIN_FILENO, &oterm); tcgetattr(STDIN_FILENO, &oterm);
term = oterm; term = oterm;
@ -111,7 +107,7 @@ int vlock_main(int argc, char **argv)
puts("Password incorrect"); puts("Password incorrect");
} while (1); } while (1);
ioctl(vfd, VT_SETMODE, &ovtm); ioctl(STDIN_FILENO, VT_SETMODE, &ovtm);
tcsetattr(STDIN_FILENO, TCSANOW, &oterm); tcsetattr(STDIN_FILENO, TCSANOW, &oterm);
fflush_stdout_and_exit(0); fflush_stdout_and_exit(0);
} }

View File

@ -386,15 +386,14 @@ int devfsd_main(int argc, char **argv)
/* Tell kernel we are special(i.e. we get to see hidden entries) */ /* Tell kernel we are special(i.e. we get to see hidden entries) */
xioctl(fd, DEVFSDIOC_SET_EVENT_MASK, 0); xioctl(fd, DEVFSDIOC_SET_EVENT_MASK, 0);
/* Set up SIGHUP and SIGUSR1 handlers */
sigemptyset(&new_action.sa_mask); sigemptyset(&new_action.sa_mask);
new_action.sa_flags = 0; new_action.sa_flags = 0;
/* Set up SIGHUP and SIGUSR1 handlers */
new_action.sa_handler = signal_handler; new_action.sa_handler = signal_handler;
if (sigaction(SIGHUP, &new_action, NULL) != 0 || sigaction(SIGUSR1, &new_action, NULL) != 0) sigaction(SIGHUP, &new_action, NULL);
bb_error_msg_and_die("sigaction"); sigaction(SIGUSR1, &new_action, NULL);
printf("%s v%s started for %s\n",applet_name, DEVFSD_VERSION, mount_point); printf("%s v%s started for %s\n", applet_name, DEVFSD_VERSION, mount_point);
/* Set umask so that mknod(2), open(2) and mkdir(2) have complete control over permissions */ /* Set umask so that mknod(2), open(2) and mkdir(2) have complete control over permissions */
umask(0); umask(0);

View File

@ -16,7 +16,6 @@
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
* *
* This was originally written for blob and then adapted for busybox. * This was originally written for blob and then adapted for busybox.
*
*/ */
#include "libbb.h" #include "libbb.h"
@ -29,66 +28,59 @@
#define BS 0x08 #define BS 0x08
/* /*
Cf: Cf:
http://www.textfiles.com/apple/xmodem http://www.textfiles.com/apple/xmodem
http://www.phys.washington.edu/~belonis/xmodem/docxmodem.txt http://www.phys.washington.edu/~belonis/xmodem/docxmodem.txt
http://www.phys.washington.edu/~belonis/xmodem/docymodem.txt http://www.phys.washington.edu/~belonis/xmodem/docymodem.txt
http://www.phys.washington.edu/~belonis/xmodem/modmprot.col http://www.phys.washington.edu/~belonis/xmodem/modmprot.col
*/ */
#define TIMEOUT 1 #define TIMEOUT 1
#define TIMEOUT_LONG 10 #define TIMEOUT_LONG 10
#define MAXERRORS 10 #define MAXERRORS 10
static int read_byte(int fd, unsigned timeout) #define read_fd STDIN_FILENO
#define write_fd STDOUT_FILENO
static int read_byte(unsigned timeout)
{ {
char buf[1]; char buf[1];
int n; int n;
alarm(timeout); alarm(timeout);
/* NOT safe_read! We want ALRM to interrupt us */
n = read(fd, &buf, 1); n = read(read_fd, buf, 1);
alarm(0); alarm(0);
if (n == 1) if (n == 1)
return buf[0] & 0xff; return (unsigned char)buf[0];
else return -1;
return -1;
} }
static int receive(char *error_buf, size_t error_buf_size, static int receive(/*int read_fd, */int file_fd)
int ttyfd, int filefd)
{ {
char blockBuf[1024]; unsigned char blockBuf[1024];
unsigned int errors = 0; unsigned errors = 0;
unsigned int wantBlockNo = 1; unsigned wantBlockNo = 1;
unsigned int length = 0; unsigned length = 0;
int docrc = 1; int do_crc = 1;
char nak = 'C'; char nak = 'C';
unsigned int timeout = TIMEOUT_LONG; unsigned timeout = TIMEOUT_LONG;
#define note_error(fmt,args...) \
snprintf(error_buf, error_buf_size, fmt,##args)
/* Flush pending input */ /* Flush pending input */
tcflush(ttyfd, TCIFLUSH); tcflush(read_fd, TCIFLUSH);
/* Ask for CRC; if we get errors, we will go with checksum */ /* Ask for CRC; if we get errors, we will go with checksum */
write(ttyfd, &nak, 1); full_write(write_fd, &nak, 1);
for (;;) { for (;;) {
int blockBegin; int blockBegin;
int blockNo, blockNoOnesCompl; int blockNo, blockNoOnesCompl;
int blockLength; int blockLength;
int cksum = 0; int cksum_crc; /* cksum OR crc */
int crcHi = 0; int expected;
int crcLo = 0; int i,j;
blockBegin = read_byte(ttyfd, timeout); blockBegin = read_byte(timeout);
if (blockBegin < 0) if (blockBegin < 0)
goto timeout; goto timeout;
@ -102,52 +94,47 @@ static int receive(char *error_buf, size_t error_buf_size,
case EOT: case EOT:
nak = ACK; nak = ACK;
write(ttyfd, &nak, 1); full_write(write_fd, &nak, 1);
goto done; return length;
default: default:
goto error; goto error;
} }
/* block no */ /* block no */
blockNo = read_byte(ttyfd, TIMEOUT); blockNo = read_byte(TIMEOUT);
if (blockNo < 0) if (blockNo < 0)
goto timeout; goto timeout;
/* block no one's compliment */ /* block no one's compliment */
blockNoOnesCompl = read_byte(ttyfd, TIMEOUT); blockNoOnesCompl = read_byte(TIMEOUT);
if (blockNoOnesCompl < 0) if (blockNoOnesCompl < 0)
goto timeout; goto timeout;
if (blockNo != (255 - blockNoOnesCompl)) { if (blockNo != (255 - blockNoOnesCompl)) {
note_error("bad block ones compl"); bb_error_msg("bad block ones compl");
goto error; goto error;
} }
blockLength = (blockBegin == SOH) ? 128 : 1024; blockLength = (blockBegin == SOH) ? 128 : 1024;
{ for (i = 0; i < blockLength; i++) {
int i; int cc = read_byte(TIMEOUT);
if (cc < 0)
for (i = 0; i < blockLength; i++) { goto timeout;
int cc = read_byte(ttyfd, TIMEOUT); blockBuf[i] = cc;
if (cc < 0)
goto timeout;
blockBuf[i] = cc;
}
} }
if (docrc) { if (do_crc) {
crcHi = read_byte(ttyfd, TIMEOUT); cksum_crc = read_byte(TIMEOUT);
if (crcHi < 0) if (cksum_crc < 0)
goto timeout; goto timeout;
cksum_crc = (cksum_crc << 8) | read_byte(TIMEOUT);
crcLo = read_byte(ttyfd, TIMEOUT); if (cksum_crc < 0)
if (crcLo < 0)
goto timeout; goto timeout;
} else { } else {
cksum = read_byte(ttyfd, TIMEOUT); cksum_crc = read_byte(TIMEOUT);
if (cksum < 0) if (cksum_crc < 0)
goto timeout; goto timeout;
} }
@ -156,93 +143,74 @@ static int receive(char *error_buf, size_t error_buf_size,
/* this also ignores the initial block 0 which is */ /* this also ignores the initial block 0 which is */
/* meta data. */ /* meta data. */
goto next; goto next;
} else if (blockNo != (wantBlockNo & 0xff)) { }
note_error("unexpected block no, 0x%08x, expecting 0x%08x", blockNo, wantBlockNo); if (blockNo != (wantBlockNo & 0xff)) {
bb_error_msg("unexpected block no, 0x%08x, expecting 0x%08x", blockNo, wantBlockNo);
goto error; goto error;
} }
if (docrc) { expected = 0;
int crc = 0; if (do_crc) {
int i, j;
int expectedCrcHi;
int expectedCrcLo;
for (i = 0; i < blockLength; i++) { for (i = 0; i < blockLength; i++) {
crc = crc ^ (int) blockBuf[i] << 8; expected = expected ^ blockBuf[i] << 8;
for (j = 0; j < 8; j++) for (j = 0; j < 8; j++) {
if (crc & 0x8000) if (expected & 0x8000)
crc = crc << 1 ^ 0x1021; expected = expected << 1 ^ 0x1021;
else else
crc = crc << 1; expected = expected << 1;
} }
expectedCrcHi = (crc >> 8) & 0xff;
expectedCrcLo = crc & 0xff;
if ((crcHi != expectedCrcHi) ||
(crcLo != expectedCrcLo)) {
note_error("crc error, expected 0x%02x 0x%02x, got 0x%02x 0x%02x", expectedCrcHi, expectedCrcLo, crcHi, crcLo);
goto error;
} }
expected &= 0xffff;
} else { } else {
unsigned char expectedCksum = 0;
int i;
for (i = 0; i < blockLength; i++) for (i = 0; i < blockLength; i++)
expectedCksum += blockBuf[i]; expected += blockBuf[i];
expected &= 0xff;
if (cksum != expectedCksum) { }
note_error("checksum error, expected 0x%02x, got 0x%02x", expectedCksum, cksum); if (cksum_crc != expected) {
goto error; bb_error_msg(do_crc ? "crc error, expected 0x%04x, got 0x%04x"
} : "checksum error, expected 0x%02x, got 0x%02x",
expected, cksum_crc);
goto error;
} }
wantBlockNo++; wantBlockNo++;
length += blockLength; length += blockLength;
if (full_write(filefd, blockBuf, blockLength) < 0) { errno = 0;
note_error("write to file failed: %m"); if (full_write(file_fd, blockBuf, blockLength) != blockLength) {
bb_perror_msg("can't write to file");
goto fatal; goto fatal;
} }
next:
next:
errors = 0; errors = 0;
nak = ACK; nak = ACK;
write(ttyfd, &nak, 1); full_write(write_fd, &nak, 1);
continue; continue;
error:
error: timeout:
timeout:
errors++; errors++;
if (errors == MAXERRORS) { if (errors == MAXERRORS) {
/* Abort */ /* Abort */
// if using crc, try again w/o crc /* if were asking for crc, try again w/o crc */
if (nak == 'C') { if (nak == 'C') {
nak = NAK; nak = NAK;
errors = 0; errors = 0;
docrc = 0; do_crc = 0;
goto timeout; goto timeout;
} }
bb_error_msg("too many errors; giving up");
note_error("too many errors; giving up"); fatal:
/* 5 CAN followed by 5 BS. Don't try too hard... */
fatal: safe_write(write_fd, "\030\030\030\030\030\010\010\010\010\010", 10);
/* 5 CAN followed by 5 BS */
write(ttyfd, "\030\030\030\030\030\010\010\010\010\010", 10);
return -1; return -1;
} }
/* Flush pending input */ /* Flush pending input */
tcflush(ttyfd, TCIFLUSH); tcflush(read_fd, TCIFLUSH);
write(ttyfd, &nak, 1); full_write(write_fd, &nak, 1);
} } /* for (;;) */
done:
return length;
#undef note_error
} }
static void sigalrm_handler(int ATTRIBUTE_UNUSED signum) static void sigalrm_handler(int ATTRIBUTE_UNUSED signum)
@ -252,40 +220,38 @@ static void sigalrm_handler(int ATTRIBUTE_UNUSED signum)
int rx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int rx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int rx_main(int argc, char **argv) int rx_main(int argc, char **argv)
{ {
char *fn;
int ttyfd, filefd;
struct termios tty, orig_tty;
struct sigaction act; struct sigaction act;
struct termios tty, orig_tty;
int termios_err;
int file_fd;
int n; int n;
char error_buf[256];
if (argc != 2) if (argc != 2)
bb_show_usage(); bb_show_usage();
fn = argv[1]; /* Disabled by vda:
ttyfd = xopen(CURRENT_TTY, O_RDWR); * why we can't receive from stdin? Why we *require*
filefd = xopen(fn, O_RDWR|O_CREAT|O_TRUNC); * controlling tty?? */
/*read_fd = xopen(CURRENT_TTY, O_RDWR);*/
file_fd = xopen(argv[1], O_RDWR|O_CREAT|O_TRUNC);
if (tcgetattr(ttyfd, &tty) < 0) termios_err = tcgetattr(read_fd, &tty);
bb_perror_msg_and_die("tcgetattr"); if (termios_err == 0) {
orig_tty = tty;
orig_tty = tty; cfmakeraw(&tty);
tcsetattr(read_fd, TCSAFLUSH, &tty);
cfmakeraw(&tty); }
tcsetattr(ttyfd, TCSAFLUSH, &tty);
/* No SA_RESTART: we want ALRM to interrupt read() */
memset(&act, 0, sizeof(act)); memset(&act, 0, sizeof(act));
act.sa_handler = sigalrm_handler; act.sa_handler = sigalrm_handler;
sigaction(SIGALRM, &act, 0); sigaction(SIGALRM, &act, NULL);
n = receive(error_buf, sizeof(error_buf), ttyfd, filefd); n = receive(file_fd);
close(filefd); if (termios_err == 0)
tcsetattr(read_fd, TCSAFLUSH, &orig_tty);
tcsetattr(ttyfd, TCSAFLUSH, &orig_tty); if (ENABLE_FEATURE_CLEAN_UP)
close(file_fd);
if (n < 0) fflush_stdout_and_exit(n >= 0);
bb_error_msg_and_die("\nreceive failed:\n %s", error_buf);
fflush_stdout_and_exit(EXIT_SUCCESS);
} }

View File

@ -3,6 +3,7 @@
/* $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $ */ /* $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $ */
/* $NetBSD: inetd.c,v 1.11 1996/02/22 11:14:41 mycroft Exp $ */ /* $NetBSD: inetd.c,v 1.11 1996/02/22 11:14:41 mycroft Exp $ */
/* Busybox port by Vladimir Oleynik (C) 2001-2005 <dzo@simtreas.ru> */ /* Busybox port by Vladimir Oleynik (C) 2001-2005 <dzo@simtreas.ru> */
/* IPv6 support, many bug fixes by Denys Vlasenko (c) 2008 */
/* /*
* Copyright (c) 1983,1991 The Regents of the University of California. * Copyright (c) 1983,1991 The Regents of the University of California.
* All rights reserved. * All rights reserved.
@ -38,21 +39,17 @@
/* Inetd - Internet super-server /* Inetd - Internet super-server
* *
* This program invokes all internet services as needed. * This program invokes configured services when a connection
* connection-oriented services are invoked each time a * from a peer is established or a datagram arrives.
* Connection-oriented services are invoked each time a
* connection is made, by creating a process. This process * connection is made, by creating a process. This process
* is passed the connection as file descriptor 0 and is * is passed the connection as file descriptor 0 and is
* expected to do a getpeername to find out the source host * expected to do a getpeername to find out peer's host
* and port. * and port.
*
* Datagram oriented services are invoked when a datagram * Datagram oriented services are invoked when a datagram
* arrives; a process is created and passed a pending message * arrives; a process is created and passed a pending message
* on file descriptor 0. Datagram servers may either connect * on file descriptor 0. peer's address can be obtained
* to their peer, freeing up the original socket for inetd * using recvfrom.
* to receive further messages on, or "take over the socket",
* processing all arriving datagrams and, eventually, timing
* out. The first type of server is said to be "multi-threaded";
* the second type of server "single-threaded".
* *
* Inetd uses a configuration file which is read at startup * Inetd uses a configuration file which is read at startup
* and, possibly, at some later time in response to a hangup signal. * and, possibly, at some later time in response to a hangup signal.
@ -60,28 +57,28 @@
* order shown below. Continuation lines for an entry must begin with * order shown below. Continuation lines for an entry must begin with
* a space or tab. All fields must be present in each entry. * a space or tab. All fields must be present in each entry.
* *
* service name must be in /etc/services * service_name must be in /etc/services
* socket type stream/dgram/raw/rdm/seqpacket * socket_type stream/dgram/raw/rdm/seqpacket
* protocol must be in /etc/protocols * protocol must be in /etc/protocols
* (usually "tcp" or "udp") * (usually "tcp" or "udp")
* wait/nowait[.max] single-threaded/multi-threaded, max # * wait/nowait[.max] single-threaded/multi-threaded, max #
* user[.group] or user[:group] user/group to run daemon as * user[.group] or user[:group] user/group to run daemon as
* server program full path name * server_program full path name
* server program arguments maximum of MAXARGS (20) * server_program_arguments maximum of MAXARGS (20)
* *
* For RPC services * For RPC services
* service name/version must be in /etc/rpc * service_name/version must be in /etc/rpc
* socket type stream/dgram/raw/rdm/seqpacket * socket_type stream/dgram/raw/rdm/seqpacket
* rpc/protocol "rpc/tcp" etc * rpc/protocol "rpc/tcp" etc
* wait/nowait[.max] single-threaded/multi-threaded * wait/nowait[.max] single-threaded/multi-threaded
* user[.group] or user[:group] user to run daemon as * user[.group] or user[:group] user to run daemon as
* server program full path name * server_program full path name
* server program arguments maximum of MAXARGS (20) * server_program_arguments maximum of MAXARGS (20)
* *
* For non-RPC services, the "service name" can be of the form * For non-RPC services, the "service name" can be of the form
* hostaddress:servicename, in which case the hostaddress is used * hostaddress:servicename, in which case the hostaddress is used
* as the host portion of the address to listen on. If hostaddress * as the host portion of the address to listen on. If hostaddress
* consists of a single `*' character, INADDR_ANY is used. * consists of a single '*' character, INADDR_ANY is used.
* *
* A line can also consist of just * A line can also consist of just
* hostaddress: * hostaddress:
@ -102,7 +99,7 @@
* one line for any given RPC service, even if the host-address * one line for any given RPC service, even if the host-address
* specifiers are different. * specifiers are different.
* *
* Comment lines are indicated by a `#' in column 1. * Comment lines are indicated by a '#' in column 1.
*/ */
/* inetd rules for passing file descriptors to children /* inetd rules for passing file descriptors to children
@ -133,6 +130,8 @@
* tening service socket, and must accept at least one connection request * tening service socket, and must accept at least one connection request
* before exiting. Such a server would normally accept and process incoming * before exiting. Such a server would normally accept and process incoming
* connection requests until a timeout. * connection requests until a timeout.
*
* In short: "stream" can be "wait" or "nowait"; "dgram" must be "wait".
*/ */
/* Here's the scoop concerning the user[:group] feature: /* Here's the scoop concerning the user[:group] feature:
@ -152,26 +151,27 @@
#include <syslog.h> #include <syslog.h>
#include <sys/un.h> #include <sys/un.h>
#include "libbb.h"
#if !BB_MMU #include "libbb.h"
/* stream versions of these builtins are forking,
* can't do that (easily) on NOMMU */
#undef ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 0
#undef ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 0
#endif
#if ENABLE_FEATURE_INETD_RPC #if ENABLE_FEATURE_INETD_RPC
#include <rpc/rpc.h> #include <rpc/rpc.h>
#include <rpc/pmap_clnt.h> #include <rpc/pmap_clnt.h>
#endif #endif
#if !BB_MMU
/* stream version of chargen is forking but not execing,
* can't do that (easily) on NOMMU */
#undef ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 0
#endif
#define _PATH_INETDPID "/var/run/inetd.pid" #define _PATH_INETDPID "/var/run/inetd.pid"
#define CNT_INTERVAL 60 /* servers in CNT_INTERVAL sec. */ #define CNT_INTERVAL 60 /* servers in CNT_INTERVAL sec. */
#define RETRYTIME (60*10) /* retry after bind or server fail */ #define RETRYTIME 60 /* retry after bind or server fail */
// TODO: explain, or get rid of setrlimit games
#ifndef RLIMIT_NOFILE #ifndef RLIMIT_NOFILE
#define RLIMIT_NOFILE RLIMIT_OFILE #define RLIMIT_NOFILE RLIMIT_OFILE
@ -209,20 +209,21 @@ typedef struct servtab_t {
#else #else
#define is_rpc_service(sep) 0 #define is_rpc_service(sep) 0
#endif #endif
pid_t se_wait; /* 0:"nowait", 1:"wait" */ pid_t se_wait; /* 0:"nowait", 1:"wait", >1:"wait" */
/* and waiting for this pid */
socktype_t se_socktype; /* SOCK_STREAM/DGRAM/RDM/... */ socktype_t se_socktype; /* SOCK_STREAM/DGRAM/RDM/... */
family_t se_family; /* AF_UNIX/INET[6] */ family_t se_family; /* AF_UNIX/INET[6] */
smallint se_proto_no; /* almost "getprotobyname(se_proto)" */ /* se_proto_no is used by RPC code only... hmm */
smallint se_proto_no; /* IPPROTO_TCP/UDP, n/a for AF_UNIX */
smallint se_checked; /* looked at during merge */ smallint se_checked; /* looked at during merge */
unsigned se_max; /* allowed instances per minute */
unsigned se_count; /* number started since se_time */
unsigned se_time; /* whem we started counting */
char *se_user; /* user name to run as */ char *se_user; /* user name to run as */
char *se_group; /* group name to run as, can be NULL */ char *se_group; /* group name to run as, can be NULL */
#ifdef INETD_BUILTINS_ENABLED #ifdef INETD_BUILTINS_ENABLED
const struct builtin *se_builtin; /* if built-in, description */ const struct builtin *se_builtin; /* if built-in, description */
#endif #endif
// TODO: wrong algorithm!!!
unsigned se_max; /* max # of instances of this service */
unsigned se_count; /* number started since se_time */
unsigned se_time; /* start of se_count */
struct servtab_t *se_next; struct servtab_t *se_next;
len_and_sockaddr *se_lsa; len_and_sockaddr *se_lsa;
char *se_program; /* server program */ char *se_program; /* server program */
@ -231,60 +232,54 @@ typedef struct servtab_t {
} servtab_t; } servtab_t;
#ifdef INETD_BUILTINS_ENABLED #ifdef INETD_BUILTINS_ENABLED
/* Echo received data */ /* Echo received data */
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
static void echo_stream(int, servtab_t *); static void echo_stream(int, servtab_t *);
static void echo_dg(int, servtab_t *); static void echo_dg(int, servtab_t *);
#endif #endif
/* Internet /dev/null */ /* Internet /dev/null */
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
static void discard_stream(int, servtab_t *); static void discard_stream(int, servtab_t *);
static void discard_dg(int, servtab_t *); static void discard_dg(int, servtab_t *);
#endif #endif
/* Return 32 bit time since 1900 */ /* Return 32 bit time since 1900 */
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
static void machtime_stream(int, servtab_t *); static void machtime_stream(int, servtab_t *);
static void machtime_dg(int, servtab_t *); static void machtime_dg(int, servtab_t *);
#endif #endif
/* Return human-readable time */ /* Return human-readable time */
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
static void daytime_stream(int, servtab_t *); static void daytime_stream(int, servtab_t *);
static void daytime_dg(int, servtab_t *); static void daytime_dg(int, servtab_t *);
#endif #endif
/* Familiar character generator */ /* Familiar character generator */
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
static void chargen_stream(int, servtab_t *); static void chargen_stream(int, servtab_t *);
static void chargen_dg(int, servtab_t *); static void chargen_dg(int, servtab_t *);
#endif #endif
struct builtin { struct builtin {
const char *bi_service; /* internally provided service name */ /* NB: not necessarily NUL terminated */
uint8_t bi_fork; /* 1 if stream fn should run in child */ char bi_service7[7]; /* internally provided service name */
/* All builtins are "nowait" */ uint8_t bi_fork; /* 1 if stream fn should run in child */
/* uint8_t bi_wait; */ /* 1 if should wait for child */
void (*bi_stream_fn)(int, servtab_t *); void (*bi_stream_fn)(int, servtab_t *);
void (*bi_dgram_fn)(int, servtab_t *); void (*bi_dgram_fn)(int, servtab_t *);
}; };
static const struct builtin builtins[] = { static const struct builtin builtins[] = {
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
/* Echo received data */
{ "echo", 1, echo_stream, echo_dg }, { "echo", 1, echo_stream, echo_dg },
#endif #endif
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
/* Internet /dev/null */
{ "discard", 1, discard_stream, discard_dg }, { "discard", 1, discard_stream, discard_dg },
#endif #endif
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
/* Familiar character generator */
{ "chargen", 1, chargen_stream, chargen_dg }, { "chargen", 1, chargen_stream, chargen_dg },
#endif #endif
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
/* Return 32 bit time since 1900 */
{ "time", 0, machtime_stream, machtime_dg }, { "time", 0, machtime_stream, machtime_dg },
#endif #endif
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
/* Return human-readable time */
{ "daytime", 0, daytime_stream, daytime_dg }, { "daytime", 0, daytime_stream, daytime_dg },
#endif #endif
}; };
@ -305,8 +300,8 @@ struct globals {
FILE *fconfig; FILE *fconfig;
char *default_local_hostname; char *default_local_hostname;
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
char *endring; char *end_ring;
char *ringpos; char *ring_pos;
char ring[128]; char ring[128];
#endif #endif
fd_set allsock; fd_set allsock;
@ -333,8 +328,8 @@ struct BUG_G_too_big {
#define default_local_hostname (G.default_local_hostname) #define default_local_hostname (G.default_local_hostname)
#define first_ps_byte (G.first_ps_byte ) #define first_ps_byte (G.first_ps_byte )
#define last_ps_byte (G.last_ps_byte ) #define last_ps_byte (G.last_ps_byte )
#define endring (G.endring ) #define end_ring (G.end_ring )
#define ringpos (G.ringpos ) #define ring_pos (G.ring_pos )
#define ring (G.ring ) #define ring (G.ring )
#define allsock (G.allsock ) #define allsock (G.allsock )
#define line (G.line ) #define line (G.line )
@ -357,6 +352,8 @@ static len_and_sockaddr *xzalloc_lsa(int family)
int sz; int sz;
sz = sizeof(struct sockaddr_in); sz = sizeof(struct sockaddr_in);
if (family == AF_UNIX)
sz = sizeof(struct sockaddr_un);
#if ENABLE_FEATURE_IPV6 #if ENABLE_FEATURE_IPV6
if (family == AF_INET6) if (family == AF_INET6)
sz = sizeof(struct sockaddr_in6); sz = sizeof(struct sockaddr_in6);
@ -367,7 +364,6 @@ static len_and_sockaddr *xzalloc_lsa(int family)
return lsa; return lsa;
} }
static void rearm_alarm(void) static void rearm_alarm(void)
{ {
if (!alarm_armed) { if (!alarm_armed) {
@ -660,10 +656,8 @@ static NOINLINE servtab_t *parse_one_line(void)
} }
arg = next_word(&cp); arg = next_word(&cp);
if (arg == NULL) { if (arg == NULL) /* a blank line. */
/* A blank line. */
goto more; goto more;
}
/* [host:]service socktype proto wait user[:group] prog [args] */ /* [host:]service socktype proto wait user[:group] prog [args] */
/* Check for "host:...." line */ /* Check for "host:...." line */
@ -764,9 +758,9 @@ static NOINLINE servtab_t *parse_one_line(void)
} }
/* we don't really need getprotobyname()! */ /* we don't really need getprotobyname()! */
if (strcmp(arg, "tcp") == 0) if (strcmp(arg, "tcp") == 0)
sep->se_proto_no = 6; sep->se_proto_no = IPPROTO_TCP; /* = 6 */
if (strcmp(arg, "udp") == 0) if (strcmp(arg, "udp") == 0)
sep->se_proto_no = 17; sep->se_proto_no = IPPROTO_UDP; /* = 17 */
if (six) if (six)
*six = '6'; *six = '6';
if (!sep->se_proto_no) /* not tcp/udp?? */ if (!sep->se_proto_no) /* not tcp/udp?? */
@ -785,7 +779,11 @@ static NOINLINE servtab_t *parse_one_line(void)
if (errno) if (errno)
goto parse_err; goto parse_err;
} }
sep->se_wait = (strcmp(arg, "wait") == 0); sep->se_wait = (arg[0] != 'n' || arg[1] != 'o');
if (!sep->se_wait) /* "no" seen */
arg += 2;
if (strcmp(arg, "wait") != 0)
goto parse_err;
/* user[:group] prog [args] */ /* user[:group] prog [args] */
sep->se_user = xstrdup(next_word(&cp)); sep->se_user = xstrdup(next_word(&cp));
@ -804,48 +802,56 @@ static NOINLINE servtab_t *parse_one_line(void)
if (sep->se_program == NULL) if (sep->se_program == NULL)
goto parse_err; goto parse_err;
#ifdef INETD_BUILTINS_ENABLED #ifdef INETD_BUILTINS_ENABLED
/* sep->se_builtin = NULL; - done by new_servtab() */
if (strcmp(sep->se_program, "internal") == 0 if (strcmp(sep->se_program, "internal") == 0
&& strlen(sep->se_service) <= 7
&& (sep->se_socktype == SOCK_STREAM && (sep->se_socktype == SOCK_STREAM
|| sep->se_socktype == SOCK_DGRAM) || sep->se_socktype == SOCK_DGRAM)
) { ) {
int i; int i;
for (i = 0; i < ARRAY_SIZE(builtins); i++) for (i = 0; i < ARRAY_SIZE(builtins); i++)
if (strcmp(builtins[i].bi_service, sep->se_service) == 0) if (strncmp(builtins[i].bi_service7, sep->se_service, 7) == 0)
goto found_bi; goto found_bi;
bb_error_msg("unknown internal service %s", sep->se_service); bb_error_msg("unknown internal service %s", sep->se_service);
goto parse_err; goto parse_err;
found_bi: found_bi:
sep->se_builtin = &builtins[i]; sep->se_builtin = &builtins[i];
sep->se_wait = 0; /* = builtins[i].bi_wait; - always 0 */ /* stream builtins must be "nowait", dgram must be "wait" */
if (sep->se_wait != (sep->se_socktype == SOCK_DGRAM))
goto parse_err;
} }
#endif #endif
argc = 0; argc = 0;
while ((arg = next_word(&cp)) != NULL && argc < MAXARGV) { while ((arg = next_word(&cp)) != NULL && argc < MAXARGV)
sep->se_argv[argc++] = xstrdup(arg); sep->se_argv[argc++] = xstrdup(arg);
}
/* while (argc <= MAXARGV) */
/* sep->se_argv[argc++] = NULL; - done by new_servtab() */
/* /* catch mixups. "<service> stream udp ..." == wtf */
* Now that we've processed the entire line, check if the hostname if (sep->se_socktype == SOCK_STREAM) {
* specifier was a comma separated list of hostnames. If so if (sep->se_proto_no == IPPROTO_UDP)
* we'll make new entries for each address. goto parse_err;
*/ }
if (sep->se_socktype == SOCK_DGRAM) {
if (sep->se_proto_no == IPPROTO_TCP)
goto parse_err;
/* "udp nowait" is a small fork bomb :) */
if (!sep->se_wait)
goto parse_err;
}
/* check if the hostname specifier is a comma separated list
* of hostnames. we'll make new entries for each address. */
while ((hostdelim = strrchr(sep->se_local_hostname, ',')) != NULL) { while ((hostdelim = strrchr(sep->se_local_hostname, ',')) != NULL) {
nsep = dup_servtab(sep); nsep = dup_servtab(sep);
/* /* NUL terminate the hostname field of the existing entry,
* NUL terminate the hostname field of the existing entry, * and make a dup for the new entry. */
* and make a dup for the new entry.
*/
*hostdelim++ = '\0'; *hostdelim++ = '\0';
nsep->se_local_hostname = xstrdup(hostdelim); nsep->se_local_hostname = xstrdup(hostdelim);
nsep->se_next = sep->se_next; nsep->se_next = sep->se_next;
sep->se_next = nsep; sep->se_next = nsep;
} }
/* Was doing it here: */ /* was doing it here: */
/* DNS resolution, create copies for each IP address */ /* DNS resolution, create copies for each IP address */
/* IPv6-ization destroyed it :( */
return sep; return sep;
} }
@ -947,15 +953,9 @@ static void reread_config_file(int sig ATTRIBUTE_UNUSED)
switch (sep->se_family) { switch (sep->se_family) {
struct sockaddr_un *sun; struct sockaddr_un *sun;
case AF_UNIX: case AF_UNIX:
/* we have poor infrastructure for AF_UNIX... */ lsa = xzalloc_lsa(AF_UNIX);
n = strlen(sep->se_service);
if (n > sizeof(sun->sun_path) - 1)
n = sizeof(sun->sun_path) - 1;
lsa = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_un));
lsa->len = sizeof(struct sockaddr_un);
sun = (struct sockaddr_un*)&lsa->u.sa; sun = (struct sockaddr_un*)&lsa->u.sa;
sun->sun_family = AF_UNIX; safe_strncpy(sun->sun_path, sep->se_service, sizeof(sun->sun_path));
strncpy(sun->sun_path, sep->se_service, n);
break; break;
default: /* case AF_INET, case AF_INET6 */ default: /* case AF_INET, case AF_INET6 */
@ -1259,8 +1259,8 @@ int inetd_main(int argc, char **argv)
sep->se_count = 0; sep->se_count = 0;
} }
} }
/* on NOMMU, streamed echo, chargen and discard /* on NOMMU, streamed chargen
* builtins wouldn't work, but they are * builtin wouldn't work, but it is
* not allowed on NOMMU (ifdefed out) */ * not allowed on NOMMU (ifdefed out) */
#ifdef INETD_BUILTINS_ENABLED #ifdef INETD_BUILTINS_ENABLED
if (BB_MMU && sep->se_builtin) if (BB_MMU && sep->se_builtin)
@ -1311,8 +1311,42 @@ int inetd_main(int argc, char **argv)
continue; /* -> check next fd in fd set */ continue; /* -> check next fd in fd set */
} }
#endif #endif
/* child. prepare env and exec program */ /* child */
setsid(); setsid();
#if 0
/* This does not work.
* Actually, it _almost_ works. The idea behind it is: child
* can peek at (already received and buffered by kernel) UDP packet,
* and perform connect() on the socket so that it is linked only
* to this peer. But this also affects parent, because descriptors
* are shared after fork() a-la dup(). When parent returns to
* select(), it will see this descriptor attached to the peer (!)
* and likely still readable, will act on it and mess things up
* (can create many copies of same child, etc).
* If child will create new socket instead, then bind() and
* connect() it to peer's address, descriptor aliasing problem
* is solved, but first packet cannot be "transferred" to the new
* socket. It is not a problem if child can account for this,
* but our child will exec - and exec'ed program does not know
* about this "lost packet" problem! Pity... */
/* "nowait" udp[6]. Hmmm... */
if (!sep->se_wait
&& sep->se_socktype == SOCK_DGRAM
&& sep->se_family != AF_UNIX
) {
len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family);
/* peek at the packet and remember peer addr */
int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
&lsa->u.sa, &lsa->len);
if (r >= 0)
/* make this socket "connected" to peer addr:
* only packets from this peer will be recv'ed,
* and bare write()/send() will work on it */
connect(ctrl, &lsa->u.sa, lsa->len);
free(lsa);
}
#endif
/* prepare env and exec program */
pwd = getpwnam(sep->se_user); pwd = getpwnam(sep->se_user);
if (pwd == NULL) { if (pwd == NULL) {
bb_error_msg("%s: no such user", sep->se_user); bb_error_msg("%s: no such user", sep->se_user);
@ -1342,8 +1376,8 @@ int inetd_main(int argc, char **argv)
bb_perror_msg("setrlimit"); bb_perror_msg("setrlimit");
closelog(); closelog();
xmove_fd(ctrl, 0); xmove_fd(ctrl, 0);
dup2(0, 1); xdup2(0, 1);
dup2(0, 2); xdup2(0, 2);
/* NB: among others, this loop closes listening socket /* NB: among others, this loop closes listening socket
* for nowait stream children */ * for nowait stream children */
for (sep2 = serv_list; sep2; sep2 = sep2->se_next) for (sep2 = serv_list; sep2; sep2 = sep2->se_next)
@ -1378,6 +1412,8 @@ static void echo_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
} }
#else #else
static const char *const args[] = { "cat", NULL }; static const char *const args[] = { "cat", NULL };
/* no error messages */
xmove_fd(xopen("/dev/null", O_WRONLY), STDERR_FILENO);
BB_EXECVP("cat", (char**)args); BB_EXECVP("cat", (char**)args);
_exit(1); _exit(1);
#endif #endif
@ -1404,8 +1440,16 @@ static void echo_dg(int s, servtab_t *sep)
/* ARGSUSED */ /* ARGSUSED */
static void discard_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED) static void discard_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
{ {
#if BB_MMU
while (safe_read(s, line, LINE_SIZE) > 0) while (safe_read(s, line, LINE_SIZE) > 0)
continue; continue;
#else
static const char *const args[] = { "dd", "of=/dev/null", NULL };
/* no error messages */
xmove_fd(xopen("/dev/null", O_WRONLY), STDERR_FILENO);
BB_EXECVP("dd", (char**)args);
_exit(1);
#endif
} }
/* ARGSUSED */ /* ARGSUSED */
static void discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) static void discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
@ -1418,14 +1462,14 @@ static void discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN #if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
#define LINESIZ 72 #define LINESIZ 72
static void initring(void) static void init_ring(void)
{ {
int i; int i;
endring = ring; end_ring = ring;
for (i = 0; i <= 128; ++i) for (i = 0; i <= 128; ++i)
if (isprint(i)) if (isprint(i))
*endring++ = i; *end_ring++ = i;
} }
/* Character generator. MMU arches only. */ /* Character generator. MMU arches only. */
/* ARGSUSED */ /* ARGSUSED */
@ -1435,8 +1479,8 @@ static void chargen_stream(int s, servtab_t *sep)
int len; int len;
char text[LINESIZ + 2]; char text[LINESIZ + 2];
if (!endring) { if (!end_ring) {
initring(); init_ring();
rs = ring; rs = ring;
} }
@ -1444,14 +1488,14 @@ static void chargen_stream(int s, servtab_t *sep)
text[LINESIZ + 1] = '\n'; text[LINESIZ + 1] = '\n';
rs = ring; rs = ring;
for (;;) { for (;;) {
len = endring - rs; len = end_ring - rs;
if (len >= LINESIZ) if (len >= LINESIZ)
memmove(text, rs, LINESIZ); memmove(text, rs, LINESIZ);
else { else {
memmove(text, rs, len); memmove(text, rs, len);
memmove(text + len, ring, LINESIZ - len); memmove(text + len, ring, LINESIZ - len);
} }
if (++rs == endring) if (++rs == end_ring)
rs = ring; rs = ring;
xwrite(s, text, sizeof(text)); xwrite(s, text, sizeof(text));
} }
@ -1469,20 +1513,20 @@ static void chargen_dg(int s, servtab_t *sep)
if (recvfrom(s, text, sizeof(text), MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0) if (recvfrom(s, text, sizeof(text), MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
return; return;
if (!endring) { if (!end_ring) {
initring(); init_ring();
ringpos = ring; ring_pos = ring;
} }
len = endring - ringpos; len = end_ring - ring_pos;
if (len >= LINESIZ) if (len >= LINESIZ)
memmove(text, ringpos, LINESIZ); memmove(text, ring_pos, LINESIZ);
else { else {
memmove(text, ringpos, len); memmove(text, ring_pos, len);
memmove(text + len, ring, LINESIZ - len); memmove(text + len, ring, LINESIZ - len);
} }
if (++ringpos == endring) if (++ring_pos == end_ring)
ringpos = ring; ring_pos = ring;
text[LINESIZ] = '\r'; text[LINESIZ] = '\r';
text[LINESIZ + 1] = '\n'; text[LINESIZ + 1] = '\n';
sendto(s, text, sizeof(text), 0, &lsa->u.sa, lsa->len); sendto(s, text, sizeof(text), 0, &lsa->u.sa, lsa->len);
@ -1498,7 +1542,7 @@ static void chargen_dg(int s, servtab_t *sep)
* we must add 2208988800 seconds to this figure to make up for * we must add 2208988800 seconds to this figure to make up for
* some seventy years Bell Labs was asleep. * some seventy years Bell Labs was asleep.
*/ */
static unsigned machtime(void) static uint32_t machtime(void)
{ {
struct timeval tv; struct timeval tv;

View File

@ -751,6 +751,11 @@ int nc_main(int argc, char **argv)
if (option_mask32 & OPT_s) { /* local address */ if (option_mask32 & OPT_s) { /* local address */
/* if o_lport is still 0, then we will use random port */ /* if o_lport is still 0, then we will use random port */
ouraddr = xhost2sockaddr(str_s, o_lport); ouraddr = xhost2sockaddr(str_s, o_lport);
#ifdef BLOAT
/* prevent spurious "UDP listen needs !0 port" */
o_lport = get_nport(ouraddr);
o_lport = ntohs(o_lport);
#endif
x = xsocket(ouraddr->u.sa.sa_family, x, 0); x = xsocket(ouraddr->u.sa.sa_family, x, 0);
} else { } else {
/* We try IPv6, then IPv4, unless addr family is /* We try IPv6, then IPv4, unless addr family is
@ -771,12 +776,14 @@ int nc_main(int argc, char **argv)
setsockopt(netfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf); setsockopt(netfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf);
#endif #endif
#ifdef BLOAT
if (OPT_l && (option_mask32 & (OPT_u|OPT_l)) == (OPT_u|OPT_l)) { if (OPT_l && (option_mask32 & (OPT_u|OPT_l)) == (OPT_u|OPT_l)) {
/* apparently UDP can listen ON "port 0", /* apparently UDP can listen ON "port 0",
but that's not useful */ but that's not useful */
if (!o_lport) if (!o_lport)
bb_error_msg_and_die("UDP listen needs nonzero -p port"); bb_error_msg_and_die("UDP listen needs nonzero -p port");
} }
#endif
FD_SET(0, &ding1); /* stdin *is* initially open */ FD_SET(0, &ding1); /* stdin *is* initially open */
if (proggie) { if (proggie) {