summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-03-12 23:13:50 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-03-12 23:13:50 +0000
commit4cf1d08fc2e50f9abda999d468c5e972ff4995c2 (patch)
tree58dd8efdd7d0f0990d30d8b5f5f53cf2ee35d444
parent4e6d5117b839cef41cd3919966f95bf25d24d8d9 (diff)
downloadbusybox-w32-4cf1d08fc2e50f9abda999d468c5e972ff4995c2.tar.gz
busybox-w32-4cf1d08fc2e50f9abda999d468c5e972ff4995c2.tar.bz2
busybox-w32-4cf1d08fc2e50f9abda999d468c5e972ff4995c2.zip
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
-rw-r--r--ipsvd/tcpudp.c12
-rw-r--r--libbb/signals.c7
-rw-r--r--loginutils/vlock.c84
-rw-r--r--miscutils/devfsd.c9
-rw-r--r--miscutils/rx.c232
-rw-r--r--networking/inetd.c258
-rw-r--r--networking/nc_bloaty.c7
7 files changed, 308 insertions, 301 deletions
diff --git a/ipsvd/tcpudp.c b/ipsvd/tcpudp.c
index cb57e598a..8b4ae88f4 100644
--- a/ipsvd/tcpudp.c
+++ b/ipsvd/tcpudp.c
@@ -339,16 +339,17 @@ int tcpudpsvd_main(int argc, char **argv)
339 * 1) we have to do it before fork() 339 * 1) we have to do it before fork()
340 * 2) order is important - is it right now? */ 340 * 2) order is important - is it right now? */
341 341
342 /* Make plain write/send work for this socket by supplying default 342 /* Open new non-connected UDP socket for further clients... */
343 sock = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0);
344 setsockopt_reuseaddr(sock);
345 /* Make plain write/send work for old socket by supplying default
343 * destination address. This also restricts incoming packets 346 * destination address. This also restricts incoming packets
344 * to ones coming from this remote IP. */ 347 * to ones coming from this remote IP. */
345 xconnect(0, &remote.u.sa, sa_len); 348 xconnect(0, &remote.u.sa, sa_len);
346 /* hole? at this point we have no wildcard udp socket... 349 /* hole? at this point we have no wildcard udp socket...
347 * can this cause clients to get "port unreachable" icmp? 350 * can this cause clients to get "port unreachable" icmp?
348 * Yup, time window is very small, but it exists (is it?) */ 351 * Yup, time window is very small, but it exists (is it?) */
349 /* Open new non-connected UDP socket for further clients */ 352 /* ..."open new socket", continued */
350 sock = xsocket(lsa->u.sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
351 setsockopt_reuseaddr(sock);
352 xbind(sock, &lsa->u.sa, sa_len); 353 xbind(sock, &lsa->u.sa, sa_len);
353 socket_want_pktinfo(sock); 354 socket_want_pktinfo(sock);
354 355
@@ -377,7 +378,6 @@ int tcpudpsvd_main(int argc, char **argv)
377 goto again; 378 goto again;
378 } 379 }
379 380
380
381 if (pid != 0) { 381 if (pid != 0) {
382 /* parent */ 382 /* parent */
383 cnum++; 383 cnum++;
@@ -467,7 +467,7 @@ int tcpudpsvd_main(int argc, char **argv)
467 467
468 argv += 2; 468 argv += 2;
469#ifdef SSLSVD 469#ifdef SSLSVD
470 strcpy(id, utoa(pid); 470 strcpy(id, utoa(pid));
471 ssl_io(0, argv); 471 ssl_io(0, argv);
472#else 472#else
473 BB_EXECVP(argv[0], argv); 473 BB_EXECVP(argv[0], argv);
diff --git a/libbb/signals.c b/libbb/signals.c
index 1929cb88e..a327e87c8 100644
--- a/libbb/signals.c
+++ b/libbb/signals.c
@@ -82,13 +82,8 @@ void sig_pause(void)
82/* Assuming the sig is fatal */ 82/* Assuming the sig is fatal */
83void kill_myself_with_sig(int sig) 83void kill_myself_with_sig(int sig)
84{ 84{
85 sigset_t set;
86
87 signal(sig, SIG_DFL); 85 signal(sig, SIG_DFL);
88 86 sig_unblock(sig);
89 sigemptyset(&set);
90 sigaddset(&set, sig);
91 sigprocmask(SIG_UNBLOCK, &set, NULL);
92 raise(sig); 87 raise(sig);
93 _exit(1); /* Should not reach it */ 88 _exit(1); /* Should not reach it */
94} 89}
diff --git a/loginutils/vlock.c b/loginutils/vlock.c
index 6e928e239..846733ea8 100644
--- a/loginutils/vlock.c
+++ b/loginutils/vlock.c
@@ -1,5 +1,4 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2
3/* 2/*
4 * vlock implementation for busybox 3 * vlock implementation for busybox
5 * 4 *
@@ -16,27 +15,25 @@
16/* Fixed by Erik Andersen to do passwords the tinylogin way... 15/* Fixed by Erik Andersen to do passwords the tinylogin way...
17 * It now works with md5, sha1, etc passwords. */ 16 * It now works with md5, sha1, etc passwords. */
18 17
19#include "libbb.h"
20#include <sys/vt.h> 18#include <sys/vt.h>
21 19#include "libbb.h"
22enum { vfd = 3 };
23
24/* static unsigned long o_lock_all; */
25 20
26static void release_vt(int signo) 21static void release_vt(int signo)
27{ 22{
28 ioctl(vfd, VT_RELDISP, (unsigned long) !option_mask32 /*!o_lock_all*/); 23 /* If -a, param is 0, which means:
24 * "no, kernel, we don't allow console switch away from us!" */
25 ioctl(STDIN_FILENO, VT_RELDISP, (unsigned long) !option_mask32);
29} 26}
30 27
31static void acquire_vt(int signo) 28static void acquire_vt(int signo)
32{ 29{
33 ioctl(vfd, VT_RELDISP, VT_ACKACQ); 30 /* ACK to kernel that switch to console is successful */
31 ioctl(STDIN_FILENO, VT_RELDISP, VT_ACKACQ);
34} 32}
35 33
36int vlock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 34int vlock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
37int vlock_main(int argc, char **argv) 35int vlock_main(int argc, char **argv)
38{ 36{
39 sigset_t sig;
40 struct sigaction sa; 37 struct sigaction sa;
41 struct vt_mode vtm; 38 struct vt_mode vtm;
42 struct termios term; 39 struct termios term;
@@ -48,49 +45,48 @@ int vlock_main(int argc, char **argv)
48 uid = getuid(); 45 uid = getuid();
49 pw = getpwuid(uid); 46 pw = getpwuid(uid);
50 if (pw == NULL) 47 if (pw == NULL)
51 bb_error_msg_and_die("unknown uid %d", uid); 48 bb_error_msg_and_die("unknown uid %d", (int)uid);
52 49
53 if (argc > 2) { 50 opt_complementary = "=0"; /* no params! */
54 bb_show_usage(); 51 getopt32(argv, "a");
55 } 52
56 53 /* Ignore some signals so that we don't get killed by them */
57 /*o_lock_all = */getopt32(argv, "a"); 54 bb_signals(0
58 55 + (1 << SIGTSTP)
59 /* Avoid using statics - use constant fd */ 56 + (1 << SIGTTIN)
60 xmove_fd(xopen(CURRENT_TTY, O_RDWR), vfd); 57 + (1 << SIGTTOU)
61 xioctl(vfd, VT_GETMODE, &vtm); 58 + (1 << SIGHUP )
62 59 + (1 << SIGCHLD) /* paranoia :) */
63 /* mask a bunch of signals */ 60 + (1 << SIGQUIT)
64 sigprocmask(SIG_SETMASK, NULL, &sig); 61 + (1 << SIGINT )
65 sigdelset(&sig, SIGUSR1); 62 , SIG_IGN);
66 sigdelset(&sig, SIGUSR2); 63
67 sigaddset(&sig, SIGTSTP); 64 /* We will use SIGUSRx for console switch control: */
68 sigaddset(&sig, SIGTTIN); 65 /* 1: set handlers */
69 sigaddset(&sig, SIGTTOU); 66 sigemptyset(&sa.sa_mask);
70 sigaddset(&sig, SIGHUP);
71 sigaddset(&sig, SIGCHLD);
72 sigaddset(&sig, SIGQUIT);
73 sigaddset(&sig, SIGINT);
74
75 sigemptyset(&(sa.sa_mask));
76 sa.sa_flags = SA_RESTART; 67 sa.sa_flags = SA_RESTART;
77 sa.sa_handler = release_vt; 68 sa.sa_handler = release_vt;
78 sigaction(SIGUSR1, &sa, NULL); 69 sigaction(SIGUSR1, &sa, NULL);
79 sa.sa_handler = acquire_vt; 70 sa.sa_handler = acquire_vt;
80 sigaction(SIGUSR2, &sa, NULL); 71 sigaction(SIGUSR2, &sa, NULL);
81 72 /* 2: unmask them */
82 /* need to handle some signals so that we don't get killed by them */ 73 sigprocmask(SIG_SETMASK, NULL, &sa.sa_mask);
83 sa.sa_handler = SIG_IGN; 74 sigdelset(&sa.sa_mask, SIGUSR1);
84 sigaction(SIGHUP, &sa, NULL); 75 sigdelset(&sa.sa_mask, SIGUSR2);
85 sigaction(SIGQUIT, &sa, NULL); 76 sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL);
86 sigaction(SIGINT, &sa, NULL); 77
87 sigaction(SIGTSTP, &sa, NULL); 78 /* Revert stdin/out to our controlling tty
88 79 * (or die if we have none) */
80 xmove_fd(xopen(CURRENT_TTY, O_RDWR), STDIN_FILENO);
81 xdup2(STDIN_FILENO, STDOUT_FILENO);
82
83 xioctl(STDIN_FILENO, VT_GETMODE, &vtm);
89 ovtm = vtm; 84 ovtm = vtm;
85 /* "console switches are controlled by us, not kernel!" */
90 vtm.mode = VT_PROCESS; 86 vtm.mode = VT_PROCESS;
91 vtm.relsig = SIGUSR1; 87 vtm.relsig = SIGUSR1;
92 vtm.acqsig = SIGUSR2; 88 vtm.acqsig = SIGUSR2;
93 ioctl(vfd, VT_SETMODE, &vtm); 89 ioctl(STDIN_FILENO, VT_SETMODE, &vtm);
94 90
95 tcgetattr(STDIN_FILENO, &oterm); 91 tcgetattr(STDIN_FILENO, &oterm);
96 term = oterm; 92 term = oterm;
@@ -111,7 +107,7 @@ int vlock_main(int argc, char **argv)
111 puts("Password incorrect"); 107 puts("Password incorrect");
112 } while (1); 108 } while (1);
113 109
114 ioctl(vfd, VT_SETMODE, &ovtm); 110 ioctl(STDIN_FILENO, VT_SETMODE, &ovtm);
115 tcsetattr(STDIN_FILENO, TCSANOW, &oterm); 111 tcsetattr(STDIN_FILENO, TCSANOW, &oterm);
116 fflush_stdout_and_exit(0); 112 fflush_stdout_and_exit(0);
117} 113}
diff --git a/miscutils/devfsd.c b/miscutils/devfsd.c
index 286f00fd8..50c8203cb 100644
--- a/miscutils/devfsd.c
+++ b/miscutils/devfsd.c
@@ -386,15 +386,14 @@ int devfsd_main(int argc, char **argv)
386 /* Tell kernel we are special(i.e. we get to see hidden entries) */ 386 /* Tell kernel we are special(i.e. we get to see hidden entries) */
387 xioctl(fd, DEVFSDIOC_SET_EVENT_MASK, 0); 387 xioctl(fd, DEVFSDIOC_SET_EVENT_MASK, 0);
388 388
389 /* Set up SIGHUP and SIGUSR1 handlers */
389 sigemptyset(&new_action.sa_mask); 390 sigemptyset(&new_action.sa_mask);
390 new_action.sa_flags = 0; 391 new_action.sa_flags = 0;
391
392 /* Set up SIGHUP and SIGUSR1 handlers */
393 new_action.sa_handler = signal_handler; 392 new_action.sa_handler = signal_handler;
394 if (sigaction(SIGHUP, &new_action, NULL) != 0 || sigaction(SIGUSR1, &new_action, NULL) != 0) 393 sigaction(SIGHUP, &new_action, NULL);
395 bb_error_msg_and_die("sigaction"); 394 sigaction(SIGUSR1, &new_action, NULL);
396 395
397 printf("%s v%s started for %s\n",applet_name, DEVFSD_VERSION, mount_point); 396 printf("%s v%s started for %s\n", applet_name, DEVFSD_VERSION, mount_point);
398 397
399 /* Set umask so that mknod(2), open(2) and mkdir(2) have complete control over permissions */ 398 /* Set umask so that mknod(2), open(2) and mkdir(2) have complete control over permissions */
400 umask(0); 399 umask(0);
diff --git a/miscutils/rx.c b/miscutils/rx.c
index 8ccea4974..9a8fcaa20 100644
--- a/miscutils/rx.c
+++ b/miscutils/rx.c
@@ -16,7 +16,6 @@
16 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 16 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
17 * 17 *
18 * This was originally written for blob and then adapted for busybox. 18 * This was originally written for blob and then adapted for busybox.
19 *
20 */ 19 */
21 20
22#include "libbb.h" 21#include "libbb.h"
@@ -29,66 +28,59 @@
29#define BS 0x08 28#define BS 0x08
30 29
31/* 30/*
32
33Cf: 31Cf:
34
35 http://www.textfiles.com/apple/xmodem 32 http://www.textfiles.com/apple/xmodem
36 http://www.phys.washington.edu/~belonis/xmodem/docxmodem.txt 33 http://www.phys.washington.edu/~belonis/xmodem/docxmodem.txt
37 http://www.phys.washington.edu/~belonis/xmodem/docymodem.txt 34 http://www.phys.washington.edu/~belonis/xmodem/docymodem.txt
38 http://www.phys.washington.edu/~belonis/xmodem/modmprot.col 35 http://www.phys.washington.edu/~belonis/xmodem/modmprot.col
39
40*/ 36*/
41 37
42#define TIMEOUT 1 38#define TIMEOUT 1
43#define TIMEOUT_LONG 10 39#define TIMEOUT_LONG 10
44#define MAXERRORS 10 40#define MAXERRORS 10
45 41
46static int read_byte(int fd, unsigned timeout) 42#define read_fd STDIN_FILENO
43#define write_fd STDOUT_FILENO
44
45static int read_byte(unsigned timeout)
47{ 46{
48 char buf[1]; 47 char buf[1];
49 int n; 48 int n;
50 49
51 alarm(timeout); 50 alarm(timeout);
52 51 /* NOT safe_read! We want ALRM to interrupt us */
53 n = read(fd, &buf, 1); 52 n = read(read_fd, buf, 1);
54
55 alarm(0); 53 alarm(0);
56
57 if (n == 1) 54 if (n == 1)
58 return buf[0] & 0xff; 55 return (unsigned char)buf[0];
59 else 56 return -1;
60 return -1;
61} 57}
62 58
63static int receive(char *error_buf, size_t error_buf_size, 59static int receive(/*int read_fd, */int file_fd)
64 int ttyfd, int filefd)
65{ 60{
66 char blockBuf[1024]; 61 unsigned char blockBuf[1024];
67 unsigned int errors = 0; 62 unsigned errors = 0;
68 unsigned int wantBlockNo = 1; 63 unsigned wantBlockNo = 1;
69 unsigned int length = 0; 64 unsigned length = 0;
70 int docrc = 1; 65 int do_crc = 1;
71 char nak = 'C'; 66 char nak = 'C';
72 unsigned int timeout = TIMEOUT_LONG; 67 unsigned timeout = TIMEOUT_LONG;
73
74#define note_error(fmt,args...) \
75 snprintf(error_buf, error_buf_size, fmt,##args)
76 68
77 /* Flush pending input */ 69 /* Flush pending input */
78 tcflush(ttyfd, TCIFLUSH); 70 tcflush(read_fd, TCIFLUSH);
79 71
80 /* Ask for CRC; if we get errors, we will go with checksum */ 72 /* Ask for CRC; if we get errors, we will go with checksum */
81 write(ttyfd, &nak, 1); 73 full_write(write_fd, &nak, 1);
82 74
83 for (;;) { 75 for (;;) {
84 int blockBegin; 76 int blockBegin;
85 int blockNo, blockNoOnesCompl; 77 int blockNo, blockNoOnesCompl;
86 int blockLength; 78 int blockLength;
87 int cksum = 0; 79 int cksum_crc; /* cksum OR crc */
88 int crcHi = 0; 80 int expected;
89 int crcLo = 0; 81 int i,j;
90 82
91 blockBegin = read_byte(ttyfd, timeout); 83 blockBegin = read_byte(timeout);
92 if (blockBegin < 0) 84 if (blockBegin < 0)
93 goto timeout; 85 goto timeout;
94 86
@@ -102,52 +94,47 @@ static int receive(char *error_buf, size_t error_buf_size,
102 94
103 case EOT: 95 case EOT:
104 nak = ACK; 96 nak = ACK;
105 write(ttyfd, &nak, 1); 97 full_write(write_fd, &nak, 1);
106 goto done; 98 return length;
107 99
108 default: 100 default:
109 goto error; 101 goto error;
110 } 102 }
111 103
112 /* block no */ 104 /* block no */
113 blockNo = read_byte(ttyfd, TIMEOUT); 105 blockNo = read_byte(TIMEOUT);
114 if (blockNo < 0) 106 if (blockNo < 0)
115 goto timeout; 107 goto timeout;
116 108
117 /* block no one's compliment */ 109 /* block no one's compliment */
118 blockNoOnesCompl = read_byte(ttyfd, TIMEOUT); 110 blockNoOnesCompl = read_byte(TIMEOUT);
119 if (blockNoOnesCompl < 0) 111 if (blockNoOnesCompl < 0)
120 goto timeout; 112 goto timeout;
121 113
122 if (blockNo != (255 - blockNoOnesCompl)) { 114 if (blockNo != (255 - blockNoOnesCompl)) {
123 note_error("bad block ones compl"); 115 bb_error_msg("bad block ones compl");
124 goto error; 116 goto error;
125 } 117 }
126 118
127 blockLength = (blockBegin == SOH) ? 128 : 1024; 119 blockLength = (blockBegin == SOH) ? 128 : 1024;
128 120
129 { 121 for (i = 0; i < blockLength; i++) {
130 int i; 122 int cc = read_byte(TIMEOUT);
131 123 if (cc < 0)
132 for (i = 0; i < blockLength; i++) { 124 goto timeout;
133 int cc = read_byte(ttyfd, TIMEOUT); 125 blockBuf[i] = cc;
134 if (cc < 0)
135 goto timeout;
136 blockBuf[i] = cc;
137 }
138 } 126 }
139 127
140 if (docrc) { 128 if (do_crc) {
141 crcHi = read_byte(ttyfd, TIMEOUT); 129 cksum_crc = read_byte(TIMEOUT);
142 if (crcHi < 0) 130 if (cksum_crc < 0)
143 goto timeout; 131 goto timeout;
144 132 cksum_crc = (cksum_crc << 8) | read_byte(TIMEOUT);
145 crcLo = read_byte(ttyfd, TIMEOUT); 133 if (cksum_crc < 0)
146 if (crcLo < 0)
147 goto timeout; 134 goto timeout;
148 } else { 135 } else {
149 cksum = read_byte(ttyfd, TIMEOUT); 136 cksum_crc = read_byte(TIMEOUT);
150 if (cksum < 0) 137 if (cksum_crc < 0)
151 goto timeout; 138 goto timeout;
152 } 139 }
153 140
@@ -156,93 +143,74 @@ static int receive(char *error_buf, size_t error_buf_size,
156 /* this also ignores the initial block 0 which is */ 143 /* this also ignores the initial block 0 which is */
157 /* meta data. */ 144 /* meta data. */
158 goto next; 145 goto next;
159 } else if (blockNo != (wantBlockNo & 0xff)) { 146 }
160 note_error("unexpected block no, 0x%08x, expecting 0x%08x", blockNo, wantBlockNo); 147 if (blockNo != (wantBlockNo & 0xff)) {
148 bb_error_msg("unexpected block no, 0x%08x, expecting 0x%08x", blockNo, wantBlockNo);
161 goto error; 149 goto error;
162 } 150 }
163 151
164 if (docrc) { 152 expected = 0;
165 int crc = 0; 153 if (do_crc) {
166 int i, j;
167 int expectedCrcHi;
168 int expectedCrcLo;
169
170 for (i = 0; i < blockLength; i++) { 154 for (i = 0; i < blockLength; i++) {
171 crc = crc ^ (int) blockBuf[i] << 8; 155 expected = expected ^ blockBuf[i] << 8;
172 for (j = 0; j < 8; j++) 156 for (j = 0; j < 8; j++) {
173 if (crc & 0x8000) 157 if (expected & 0x8000)
174 crc = crc << 1 ^ 0x1021; 158 expected = expected << 1 ^ 0x1021;
175 else 159 else
176 crc = crc << 1; 160 expected = expected << 1;
177 } 161 }
178
179 expectedCrcHi = (crc >> 8) & 0xff;
180 expectedCrcLo = crc & 0xff;
181
182 if ((crcHi != expectedCrcHi) ||
183 (crcLo != expectedCrcLo)) {
184 note_error("crc error, expected 0x%02x 0x%02x, got 0x%02x 0x%02x", expectedCrcHi, expectedCrcLo, crcHi, crcLo);
185 goto error;
186 } 162 }
163 expected &= 0xffff;
187 } else { 164 } else {
188 unsigned char expectedCksum = 0;
189 int i;
190
191 for (i = 0; i < blockLength; i++) 165 for (i = 0; i < blockLength; i++)
192 expectedCksum += blockBuf[i]; 166 expected += blockBuf[i];
193 167 expected &= 0xff;
194 if (cksum != expectedCksum) { 168 }
195 note_error("checksum error, expected 0x%02x, got 0x%02x", expectedCksum, cksum); 169 if (cksum_crc != expected) {
196 goto error; 170 bb_error_msg(do_crc ? "crc error, expected 0x%04x, got 0x%04x"
197 } 171 : "checksum error, expected 0x%02x, got 0x%02x",
172 expected, cksum_crc);
173 goto error;
198 } 174 }
199 175
200 wantBlockNo++; 176 wantBlockNo++;
201 length += blockLength; 177 length += blockLength;
202 178
203 if (full_write(filefd, blockBuf, blockLength) < 0) { 179 errno = 0;
204 note_error("write to file failed: %m"); 180 if (full_write(file_fd, blockBuf, blockLength) != blockLength) {
181 bb_perror_msg("can't write to file");
205 goto fatal; 182 goto fatal;
206 } 183 }
207 184 next:
208 next:
209 errors = 0; 185 errors = 0;
210 nak = ACK; 186 nak = ACK;
211 write(ttyfd, &nak, 1); 187 full_write(write_fd, &nak, 1);
212 continue; 188 continue;
213 189 error:
214 error: 190 timeout:
215 timeout:
216 errors++; 191 errors++;
217 if (errors == MAXERRORS) { 192 if (errors == MAXERRORS) {
218 /* Abort */ 193 /* Abort */
219 194
220 // if using crc, try again w/o crc 195 /* if were asking for crc, try again w/o crc */
221 if (nak == 'C') { 196 if (nak == 'C') {
222 nak = NAK; 197 nak = NAK;
223 errors = 0; 198 errors = 0;
224 docrc = 0; 199 do_crc = 0;
225 goto timeout; 200 goto timeout;
226 } 201 }
227 202 bb_error_msg("too many errors; giving up");
228 note_error("too many errors; giving up"); 203 fatal:
229 204 /* 5 CAN followed by 5 BS. Don't try too hard... */
230 fatal: 205 safe_write(write_fd, "\030\030\030\030\030\010\010\010\010\010", 10);
231 /* 5 CAN followed by 5 BS */
232 write(ttyfd, "\030\030\030\030\030\010\010\010\010\010", 10);
233 return -1; 206 return -1;
234 } 207 }
235 208
236 /* Flush pending input */ 209 /* Flush pending input */
237 tcflush(ttyfd, TCIFLUSH); 210 tcflush(read_fd, TCIFLUSH);
238
239 write(ttyfd, &nak, 1);
240 }
241
242 done:
243 return length;
244 211
245#undef note_error 212 full_write(write_fd, &nak, 1);
213 } /* for (;;) */
246} 214}
247 215
248static void sigalrm_handler(int ATTRIBUTE_UNUSED signum) 216static void sigalrm_handler(int ATTRIBUTE_UNUSED signum)
@@ -252,40 +220,38 @@ static void sigalrm_handler(int ATTRIBUTE_UNUSED signum)
252int rx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 220int rx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
253int rx_main(int argc, char **argv) 221int rx_main(int argc, char **argv)
254{ 222{
255 char *fn;
256 int ttyfd, filefd;
257 struct termios tty, orig_tty;
258 struct sigaction act; 223 struct sigaction act;
224 struct termios tty, orig_tty;
225 int termios_err;
226 int file_fd;
259 int n; 227 int n;
260 char error_buf[256];
261 228
262 if (argc != 2) 229 if (argc != 2)
263 bb_show_usage(); 230 bb_show_usage();
264 231
265 fn = argv[1]; 232 /* Disabled by vda:
266 ttyfd = xopen(CURRENT_TTY, O_RDWR); 233 * why we can't receive from stdin? Why we *require*
267 filefd = xopen(fn, O_RDWR|O_CREAT|O_TRUNC); 234 * controlling tty?? */
268 235 /*read_fd = xopen(CURRENT_TTY, O_RDWR);*/
269 if (tcgetattr(ttyfd, &tty) < 0) 236 file_fd = xopen(argv[1], O_RDWR|O_CREAT|O_TRUNC);
270 bb_perror_msg_and_die("tcgetattr"); 237
271 238 termios_err = tcgetattr(read_fd, &tty);
272 orig_tty = tty; 239 if (termios_err == 0) {
273 240 orig_tty = tty;
274 cfmakeraw(&tty); 241 cfmakeraw(&tty);
275 tcsetattr(ttyfd, TCSAFLUSH, &tty); 242 tcsetattr(read_fd, TCSAFLUSH, &tty);
243 }
276 244
245 /* No SA_RESTART: we want ALRM to interrupt read() */
277 memset(&act, 0, sizeof(act)); 246 memset(&act, 0, sizeof(act));
278 act.sa_handler = sigalrm_handler; 247 act.sa_handler = sigalrm_handler;
279 sigaction(SIGALRM, &act, 0); 248 sigaction(SIGALRM, &act, NULL);
280
281 n = receive(error_buf, sizeof(error_buf), ttyfd, filefd);
282
283 close(filefd);
284
285 tcsetattr(ttyfd, TCSAFLUSH, &orig_tty);
286 249
287 if (n < 0) 250 n = receive(file_fd);
288 bb_error_msg_and_die("\nreceive failed:\n %s", error_buf);
289 251
290 fflush_stdout_and_exit(EXIT_SUCCESS); 252 if (termios_err == 0)
253 tcsetattr(read_fd, TCSAFLUSH, &orig_tty);
254 if (ENABLE_FEATURE_CLEAN_UP)
255 close(file_fd);
256 fflush_stdout_and_exit(n >= 0);
291} 257}
diff --git a/networking/inetd.c b/networking/inetd.c
index 8a4c9fbf6..463c7cfcf 100644
--- a/networking/inetd.c
+++ b/networking/inetd.c
@@ -3,6 +3,7 @@
3/* $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $ */ 3/* $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $ */
4/* $NetBSD: inetd.c,v 1.11 1996/02/22 11:14:41 mycroft Exp $ */ 4/* $NetBSD: inetd.c,v 1.11 1996/02/22 11:14:41 mycroft Exp $ */
5/* Busybox port by Vladimir Oleynik (C) 2001-2005 <dzo@simtreas.ru> */ 5/* Busybox port by Vladimir Oleynik (C) 2001-2005 <dzo@simtreas.ru> */
6/* IPv6 support, many bug fixes by Denys Vlasenko (c) 2008 */
6/* 7/*
7 * Copyright (c) 1983,1991 The Regents of the University of California. 8 * Copyright (c) 1983,1991 The Regents of the University of California.
8 * All rights reserved. 9 * All rights reserved.
@@ -38,21 +39,17 @@
38 39
39/* Inetd - Internet super-server 40/* Inetd - Internet super-server
40 * 41 *
41 * This program invokes all internet services as needed. 42 * This program invokes configured services when a connection
42 * connection-oriented services are invoked each time a 43 * from a peer is established or a datagram arrives.
44 * Connection-oriented services are invoked each time a
43 * connection is made, by creating a process. This process 45 * connection is made, by creating a process. This process
44 * is passed the connection as file descriptor 0 and is 46 * is passed the connection as file descriptor 0 and is
45 * expected to do a getpeername to find out the source host 47 * expected to do a getpeername to find out peer's host
46 * and port. 48 * and port.
47 *
48 * Datagram oriented services are invoked when a datagram 49 * Datagram oriented services are invoked when a datagram
49 * arrives; a process is created and passed a pending message 50 * arrives; a process is created and passed a pending message
50 * on file descriptor 0. Datagram servers may either connect 51 * on file descriptor 0. peer's address can be obtained
51 * to their peer, freeing up the original socket for inetd 52 * using recvfrom.
52 * to receive further messages on, or "take over the socket",
53 * processing all arriving datagrams and, eventually, timing
54 * out. The first type of server is said to be "multi-threaded";
55 * the second type of server "single-threaded".
56 * 53 *
57 * Inetd uses a configuration file which is read at startup 54 * Inetd uses a configuration file which is read at startup
58 * and, possibly, at some later time in response to a hangup signal. 55 * and, possibly, at some later time in response to a hangup signal.
@@ -60,28 +57,28 @@
60 * order shown below. Continuation lines for an entry must begin with 57 * order shown below. Continuation lines for an entry must begin with
61 * a space or tab. All fields must be present in each entry. 58 * a space or tab. All fields must be present in each entry.
62 * 59 *
63 * service name must be in /etc/services 60 * service_name must be in /etc/services
64 * socket type stream/dgram/raw/rdm/seqpacket 61 * socket_type stream/dgram/raw/rdm/seqpacket
65 * protocol must be in /etc/protocols 62 * protocol must be in /etc/protocols
66 * (usually "tcp" or "udp") 63 * (usually "tcp" or "udp")
67 * wait/nowait[.max] single-threaded/multi-threaded, max # 64 * wait/nowait[.max] single-threaded/multi-threaded, max #
68 * user[.group] or user[:group] user/group to run daemon as 65 * user[.group] or user[:group] user/group to run daemon as
69 * server program full path name 66 * server_program full path name
70 * server program arguments maximum of MAXARGS (20) 67 * server_program_arguments maximum of MAXARGS (20)
71 * 68 *
72 * For RPC services 69 * For RPC services
73 * service name/version must be in /etc/rpc 70 * service_name/version must be in /etc/rpc
74 * socket type stream/dgram/raw/rdm/seqpacket 71 * socket_type stream/dgram/raw/rdm/seqpacket
75 * rpc/protocol "rpc/tcp" etc 72 * rpc/protocol "rpc/tcp" etc
76 * wait/nowait[.max] single-threaded/multi-threaded 73 * wait/nowait[.max] single-threaded/multi-threaded
77 * user[.group] or user[:group] user to run daemon as 74 * user[.group] or user[:group] user to run daemon as
78 * server program full path name 75 * server_program full path name
79 * server program arguments maximum of MAXARGS (20) 76 * server_program_arguments maximum of MAXARGS (20)
80 * 77 *
81 * For non-RPC services, the "service name" can be of the form 78 * For non-RPC services, the "service name" can be of the form
82 * hostaddress:servicename, in which case the hostaddress is used 79 * hostaddress:servicename, in which case the hostaddress is used
83 * as the host portion of the address to listen on. If hostaddress 80 * as the host portion of the address to listen on. If hostaddress
84 * consists of a single `*' character, INADDR_ANY is used. 81 * consists of a single '*' character, INADDR_ANY is used.
85 * 82 *
86 * A line can also consist of just 83 * A line can also consist of just
87 * hostaddress: 84 * hostaddress:
@@ -102,7 +99,7 @@
102 * one line for any given RPC service, even if the host-address 99 * one line for any given RPC service, even if the host-address
103 * specifiers are different. 100 * specifiers are different.
104 * 101 *
105 * Comment lines are indicated by a `#' in column 1. 102 * Comment lines are indicated by a '#' in column 1.
106 */ 103 */
107 104
108/* inetd rules for passing file descriptors to children 105/* inetd rules for passing file descriptors to children
@@ -133,6 +130,8 @@
133 * tening service socket, and must accept at least one connection request 130 * tening service socket, and must accept at least one connection request
134 * before exiting. Such a server would normally accept and process incoming 131 * before exiting. Such a server would normally accept and process incoming
135 * connection requests until a timeout. 132 * connection requests until a timeout.
133 *
134 * In short: "stream" can be "wait" or "nowait"; "dgram" must be "wait".
136 */ 135 */
137 136
138/* Here's the scoop concerning the user[:group] feature: 137/* Here's the scoop concerning the user[:group] feature:
@@ -152,26 +151,27 @@
152 151
153#include <syslog.h> 152#include <syslog.h>
154#include <sys/un.h> 153#include <sys/un.h>
154
155#include "libbb.h" 155#include "libbb.h"
156 156
157#if ENABLE_FEATURE_INETD_RPC
158#include <rpc/rpc.h>
159#include <rpc/pmap_clnt.h>
160#endif
161
157#if !BB_MMU 162#if !BB_MMU
158/* stream versions of these builtins are forking, 163/* stream version of chargen is forking but not execing,
159 * can't do that (easily) on NOMMU */ 164 * can't do that (easily) on NOMMU */
160#undef ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
161#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 0
162#undef ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 165#undef ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
163#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 0 166#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 0
164#endif 167#endif
165 168
166#if ENABLE_FEATURE_INETD_RPC
167#include <rpc/rpc.h>
168#include <rpc/pmap_clnt.h>
169#endif
170
171#define _PATH_INETDPID "/var/run/inetd.pid" 169#define _PATH_INETDPID "/var/run/inetd.pid"
172 170
173#define CNT_INTERVAL 60 /* servers in CNT_INTERVAL sec. */ 171#define CNT_INTERVAL 60 /* servers in CNT_INTERVAL sec. */
174#define RETRYTIME (60*10) /* retry after bind or server fail */ 172#define RETRYTIME 60 /* retry after bind or server fail */
173
174// TODO: explain, or get rid of setrlimit games
175 175
176#ifndef RLIMIT_NOFILE 176#ifndef RLIMIT_NOFILE
177#define RLIMIT_NOFILE RLIMIT_OFILE 177#define RLIMIT_NOFILE RLIMIT_OFILE
@@ -209,20 +209,21 @@ typedef struct servtab_t {
209#else 209#else
210#define is_rpc_service(sep) 0 210#define is_rpc_service(sep) 0
211#endif 211#endif
212 pid_t se_wait; /* 0:"nowait", 1:"wait" */ 212 pid_t se_wait; /* 0:"nowait", 1:"wait", >1:"wait" */
213 /* and waiting for this pid */
213 socktype_t se_socktype; /* SOCK_STREAM/DGRAM/RDM/... */ 214 socktype_t se_socktype; /* SOCK_STREAM/DGRAM/RDM/... */
214 family_t se_family; /* AF_UNIX/INET[6] */ 215 family_t se_family; /* AF_UNIX/INET[6] */
215 smallint se_proto_no; /* almost "getprotobyname(se_proto)" */ 216 /* se_proto_no is used by RPC code only... hmm */
217 smallint se_proto_no; /* IPPROTO_TCP/UDP, n/a for AF_UNIX */
216 smallint se_checked; /* looked at during merge */ 218 smallint se_checked; /* looked at during merge */
219 unsigned se_max; /* allowed instances per minute */
220 unsigned se_count; /* number started since se_time */
221 unsigned se_time; /* whem we started counting */
217 char *se_user; /* user name to run as */ 222 char *se_user; /* user name to run as */
218 char *se_group; /* group name to run as, can be NULL */ 223 char *se_group; /* group name to run as, can be NULL */
219#ifdef INETD_BUILTINS_ENABLED 224#ifdef INETD_BUILTINS_ENABLED
220 const struct builtin *se_builtin; /* if built-in, description */ 225 const struct builtin *se_builtin; /* if built-in, description */
221#endif 226#endif
222// TODO: wrong algorithm!!!
223 unsigned se_max; /* max # of instances of this service */
224 unsigned se_count; /* number started since se_time */
225 unsigned se_time; /* start of se_count */
226 struct servtab_t *se_next; 227 struct servtab_t *se_next;
227 len_and_sockaddr *se_lsa; 228 len_and_sockaddr *se_lsa;
228 char *se_program; /* server program */ 229 char *se_program; /* server program */
@@ -231,60 +232,54 @@ typedef struct servtab_t {
231} servtab_t; 232} servtab_t;
232 233
233#ifdef INETD_BUILTINS_ENABLED 234#ifdef INETD_BUILTINS_ENABLED
234 /* Echo received data */ 235/* Echo received data */
235#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 236#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
236static void echo_stream(int, servtab_t *); 237static void echo_stream(int, servtab_t *);
237static void echo_dg(int, servtab_t *); 238static void echo_dg(int, servtab_t *);
238#endif 239#endif
239 /* Internet /dev/null */ 240/* Internet /dev/null */
240#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 241#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
241static void discard_stream(int, servtab_t *); 242static void discard_stream(int, servtab_t *);
242static void discard_dg(int, servtab_t *); 243static void discard_dg(int, servtab_t *);
243#endif 244#endif
244 /* Return 32 bit time since 1900 */ 245/* Return 32 bit time since 1900 */
245#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 246#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
246static void machtime_stream(int, servtab_t *); 247static void machtime_stream(int, servtab_t *);
247static void machtime_dg(int, servtab_t *); 248static void machtime_dg(int, servtab_t *);
248#endif 249#endif
249 /* Return human-readable time */ 250/* Return human-readable time */
250#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 251#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
251static void daytime_stream(int, servtab_t *); 252static void daytime_stream(int, servtab_t *);
252static void daytime_dg(int, servtab_t *); 253static void daytime_dg(int, servtab_t *);
253#endif 254#endif
254 /* Familiar character generator */ 255/* Familiar character generator */
255#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 256#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
256static void chargen_stream(int, servtab_t *); 257static void chargen_stream(int, servtab_t *);
257static void chargen_dg(int, servtab_t *); 258static void chargen_dg(int, servtab_t *);
258#endif 259#endif
259 260
260struct builtin { 261struct builtin {
261 const char *bi_service; /* internally provided service name */ 262 /* NB: not necessarily NUL terminated */
262 uint8_t bi_fork; /* 1 if stream fn should run in child */ 263 char bi_service7[7]; /* internally provided service name */
263 /* All builtins are "nowait" */ 264 uint8_t bi_fork; /* 1 if stream fn should run in child */
264 /* uint8_t bi_wait; */ /* 1 if should wait for child */
265 void (*bi_stream_fn)(int, servtab_t *); 265 void (*bi_stream_fn)(int, servtab_t *);
266 void (*bi_dgram_fn)(int, servtab_t *); 266 void (*bi_dgram_fn)(int, servtab_t *);
267}; 267};
268 268
269static const struct builtin builtins[] = { 269static const struct builtin builtins[] = {
270#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 270#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
271 /* Echo received data */
272 { "echo", 1, echo_stream, echo_dg }, 271 { "echo", 1, echo_stream, echo_dg },
273#endif 272#endif
274#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 273#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
275 /* Internet /dev/null */
276 { "discard", 1, discard_stream, discard_dg }, 274 { "discard", 1, discard_stream, discard_dg },
277#endif 275#endif
278#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 276#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
279 /* Familiar character generator */
280 { "chargen", 1, chargen_stream, chargen_dg }, 277 { "chargen", 1, chargen_stream, chargen_dg },
281#endif 278#endif
282#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 279#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
283 /* Return 32 bit time since 1900 */
284 { "time", 0, machtime_stream, machtime_dg }, 280 { "time", 0, machtime_stream, machtime_dg },
285#endif 281#endif
286#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 282#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
287 /* Return human-readable time */
288 { "daytime", 0, daytime_stream, daytime_dg }, 283 { "daytime", 0, daytime_stream, daytime_dg },
289#endif 284#endif
290}; 285};
@@ -305,8 +300,8 @@ struct globals {
305 FILE *fconfig; 300 FILE *fconfig;
306 char *default_local_hostname; 301 char *default_local_hostname;
307#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 302#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
308 char *endring; 303 char *end_ring;
309 char *ringpos; 304 char *ring_pos;
310 char ring[128]; 305 char ring[128];
311#endif 306#endif
312 fd_set allsock; 307 fd_set allsock;
@@ -333,8 +328,8 @@ struct BUG_G_too_big {
333#define default_local_hostname (G.default_local_hostname) 328#define default_local_hostname (G.default_local_hostname)
334#define first_ps_byte (G.first_ps_byte ) 329#define first_ps_byte (G.first_ps_byte )
335#define last_ps_byte (G.last_ps_byte ) 330#define last_ps_byte (G.last_ps_byte )
336#define endring (G.endring ) 331#define end_ring (G.end_ring )
337#define ringpos (G.ringpos ) 332#define ring_pos (G.ring_pos )
338#define ring (G.ring ) 333#define ring (G.ring )
339#define allsock (G.allsock ) 334#define allsock (G.allsock )
340#define line (G.line ) 335#define line (G.line )
@@ -357,6 +352,8 @@ static len_and_sockaddr *xzalloc_lsa(int family)
357 int sz; 352 int sz;
358 353
359 sz = sizeof(struct sockaddr_in); 354 sz = sizeof(struct sockaddr_in);
355 if (family == AF_UNIX)
356 sz = sizeof(struct sockaddr_un);
360#if ENABLE_FEATURE_IPV6 357#if ENABLE_FEATURE_IPV6
361 if (family == AF_INET6) 358 if (family == AF_INET6)
362 sz = sizeof(struct sockaddr_in6); 359 sz = sizeof(struct sockaddr_in6);
@@ -367,7 +364,6 @@ static len_and_sockaddr *xzalloc_lsa(int family)
367 return lsa; 364 return lsa;
368} 365}
369 366
370
371static void rearm_alarm(void) 367static void rearm_alarm(void)
372{ 368{
373 if (!alarm_armed) { 369 if (!alarm_armed) {
@@ -660,10 +656,8 @@ static NOINLINE servtab_t *parse_one_line(void)
660 } 656 }
661 657
662 arg = next_word(&cp); 658 arg = next_word(&cp);
663 if (arg == NULL) { 659 if (arg == NULL) /* a blank line. */
664 /* A blank line. */
665 goto more; 660 goto more;
666 }
667 661
668 /* [host:]service socktype proto wait user[:group] prog [args] */ 662 /* [host:]service socktype proto wait user[:group] prog [args] */
669 /* Check for "host:...." line */ 663 /* Check for "host:...." line */
@@ -764,9 +758,9 @@ static NOINLINE servtab_t *parse_one_line(void)
764 } 758 }
765 /* we don't really need getprotobyname()! */ 759 /* we don't really need getprotobyname()! */
766 if (strcmp(arg, "tcp") == 0) 760 if (strcmp(arg, "tcp") == 0)
767 sep->se_proto_no = 6; 761 sep->se_proto_no = IPPROTO_TCP; /* = 6 */
768 if (strcmp(arg, "udp") == 0) 762 if (strcmp(arg, "udp") == 0)
769 sep->se_proto_no = 17; 763 sep->se_proto_no = IPPROTO_UDP; /* = 17 */
770 if (six) 764 if (six)
771 *six = '6'; 765 *six = '6';
772 if (!sep->se_proto_no) /* not tcp/udp?? */ 766 if (!sep->se_proto_no) /* not tcp/udp?? */
@@ -785,7 +779,11 @@ static NOINLINE servtab_t *parse_one_line(void)
785 if (errno) 779 if (errno)
786 goto parse_err; 780 goto parse_err;
787 } 781 }
788 sep->se_wait = (strcmp(arg, "wait") == 0); 782 sep->se_wait = (arg[0] != 'n' || arg[1] != 'o');
783 if (!sep->se_wait) /* "no" seen */
784 arg += 2;
785 if (strcmp(arg, "wait") != 0)
786 goto parse_err;
789 787
790 /* user[:group] prog [args] */ 788 /* user[:group] prog [args] */
791 sep->se_user = xstrdup(next_word(&cp)); 789 sep->se_user = xstrdup(next_word(&cp));
@@ -804,48 +802,56 @@ static NOINLINE servtab_t *parse_one_line(void)
804 if (sep->se_program == NULL) 802 if (sep->se_program == NULL)
805 goto parse_err; 803 goto parse_err;
806#ifdef INETD_BUILTINS_ENABLED 804#ifdef INETD_BUILTINS_ENABLED
807 /* sep->se_builtin = NULL; - done by new_servtab() */
808 if (strcmp(sep->se_program, "internal") == 0 805 if (strcmp(sep->se_program, "internal") == 0
806 && strlen(sep->se_service) <= 7
809 && (sep->se_socktype == SOCK_STREAM 807 && (sep->se_socktype == SOCK_STREAM
810 || sep->se_socktype == SOCK_DGRAM) 808 || sep->se_socktype == SOCK_DGRAM)
811 ) { 809 ) {
812 int i; 810 int i;
813 for (i = 0; i < ARRAY_SIZE(builtins); i++) 811 for (i = 0; i < ARRAY_SIZE(builtins); i++)
814 if (strcmp(builtins[i].bi_service, sep->se_service) == 0) 812 if (strncmp(builtins[i].bi_service7, sep->se_service, 7) == 0)
815 goto found_bi; 813 goto found_bi;
816 bb_error_msg("unknown internal service %s", sep->se_service); 814 bb_error_msg("unknown internal service %s", sep->se_service);
817 goto parse_err; 815 goto parse_err;
818 found_bi: 816 found_bi:
819 sep->se_builtin = &builtins[i]; 817 sep->se_builtin = &builtins[i];
820 sep->se_wait = 0; /* = builtins[i].bi_wait; - always 0 */ 818 /* stream builtins must be "nowait", dgram must be "wait" */
819 if (sep->se_wait != (sep->se_socktype == SOCK_DGRAM))
820 goto parse_err;
821 } 821 }
822#endif 822#endif
823 argc = 0; 823 argc = 0;
824 while ((arg = next_word(&cp)) != NULL && argc < MAXARGV) { 824 while ((arg = next_word(&cp)) != NULL && argc < MAXARGV)
825 sep->se_argv[argc++] = xstrdup(arg); 825 sep->se_argv[argc++] = xstrdup(arg);
826
827 /* catch mixups. "<service> stream udp ..." == wtf */
828 if (sep->se_socktype == SOCK_STREAM) {
829 if (sep->se_proto_no == IPPROTO_UDP)
830 goto parse_err;
831 }
832 if (sep->se_socktype == SOCK_DGRAM) {
833 if (sep->se_proto_no == IPPROTO_TCP)
834 goto parse_err;
835 /* "udp nowait" is a small fork bomb :) */
836 if (!sep->se_wait)
837 goto parse_err;
826 } 838 }
827 /* while (argc <= MAXARGV) */ 839
828 /* sep->se_argv[argc++] = NULL; - done by new_servtab() */ 840 /* check if the hostname specifier is a comma separated list
829 841 * of hostnames. we'll make new entries for each address. */
830 /*
831 * Now that we've processed the entire line, check if the hostname
832 * specifier was a comma separated list of hostnames. If so
833 * we'll make new entries for each address.
834 */
835 while ((hostdelim = strrchr(sep->se_local_hostname, ',')) != NULL) { 842 while ((hostdelim = strrchr(sep->se_local_hostname, ',')) != NULL) {
836 nsep = dup_servtab(sep); 843 nsep = dup_servtab(sep);
837 /* 844 /* NUL terminate the hostname field of the existing entry,
838 * NUL terminate the hostname field of the existing entry, 845 * and make a dup for the new entry. */
839 * and make a dup for the new entry.
840 */
841 *hostdelim++ = '\0'; 846 *hostdelim++ = '\0';
842 nsep->se_local_hostname = xstrdup(hostdelim); 847 nsep->se_local_hostname = xstrdup(hostdelim);
843 nsep->se_next = sep->se_next; 848 nsep->se_next = sep->se_next;
844 sep->se_next = nsep; 849 sep->se_next = nsep;
845 } 850 }
846 851
847 /* Was doing it here: */ 852 /* was doing it here: */
848 /* DNS resolution, create copies for each IP address */ 853 /* DNS resolution, create copies for each IP address */
854 /* IPv6-ization destroyed it :( */
849 855
850 return sep; 856 return sep;
851} 857}
@@ -947,15 +953,9 @@ static void reread_config_file(int sig ATTRIBUTE_UNUSED)
947 switch (sep->se_family) { 953 switch (sep->se_family) {
948 struct sockaddr_un *sun; 954 struct sockaddr_un *sun;
949 case AF_UNIX: 955 case AF_UNIX:
950 /* we have poor infrastructure for AF_UNIX... */ 956 lsa = xzalloc_lsa(AF_UNIX);
951 n = strlen(sep->se_service);
952 if (n > sizeof(sun->sun_path) - 1)
953 n = sizeof(sun->sun_path) - 1;
954 lsa = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_un));
955 lsa->len = sizeof(struct sockaddr_un);
956 sun = (struct sockaddr_un*)&lsa->u.sa; 957 sun = (struct sockaddr_un*)&lsa->u.sa;
957 sun->sun_family = AF_UNIX; 958 safe_strncpy(sun->sun_path, sep->se_service, sizeof(sun->sun_path));
958 strncpy(sun->sun_path, sep->se_service, n);
959 break; 959 break;
960 960
961 default: /* case AF_INET, case AF_INET6 */ 961 default: /* case AF_INET, case AF_INET6 */
@@ -1259,8 +1259,8 @@ int inetd_main(int argc, char **argv)
1259 sep->se_count = 0; 1259 sep->se_count = 0;
1260 } 1260 }
1261 } 1261 }
1262 /* on NOMMU, streamed echo, chargen and discard 1262 /* on NOMMU, streamed chargen
1263 * builtins wouldn't work, but they are 1263 * builtin wouldn't work, but it is
1264 * not allowed on NOMMU (ifdefed out) */ 1264 * not allowed on NOMMU (ifdefed out) */
1265#ifdef INETD_BUILTINS_ENABLED 1265#ifdef INETD_BUILTINS_ENABLED
1266 if (BB_MMU && sep->se_builtin) 1266 if (BB_MMU && sep->se_builtin)
@@ -1311,8 +1311,42 @@ int inetd_main(int argc, char **argv)
1311 continue; /* -> check next fd in fd set */ 1311 continue; /* -> check next fd in fd set */
1312 } 1312 }
1313#endif 1313#endif
1314 /* child. prepare env and exec program */ 1314 /* child */
1315 setsid(); 1315 setsid();
1316#if 0
1317/* This does not work.
1318 * Actually, it _almost_ works. The idea behind it is: child
1319 * can peek at (already received and buffered by kernel) UDP packet,
1320 * and perform connect() on the socket so that it is linked only
1321 * to this peer. But this also affects parent, because descriptors
1322 * are shared after fork() a-la dup(). When parent returns to
1323 * select(), it will see this descriptor attached to the peer (!)
1324 * and likely still readable, will act on it and mess things up
1325 * (can create many copies of same child, etc).
1326 * If child will create new socket instead, then bind() and
1327 * connect() it to peer's address, descriptor aliasing problem
1328 * is solved, but first packet cannot be "transferred" to the new
1329 * socket. It is not a problem if child can account for this,
1330 * but our child will exec - and exec'ed program does not know
1331 * about this "lost packet" problem! Pity... */
1332 /* "nowait" udp[6]. Hmmm... */
1333 if (!sep->se_wait
1334 && sep->se_socktype == SOCK_DGRAM
1335 && sep->se_family != AF_UNIX
1336 ) {
1337 len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family);
1338 /* peek at the packet and remember peer addr */
1339 int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
1340 &lsa->u.sa, &lsa->len);
1341 if (r >= 0)
1342 /* make this socket "connected" to peer addr:
1343 * only packets from this peer will be recv'ed,
1344 * and bare write()/send() will work on it */
1345 connect(ctrl, &lsa->u.sa, lsa->len);
1346 free(lsa);
1347 }
1348#endif
1349 /* prepare env and exec program */
1316 pwd = getpwnam(sep->se_user); 1350 pwd = getpwnam(sep->se_user);
1317 if (pwd == NULL) { 1351 if (pwd == NULL) {
1318 bb_error_msg("%s: no such user", sep->se_user); 1352 bb_error_msg("%s: no such user", sep->se_user);
@@ -1342,8 +1376,8 @@ int inetd_main(int argc, char **argv)
1342 bb_perror_msg("setrlimit"); 1376 bb_perror_msg("setrlimit");
1343 closelog(); 1377 closelog();
1344 xmove_fd(ctrl, 0); 1378 xmove_fd(ctrl, 0);
1345 dup2(0, 1); 1379 xdup2(0, 1);
1346 dup2(0, 2); 1380 xdup2(0, 2);
1347 /* NB: among others, this loop closes listening socket 1381 /* NB: among others, this loop closes listening socket
1348 * for nowait stream children */ 1382 * for nowait stream children */
1349 for (sep2 = serv_list; sep2; sep2 = sep2->se_next) 1383 for (sep2 = serv_list; sep2; sep2 = sep2->se_next)
@@ -1378,6 +1412,8 @@ static void echo_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
1378 } 1412 }
1379#else 1413#else
1380 static const char *const args[] = { "cat", NULL }; 1414 static const char *const args[] = { "cat", NULL };
1415 /* no error messages */
1416 xmove_fd(xopen("/dev/null", O_WRONLY), STDERR_FILENO);
1381 BB_EXECVP("cat", (char**)args); 1417 BB_EXECVP("cat", (char**)args);
1382 _exit(1); 1418 _exit(1);
1383#endif 1419#endif
@@ -1404,8 +1440,16 @@ static void echo_dg(int s, servtab_t *sep)
1404/* ARGSUSED */ 1440/* ARGSUSED */
1405static void discard_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1441static void discard_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
1406{ 1442{
1443#if BB_MMU
1407 while (safe_read(s, line, LINE_SIZE) > 0) 1444 while (safe_read(s, line, LINE_SIZE) > 0)
1408 continue; 1445 continue;
1446#else
1447 static const char *const args[] = { "dd", "of=/dev/null", NULL };
1448 /* no error messages */
1449 xmove_fd(xopen("/dev/null", O_WRONLY), STDERR_FILENO);
1450 BB_EXECVP("dd", (char**)args);
1451 _exit(1);
1452#endif
1409} 1453}
1410/* ARGSUSED */ 1454/* ARGSUSED */
1411static void discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED) 1455static 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)
1418 1462
1419#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 1463#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
1420#define LINESIZ 72 1464#define LINESIZ 72
1421static void initring(void) 1465static void init_ring(void)
1422{ 1466{
1423 int i; 1467 int i;
1424 1468
1425 endring = ring; 1469 end_ring = ring;
1426 for (i = 0; i <= 128; ++i) 1470 for (i = 0; i <= 128; ++i)
1427 if (isprint(i)) 1471 if (isprint(i))
1428 *endring++ = i; 1472 *end_ring++ = i;
1429} 1473}
1430/* Character generator. MMU arches only. */ 1474/* Character generator. MMU arches only. */
1431/* ARGSUSED */ 1475/* ARGSUSED */
@@ -1435,8 +1479,8 @@ static void chargen_stream(int s, servtab_t *sep)
1435 int len; 1479 int len;
1436 char text[LINESIZ + 2]; 1480 char text[LINESIZ + 2];
1437 1481
1438 if (!endring) { 1482 if (!end_ring) {
1439 initring(); 1483 init_ring();
1440 rs = ring; 1484 rs = ring;
1441 } 1485 }
1442 1486
@@ -1444,14 +1488,14 @@ static void chargen_stream(int s, servtab_t *sep)
1444 text[LINESIZ + 1] = '\n'; 1488 text[LINESIZ + 1] = '\n';
1445 rs = ring; 1489 rs = ring;
1446 for (;;) { 1490 for (;;) {
1447 len = endring - rs; 1491 len = end_ring - rs;
1448 if (len >= LINESIZ) 1492 if (len >= LINESIZ)
1449 memmove(text, rs, LINESIZ); 1493 memmove(text, rs, LINESIZ);
1450 else { 1494 else {
1451 memmove(text, rs, len); 1495 memmove(text, rs, len);
1452 memmove(text + len, ring, LINESIZ - len); 1496 memmove(text + len, ring, LINESIZ - len);
1453 } 1497 }
1454 if (++rs == endring) 1498 if (++rs == end_ring)
1455 rs = ring; 1499 rs = ring;
1456 xwrite(s, text, sizeof(text)); 1500 xwrite(s, text, sizeof(text));
1457 } 1501 }
@@ -1469,20 +1513,20 @@ static void chargen_dg(int s, servtab_t *sep)
1469 if (recvfrom(s, text, sizeof(text), MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0) 1513 if (recvfrom(s, text, sizeof(text), MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
1470 return; 1514 return;
1471 1515
1472 if (!endring) { 1516 if (!end_ring) {
1473 initring(); 1517 init_ring();
1474 ringpos = ring; 1518 ring_pos = ring;
1475 } 1519 }
1476 1520
1477 len = endring - ringpos; 1521 len = end_ring - ring_pos;
1478 if (len >= LINESIZ) 1522 if (len >= LINESIZ)
1479 memmove(text, ringpos, LINESIZ); 1523 memmove(text, ring_pos, LINESIZ);
1480 else { 1524 else {
1481 memmove(text, ringpos, len); 1525 memmove(text, ring_pos, len);
1482 memmove(text + len, ring, LINESIZ - len); 1526 memmove(text + len, ring, LINESIZ - len);
1483 } 1527 }
1484 if (++ringpos == endring) 1528 if (++ring_pos == end_ring)
1485 ringpos = ring; 1529 ring_pos = ring;
1486 text[LINESIZ] = '\r'; 1530 text[LINESIZ] = '\r';
1487 text[LINESIZ + 1] = '\n'; 1531 text[LINESIZ + 1] = '\n';
1488 sendto(s, text, sizeof(text), 0, &lsa->u.sa, lsa->len); 1532 sendto(s, text, sizeof(text), 0, &lsa->u.sa, lsa->len);
@@ -1498,7 +1542,7 @@ static void chargen_dg(int s, servtab_t *sep)
1498 * we must add 2208988800 seconds to this figure to make up for 1542 * we must add 2208988800 seconds to this figure to make up for
1499 * some seventy years Bell Labs was asleep. 1543 * some seventy years Bell Labs was asleep.
1500 */ 1544 */
1501static unsigned machtime(void) 1545static uint32_t machtime(void)
1502{ 1546{
1503 struct timeval tv; 1547 struct timeval tv;
1504 1548
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c
index 2ee833e3f..ce4829584 100644
--- a/networking/nc_bloaty.c
+++ b/networking/nc_bloaty.c
@@ -751,6 +751,11 @@ int nc_main(int argc, char **argv)
751 if (option_mask32 & OPT_s) { /* local address */ 751 if (option_mask32 & OPT_s) { /* local address */
752 /* if o_lport is still 0, then we will use random port */ 752 /* if o_lport is still 0, then we will use random port */
753 ouraddr = xhost2sockaddr(str_s, o_lport); 753 ouraddr = xhost2sockaddr(str_s, o_lport);
754#ifdef BLOAT
755 /* prevent spurious "UDP listen needs !0 port" */
756 o_lport = get_nport(ouraddr);
757 o_lport = ntohs(o_lport);
758#endif
754 x = xsocket(ouraddr->u.sa.sa_family, x, 0); 759 x = xsocket(ouraddr->u.sa.sa_family, x, 0);
755 } else { 760 } else {
756 /* We try IPv6, then IPv4, unless addr family is 761 /* We try IPv6, then IPv4, unless addr family is
@@ -771,12 +776,14 @@ int nc_main(int argc, char **argv)
771 setsockopt(netfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf); 776 setsockopt(netfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf);
772#endif 777#endif
773 778
779#ifdef BLOAT
774 if (OPT_l && (option_mask32 & (OPT_u|OPT_l)) == (OPT_u|OPT_l)) { 780 if (OPT_l && (option_mask32 & (OPT_u|OPT_l)) == (OPT_u|OPT_l)) {
775 /* apparently UDP can listen ON "port 0", 781 /* apparently UDP can listen ON "port 0",
776 but that's not useful */ 782 but that's not useful */
777 if (!o_lport) 783 if (!o_lport)
778 bb_error_msg_and_die("UDP listen needs nonzero -p port"); 784 bb_error_msg_and_die("UDP listen needs nonzero -p port");
779 } 785 }
786#endif
780 787
781 FD_SET(0, &ding1); /* stdin *is* initially open */ 788 FD_SET(0, &ding1); /* stdin *is* initially open */
782 if (proggie) { 789 if (proggie) {