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:
parent
4e6d5117b8
commit
4cf1d08fc2
@ -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);
|
||||||
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
228
miscutils/rx.c
228
miscutils/rx.c
@ -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);
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user