aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-03-17 09:10:39 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-03-17 09:10:39 +0000
commitaa9b1828b91bc4b60f1164b7929a6a0ac091419e (patch)
tree31a2278e3998160a7c40ac5882736a2f48768a2d
parent1d42665b6b0571b9fa5d3b10fbf2dd03382f0ba2 (diff)
downloadbusybox-w32-aa9b1828b91bc4b60f1164b7929a6a0ac091419e.tar.gz
busybox-w32-aa9b1828b91bc4b60f1164b7929a6a0ac091419e.tar.bz2
busybox-w32-aa9b1828b91bc4b60f1164b7929a6a0ac091419e.zip
tftpd: new applet (mostly using existing code for tftp)
function old new delta tftp_protocol - 1173 +1173 tftpd_main - 500 +500 tftp_option_get - 102 +102 packed_usage 23650 23662 +12 applet_names 1809 1815 +6 applet_main 1100 1104 +4 applet_nameofs 550 552 +2 tftp_main 302 301 -1 get_nport 32 - -32 tftp 1172 - -1172 ------------------------------------------------------------------------------ (add/remove: 3/2 grow/shrink: 4/1 up/down: 1799/-1205) Total: 594 bytes text data bss dec hex filename 796479 662 7420 804561 c46d1 busybox_old 797153 662 7420 805235 c4973 busybox_unstripped
-rw-r--r--TODO_config_nommu4
-rw-r--r--include/applets.h1
-rw-r--r--include/usage.h8
-rw-r--r--ipsvd/Config.in2
-rw-r--r--ipsvd/tcpudp.c2
-rw-r--r--networking/Config.in23
-rw-r--r--networking/Kbuild1
-rw-r--r--networking/tftp.c334
-rw-r--r--printutils/Config.in2
9 files changed, 274 insertions, 103 deletions
diff --git a/TODO_config_nommu b/TODO_config_nommu
index 8bf7b215c..042f622bb 100644
--- a/TODO_config_nommu
+++ b/TODO_config_nommu
@@ -835,14 +835,14 @@ CONFIG_SOFTLIMIT=y
835# CONFIG_SESTATUS is not set 835# CONFIG_SESTATUS is not set
836 836
837# 837#
838# print support 838# Print Utilities
839# 839#
840CONFIG_LPD=y 840CONFIG_LPD=y
841CONFIG_LPR=y 841CONFIG_LPR=y
842CONFIG_LPQ=y 842CONFIG_LPQ=y
843 843
844# 844#
845# ipsvd utilities 845# ipsvd Utilities
846# 846#
847CONFIG_TCPSVD=y 847CONFIG_TCPSVD=y
848CONFIG_UDPSVD=y 848CONFIG_UDPSVD=y
diff --git a/include/applets.h b/include/applets.h
index d4b6dbeaa..c2a089c69 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -355,6 +355,7 @@ USE_TELNETD(APPLET(telnetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
355USE_TEST(APPLET_NOEXEC(test, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test)) 355USE_TEST(APPLET_NOEXEC(test, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test))
356#if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT 356#if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT
357USE_TFTP(APPLET(tftp, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 357USE_TFTP(APPLET(tftp, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
358USE_TFTPD(APPLET(tftpd, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
358#endif 359#endif
359USE_TIME(APPLET(time, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 360USE_TIME(APPLET(time, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
360USE_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 361USE_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
diff --git a/include/usage.h b/include/usage.h
index 507a52dab..8f563f55e 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -3961,7 +3961,7 @@
3961#define tftp_trivial_usage \ 3961#define tftp_trivial_usage \
3962 "[OPTION]... HOST [PORT]" 3962 "[OPTION]... HOST [PORT]"
3963#define tftp_full_usage \ 3963#define tftp_full_usage \
3964 "Transfer a file from/to tftp server using \"octet\" mode\n" \ 3964 "Transfer a file from/to tftp server\n" \
3965 "\nOptions:" \ 3965 "\nOptions:" \
3966 "\n -l FILE Local FILE" \ 3966 "\n -l FILE Local FILE" \
3967 "\n -r FILE Remote FILE" \ 3967 "\n -r FILE Remote FILE" \
@@ -3974,6 +3974,12 @@
3974 USE_FEATURE_TFTP_BLOCKSIZE( \ 3974 USE_FEATURE_TFTP_BLOCKSIZE( \
3975 "\n -b SIZE Transfer blocks of SIZE octets" \ 3975 "\n -b SIZE Transfer blocks of SIZE octets" \
3976 ) 3976 )
3977
3978#define tftpd_trivial_usage \
3979 "[DIR]"
3980#define tftpd_full_usage \
3981 "Transfer a file on request from a tftp client" \
3982
3977#define time_trivial_usage \ 3983#define time_trivial_usage \
3978 "[OPTION]... COMMAND [ARGS...]" 3984 "[OPTION]... COMMAND [ARGS...]"
3979#define time_full_usage \ 3985#define time_full_usage \
diff --git a/ipsvd/Config.in b/ipsvd/Config.in
index 8522ef9eb..0cb8c62de 100644
--- a/ipsvd/Config.in
+++ b/ipsvd/Config.in
@@ -3,7 +3,7 @@
3# see scripts/kbuild/config-language.txt. 3# see scripts/kbuild/config-language.txt.
4# 4#
5 5
6menu "ipsvd utilities" 6menu "ipsvd Utilities"
7 7
8config TCPSVD 8config TCPSVD
9 bool "tcpsvd" 9 bool "tcpsvd"
diff --git a/ipsvd/tcpudp.c b/ipsvd/tcpudp.c
index 8f6616fe0..729b7bca9 100644
--- a/ipsvd/tcpudp.c
+++ b/ipsvd/tcpudp.c
@@ -322,7 +322,7 @@ int tcpudpsvd_main(int argc ATTRIBUTE_UNUSED, char **argv)
322 /* In case recv_from_to won't be able to recover local addr. 322 /* In case recv_from_to won't be able to recover local addr.
323 * Also sets port - recv_from_to is unable to do it. */ 323 * Also sets port - recv_from_to is unable to do it. */
324 local = *lsa; 324 local = *lsa;
325 conn = recv_from_to(sock, NULL, 0, MSG_DONTWAIT | MSG_PEEK, 325 conn = recv_from_to(sock, NULL, 0, MSG_PEEK,
326 &remote.u.sa, &local.u.sa, sa_len); 326 &remote.u.sa, &local.u.sa, sa_len);
327 } 327 }
328 sig_block(SIGCHLD); 328 sig_block(SIGCHLD);
diff --git a/networking/Config.in b/networking/Config.in
index 3c53c1115..729cca148 100644
--- a/networking/Config.in
+++ b/networking/Config.in
@@ -774,28 +774,41 @@ config TFTP
774 is usually used for simple, small transfers such as a root image 774 is usually used for simple, small transfers such as a root image
775 for a network-enabled bootloader. 775 for a network-enabled bootloader.
776 776
777config TFTPD
778 bool "tftpd"
779 default n
780 help
781 This enables the Trivial File Transfer Protocol server program.
782 It expects that stdin is a datagram socket and a packet
783 is already pending on it. It will exit after one transfer.
784 In other words: it should be run from inetd in nowait mode,
785 or from udpsvd. Example: "udpsvd -E 0 69 tftpd DIR"
786
777config FEATURE_TFTP_GET 787config FEATURE_TFTP_GET
778 bool "Enable \"get\" command" 788 bool "Enable \"get\" command"
779 default y 789 default y
780 depends on TFTP 790 depends on TFTP || TFTPD
781 help 791 help
782 Add support for the GET command within the TFTP client. This allows 792 Add support for the GET command within the TFTP client. This allows
783 a client to retrieve a file from a TFTP server. 793 a client to retrieve a file from a TFTP server.
794 Also enable upload support in tftpd, if tftpd is selected.
784 795
785config FEATURE_TFTP_PUT 796config FEATURE_TFTP_PUT
786 bool "Enable \"put\" command" 797 bool "Enable \"put\" command"
787 default y 798 default y
788 depends on TFTP 799 depends on TFTP || TFTPD
789 help 800 help
790 Add support for the PUT command within the TFTP client. This allows 801 Add support for the PUT command within the TFTP client. This allows
791 a client to transfer a file to a TFTP server. 802 a client to transfer a file to a TFTP server.
803 Also enable download support in tftpd, if tftpd is selected.
792 804
793config FEATURE_TFTP_BLOCKSIZE 805config FEATURE_TFTP_BLOCKSIZE
794 bool "Enable \"blocksize\" command" 806 bool "Enable \"blksize\" protocol option"
795 default n 807 default n
796 depends on TFTP 808 depends on TFTP || TFTPD
797 help 809 help
798 Allow the client to specify the desired block size for transfers. 810 Allow tftp to specify block size, and tftpd to understand
811 "blksize" option.
799 812
800config DEBUG_TFTP 813config DEBUG_TFTP
801 bool "Enable debug" 814 bool "Enable debug"
diff --git a/networking/Kbuild b/networking/Kbuild
index 44258e9b0..bf9ba9960 100644
--- a/networking/Kbuild
+++ b/networking/Kbuild
@@ -35,6 +35,7 @@ lib-$(CONFIG_SLATTACH) += slattach.o
35lib-$(CONFIG_TELNET) += telnet.o 35lib-$(CONFIG_TELNET) += telnet.o
36lib-$(CONFIG_TELNETD) += telnetd.o 36lib-$(CONFIG_TELNETD) += telnetd.o
37lib-$(CONFIG_TFTP) += tftp.o 37lib-$(CONFIG_TFTP) += tftp.o
38lib-$(CONFIG_TFTPD) += tftp.o
38lib-$(CONFIG_TRACEROUTE) += traceroute.o 39lib-$(CONFIG_TRACEROUTE) += traceroute.o
39lib-$(CONFIG_VCONFIG) += vconfig.o 40lib-$(CONFIG_VCONFIG) += vconfig.o
40lib-$(CONFIG_WGET) += wget.o 41lib-$(CONFIG_WGET) += wget.o
diff --git a/networking/tftp.c b/networking/tftp.c
index 187261568..23a24139b 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -2,7 +2,7 @@
2/* ------------------------------------------------------------------------- 2/* -------------------------------------------------------------------------
3 * tftp.c 3 * tftp.c
4 * 4 *
5 * A simple tftp client for busybox. 5 * A simple tftp client/server for busybox.
6 * Tries to follow RFC1350. 6 * Tries to follow RFC1350.
7 * Only "octet" mode supported. 7 * Only "octet" mode supported.
8 * Optional blocksize negotiation (RFC2347 + RFC2348) 8 * Optional blocksize negotiation (RFC2347 + RFC2348)
@@ -16,6 +16,8 @@
16 * 16 *
17 * utftp: Copyright (C) 1999 Uwe Ohse <uwe@ohse.de> 17 * utftp: Copyright (C) 1999 Uwe Ohse <uwe@ohse.de>
18 * 18 *
19 * tftpd added by Denys Vlasenko
20 *
19 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 21 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
20 * ------------------------------------------------------------------------- */ 22 * ------------------------------------------------------------------------- */
21 23
@@ -46,7 +48,7 @@
46#define CMD_PUT(cmd) 1 48#define CMD_PUT(cmd) 1
47#else 49#else
48#define USE_GETPUT(...) __VA_ARGS__ 50#define USE_GETPUT(...) __VA_ARGS__
49/* masks coming from getpot32 */ 51/* masks coming from getopt32 */
50#define CMD_GET(cmd) ((cmd) & 1) 52#define CMD_GET(cmd) ((cmd) & 1)
51#define CMD_PUT(cmd) ((cmd) & 2) 53#define CMD_PUT(cmd) ((cmd) & 2)
52#endif 54#endif
@@ -64,14 +66,12 @@ static int tftp_blocksize_check(int blocksize, int bufsize)
64 * but our implementation makes it impossible 66 * but our implementation makes it impossible
65 * to use blocksizes smaller than 22 octets. 67 * to use blocksizes smaller than 22 octets.
66 */ 68 */
67
68 if ((bufsize && (blocksize > bufsize)) 69 if ((bufsize && (blocksize > bufsize))
69 || (blocksize < 8) || (blocksize > 65564) 70 || (blocksize < 24) || (blocksize > 65564)
70 ) { 71 ) {
71 bb_error_msg("bad blocksize"); 72 bb_error_msg("bad blocksize");
72 return 0; 73 return 0;
73 } 74 }
74
75 return blocksize; 75 return blocksize;
76} 76}
77 77
@@ -81,8 +81,11 @@ static char *tftp_option_get(char *buf, int len, const char *option)
81 int opt_found = 0; 81 int opt_found = 0;
82 int k; 82 int k;
83 83
84 /* buf points to:
85 * "opt_name<NUL>opt_val<NUL>opt_name2<NUL>opt_val2<NUL>..." */
86
84 while (len > 0) { 87 while (len > 0) {
85 /* Make sure the options are terminated correctly */ 88 /* Make sure options are terminated correctly */
86 for (k = 0; k < len; k++) { 89 for (k = 0; k < len; k++) {
87 if (buf[k] == '\0') { 90 if (buf[k] == '\0') {
88 goto nul_found; 91 goto nul_found;
@@ -90,7 +93,7 @@ static char *tftp_option_get(char *buf, int len, const char *option)
90 } 93 }
91 return NULL; 94 return NULL;
92 nul_found: 95 nul_found:
93 if (opt_val == 0) { 96 if (opt_val == 0) { /* it's "name" part */
94 if (strcasecmp(buf, option) == 0) { 97 if (strcasecmp(buf, option) == 0) {
95 opt_found = 1; 98 opt_found = 1;
96 } 99 }
@@ -109,77 +112,116 @@ static char *tftp_option_get(char *buf, int len, const char *option)
109 112
110#endif 113#endif
111 114
112static int tftp( USE_GETPUT(const int cmd,) 115static int tftp_protocol(
116 USE_GETPUT(int cmd,)
117 len_and_sockaddr *our_lsa,
113 len_and_sockaddr *peer_lsa, 118 len_and_sockaddr *peer_lsa,
114 const char *remotefile, const int localfd, 119 USE_TFTP(const char *remote_file,)
115 unsigned port, int tftp_bufsize) 120 int local_fd,
121 int blocksize)
116{ 122{
123#if !ENABLE_TFTP
124#define remote_file NULL
125#endif
117 struct pollfd pfd[1]; 126 struct pollfd pfd[1];
118#define socketfd (pfd[0].fd) 127#define socket_fd (pfd[0].fd)
119 int len; 128 int len;
120 int send_len; 129 int send_len;
121 USE_FEATURE_TFTP_BLOCKSIZE(smallint want_option_ack = 0;) 130 USE_FEATURE_TFTP_BLOCKSIZE(smallint want_option_ack = 0;)
122 smallint finished = 0; 131 smallint finished = 0;
123 uint16_t opcode; 132 uint16_t opcode;
124 uint16_t block_nr = 1; 133 uint16_t block_nr;
125 uint16_t recv_blk; 134 uint16_t recv_blk;
126 int retries, waittime_ms; 135 int retries, waittime_ms;
136 int tftp_bufsize = blocksize + 4;
127 char *cp; 137 char *cp;
128
129 unsigned org_port;
130 len_and_sockaddr *const from = alloca(LSA_LEN_SIZE + peer_lsa->len);
131
132 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation 138 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
133 * size varies meaning BUFFERS_GO_ON_STACK would fail */ 139 * size varies meaning BUFFERS_GO_ON_STACK would fail */
134 /* We must keep the transmit and receive buffers seperate */ 140 /* We must keep the transmit and receive buffers seperate */
135 /* In case we rcv a garbage pkt and we need to rexmit the last pkt */ 141 /* In case we rcv a garbage pkt and we need to rexmit the last pkt */
136 char *xbuf = xmalloc(tftp_bufsize += 4); 142 char *xbuf = xmalloc(tftp_bufsize);
137 char *rbuf = xmalloc(tftp_bufsize); 143 char *rbuf = xmalloc(tftp_bufsize);
138 144
139 port = org_port = htons(port); 145 socket_fd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0);
146 setsockopt_reuseaddr(socket_fd);
140 147
141 socketfd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0); 148 if (!ENABLE_TFTP || our_lsa) {
149 /* tftpd */
150 block_nr = 0;
142 151
143 /* build opcode */ 152 /* Create a socket which is:
144 opcode = TFTP_WRQ; 153 * 1. bound to IP:port peer sent 1st datagram to,
145 if (CMD_GET(cmd)) { 154 * 2. connected to peer's IP:port
146 opcode = TFTP_RRQ; 155 * This way we will answer from the IP:port peer
147 } 156 * expects, will not get any other packets on
148 cp = xbuf + 2; 157 * the socket, and also plain read/write will work. */
149 /* add filename and mode */ 158 xbind(socket_fd, &our_lsa->u.sa, our_lsa->len);
150 /* fill in packet if the filename fits into xbuf */ 159 xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len);
151 len = strlen(remotefile) + 1;
152 if (2 + len + sizeof("octet") >= tftp_bufsize) {
153 bb_error_msg("remote filename is too long");
154 goto ret;
155 }
156 strcpy(cp, remotefile);
157 cp += len;
158 /* add "mode" part of the package */
159 strcpy(cp, "octet");
160 cp += sizeof("octet");
161 160
162#if ENABLE_FEATURE_TFTP_BLOCKSIZE 161#if ENABLE_FEATURE_TFTP_BLOCKSIZE
163 len = tftp_bufsize - 4; /* data block size */ 162 if (blocksize != TFTP_BLOCKSIZE_DEFAULT) {
164 if (len != TFTP_BLOCKSIZE_DEFAULT) { 163 /* Create and send OACK packet */
165 /* rfc2348 says that 65464 is a max allowed value */ 164 opcode = TFTP_OACK;
166 if ((&xbuf[tftp_bufsize - 1] - cp) < sizeof("blksize NNNNN")) { 165 cp = xbuf + 2;
166 goto add_blksize_opt;
167 }
168 /* else: just fall into while (1) loop below */
169#endif
170 } else {
171 /* tftp */
172 block_nr = 1;
173
174 /* We can't (and don't really need to) bind the socket:
175 * we don't know from which local IP datagrams will be sent,
176 * but kernel will pick the same IP every time (unless routing
177 * table is changed), thus peer will see dgrams consistently
178 * coming from the same IP.
179 * We would like to connect the socket, but since peer's
180 * UDP code can be less perfect than ours, _peer's_ IP:port
181 * in replies may differ from IP:port we used to send
182 * our first packet. We can connect() only when we get
183 * first reply. */
184
185 /* build opcode */
186 opcode = TFTP_WRQ;
187 if (CMD_GET(cmd)) {
188 opcode = TFTP_RRQ;
189 }
190 cp = xbuf + 2;
191 /* add filename and mode */
192 /* fill in packet if the filename fits into xbuf */
193 len = strlen(remote_file) + 1;
194 if (2 + len + sizeof("octet") >= tftp_bufsize) {
167 bb_error_msg("remote filename is too long"); 195 bb_error_msg("remote filename is too long");
168 goto ret; 196 goto ret;
169 } 197 }
170 /* add "blksize", <nul>, blocksize */ 198 strcpy(cp, remote_file);
171 strcpy(cp, "blksize"); 199 cp += len;
172 cp += sizeof("blksize"); 200 /* add "mode" part of the package */
173 cp += snprintf(cp, 6, "%d", len) + 1; 201 strcpy(cp, "octet");
174 want_option_ack = 1; 202 cp += sizeof("octet");
175 } 203
204#if ENABLE_FEATURE_TFTP_BLOCKSIZE
205 if (blocksize != TFTP_BLOCKSIZE_DEFAULT) {
206 /* rfc2348 says that 65464 is a max allowed value */
207 if ((&xbuf[tftp_bufsize - 1] - cp) < sizeof("blksize NNNNN")) {
208 bb_error_msg("remote filename is too long");
209 goto ret;
210 }
211 want_option_ack = 1;
212 add_blksize_opt:
213 /* add "blksize", <nul>, blocksize, <nul> */
214 strcpy(cp, "blksize");
215 cp += sizeof("blksize");
216 cp += snprintf(cp, 6, "%d", blocksize) + 1;
217 }
176#endif 218#endif
177 /* First packet is built, so skip packet generation */ 219 /* First packet is built, so skip packet generation */
178 goto send_pkt; 220 goto send_pkt;
221 }
179 222
180 /* Using mostly goto's - continue/break will be less clear 223 /* Using mostly goto's - continue/break will be less clear
181 * in where we actually jump to */ 224 * in where we actually jump to */
182
183 while (1) { 225 while (1) {
184 /* Build ACK or DATA */ 226 /* Build ACK or DATA */
185 cp = xbuf + 2; 227 cp = xbuf + 2;
@@ -189,7 +231,7 @@ static int tftp( USE_GETPUT(const int cmd,)
189 opcode = TFTP_ACK; 231 opcode = TFTP_ACK;
190 if (CMD_PUT(cmd)) { 232 if (CMD_PUT(cmd)) {
191 opcode = TFTP_DATA; 233 opcode = TFTP_DATA;
192 len = full_read(localfd, cp, tftp_bufsize - 4); 234 len = full_read(local_fd, cp, tftp_bufsize - 4);
193 if (len < 0) { 235 if (len < 0) {
194 bb_perror_msg(bb_msg_read_error); 236 bb_perror_msg(bb_msg_read_error);
195 goto ret; 237 goto ret;
@@ -216,36 +258,36 @@ static int tftp( USE_GETPUT(const int cmd,)
216 fprintf(stderr, "%02x ", (unsigned char) *cp); 258 fprintf(stderr, "%02x ", (unsigned char) *cp);
217 fprintf(stderr, "\n"); 259 fprintf(stderr, "\n");
218#endif 260#endif
219 xsendto(socketfd, xbuf, send_len, &peer_lsa->u.sa, peer_lsa->len); 261 xsendto(socket_fd, xbuf, send_len, &peer_lsa->u.sa, peer_lsa->len);
220 /* Was it final ACK? then exit */ 262 /* Was it final ACK? then exit */
221 if (finished && (opcode == TFTP_ACK)) 263 if (finished && (opcode == TFTP_ACK))
222 goto ret; 264 goto ret;
223 265
224 recv_again: 266 recv_again:
225 /* Receive packet */ 267 /* Receive packet */
226 /*pfd[0].fd = socketfd;*/ 268 /*pfd[0].fd = socket_fd;*/
227 pfd[0].events = POLLIN; 269 pfd[0].events = POLLIN;
228 switch (safe_poll(pfd, 1, waittime_ms)) { 270 switch (safe_poll(pfd, 1, waittime_ms)) {
229 unsigned from_port;
230 case 1: 271 case 1:
231 from->len = peer_lsa->len; 272 if (!our_lsa) {
232 memset(&from->u.sa, 0, peer_lsa->len); 273 /* tftp (not tftpd!) receiving 1st packet */
233 len = recvfrom(socketfd, rbuf, tftp_bufsize, 0, 274 our_lsa = ((void*)(ptrdiff_t)-1); /* not NULL */
234 &from->u.sa, &from->len); 275 len = recvfrom(socket_fd, rbuf, tftp_bufsize, 0,
276 &peer_lsa->u.sa, &peer_lsa->len);
277 /* Our first dgram went to port 69
278 * but reply may come from different one.
279 * Remember and use this new port (and IP) */
280 if (len >= 0)
281 xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len);
282 } else {
283 /* tftpd, or not the very first packet:
284 * socket is connect()ed, can just read from it. */
285 len = safe_read(socket_fd, rbuf, tftp_bufsize);
286 }
235 if (len < 0) { 287 if (len < 0) {
236 bb_perror_msg("recvfrom"); 288 bb_perror_msg("read");
237 goto ret; 289 goto ret;
238 } 290 }
239 from_port = get_nport(&from->u.sa);
240 if (port == org_port) {
241 /* Our first query went to port 69
242 * but reply will come from different one.
243 * Remember and use this new port */
244 port = from_port;
245 set_nport(peer_lsa, from_port);
246 }
247 if (port != from_port)
248 goto recv_again;
249 goto process_pkt; 291 goto process_pkt;
250 case 0: 292 case 0:
251 retries--; 293 retries--;
@@ -316,7 +358,7 @@ static int tftp( USE_GETPUT(const int cmd,)
316 /*static const uint16_t error_8[2] = { htons(TFTP_ERROR), htons(8) };*/ 358 /*static const uint16_t error_8[2] = { htons(TFTP_ERROR), htons(8) };*/
317 /* thus we open-code big-endian layout */ 359 /* thus we open-code big-endian layout */
318 static const uint8_t error_8[4] = { 0,TFTP_ERROR, 0,8 }; 360 static const uint8_t error_8[4] = { 0,TFTP_ERROR, 0,8 };
319 xsendto(socketfd, error_8, 4, &peer_lsa->u.sa, peer_lsa->len); 361 xsendto(socket_fd, error_8, 4, &peer_lsa->u.sa, peer_lsa->len);
320 bb_error_msg("server proposes bad blksize %d, exiting", blksize); 362 bb_error_msg("server proposes bad blksize %d, exiting", blksize);
321 goto ret; 363 goto ret;
322 } 364 }
@@ -345,7 +387,7 @@ static int tftp( USE_GETPUT(const int cmd,)
345 387
346 if (CMD_GET(cmd) && (opcode == TFTP_DATA)) { 388 if (CMD_GET(cmd) && (opcode == TFTP_DATA)) {
347 if (recv_blk == block_nr) { 389 if (recv_blk == block_nr) {
348 len = full_write(localfd, &rbuf[4], len - 4); 390 len = full_write(local_fd, &rbuf[4], len - 4);
349 if (len < 0) { 391 if (len < 0) {
350 bb_perror_msg(bb_msg_write_error); 392 bb_perror_msg(bb_msg_write_error);
351 goto ret; 393 goto ret;
@@ -363,7 +405,7 @@ static int tftp( USE_GETPUT(const int cmd,)
363 } 405 }
364 406
365 if (CMD_PUT(cmd) && (opcode == TFTP_ACK)) { 407 if (CMD_PUT(cmd) && (opcode == TFTP_ACK)) {
366 /* did server ACK our last DATA pkt? */ 408 /* did peer ACK our last DATA pkt? */
367 if (recv_blk == (uint16_t) (block_nr - 1)) { 409 if (recv_blk == (uint16_t) (block_nr - 1)) {
368 if (finished) 410 if (finished)
369 goto ret; 411 goto ret;
@@ -381,25 +423,27 @@ static int tftp( USE_GETPUT(const int cmd,)
381 * See: 423 * See:
382 * http://en.wikipedia.org/wiki/Sorcerer's_Apprentice_Syndrome 424 * http://en.wikipedia.org/wiki/Sorcerer's_Apprentice_Syndrome
383 */ 425 */
384 } 426 } /* end of "while (1)" */
385 ret: 427 ret:
386 if (ENABLE_FEATURE_CLEAN_UP) { 428 if (ENABLE_FEATURE_CLEAN_UP) {
387 close(socketfd); 429 close(socket_fd);
388 free(xbuf); 430 free(xbuf);
389 free(rbuf); 431 free(rbuf);
390 } 432 }
391 return finished == 0; /* returns 1 on failure */ 433 return finished == 0; /* returns 1 on failure */
392} 434}
393 435
436#if ENABLE_TFTP
437
394int tftp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 438int tftp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
395int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv) 439int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv)
396{ 440{
397 len_and_sockaddr *peer_lsa; 441 len_and_sockaddr *peer_lsa;
398 const char *localfile = NULL; 442 const char *local_file = NULL;
399 const char *remotefile = NULL; 443 const char *remote_file = NULL;
400 int port; 444 int port;
401 USE_GETPUT(int cmd;) 445 USE_GETPUT(int cmd;)
402 int fd = -1; 446 int local_fd;
403 int flags = 0; 447 int flags = 0;
404 int result; 448 int result;
405 int blocksize = TFTP_BLOCKSIZE_DEFAULT; 449 int blocksize = TFTP_BLOCKSIZE_DEFAULT;
@@ -412,7 +456,7 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv)
412 USE_GETPUT(cmd =) getopt32(argv, 456 USE_GETPUT(cmd =) getopt32(argv,
413 USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p") 457 USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p")
414 "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"), 458 "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"),
415 &localfile, &remotefile 459 &local_file, &remote_file
416 USE_FEATURE_TFTP_BLOCKSIZE(, &blocksize)); 460 USE_FEATURE_TFTP_BLOCKSIZE(, &blocksize));
417 argv += optind; 461 argv += optind;
418 462
@@ -425,36 +469,142 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv)
425 return EXIT_FAILURE; 469 return EXIT_FAILURE;
426#endif 470#endif
427 471
428 if (!localfile) 472 if (!local_file)
429 localfile = remotefile; 473 local_file = remote_file;
430 if (!remotefile) 474 if (!remote_file)
431 remotefile = localfile; 475 remote_file = local_file;
432 /* Error if filename or host is not known */ 476 /* Error if filename or host is not known */
433 if (!remotefile || !argv[0]) 477 if (!remote_file || !argv[0])
434 bb_show_usage(); 478 bb_show_usage();
435 479
436 fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO; 480 local_fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO;
437 if (!LONE_DASH(localfile)) { 481 if (!LONE_DASH(local_file)) {
438 fd = xopen(localfile, flags); 482 local_fd = xopen(local_file, flags);
439 } 483 }
440 484
441 port = bb_lookup_port(argv[1], "udp", 69); 485 port = bb_lookup_port(argv[1], "udp", 69);
442 peer_lsa = xhost2sockaddr(argv[0], port); 486 peer_lsa = xhost2sockaddr(argv[0], port);
443 487
444#if ENABLE_DEBUG_TFTP 488#if ENABLE_DEBUG_TFTP
445 fprintf(stderr, "using server '%s', remotefile '%s', localfile '%s'\n", 489 fprintf(stderr, "using server '%s', remote_file '%s', local_file '%s'\n",
446 xmalloc_sockaddr2dotted(&peer_lsa->u.sa), 490 xmalloc_sockaddr2dotted(&peer_lsa->u.sa),
447 remotefile, localfile); 491 remote_file, local_file);
448#endif 492#endif
449 493
450 result = tftp( USE_GETPUT(cmd,) peer_lsa, remotefile, fd, port, blocksize); 494 result = tftp_protocol(
495 USE_GETPUT(cmd,)
496 NULL /* our_lsa*/,
497 peer_lsa,
498 remote_file, local_fd, blocksize);
451 499
452 if (ENABLE_FEATURE_CLEAN_UP) 500 if (ENABLE_FEATURE_CLEAN_UP)
453 close(fd); 501 close(local_fd);
454 if (result != EXIT_SUCCESS && !LONE_DASH(localfile) && CMD_GET(cmd)) { 502 if (result != EXIT_SUCCESS && !LONE_DASH(local_file) && CMD_GET(cmd)) {
455 unlink(localfile); 503 unlink(local_file);
456 } 504 }
457 return result; 505 return result;
458} 506}
459 507
508#endif /* ENABLE_TFTP */
509
510#if ENABLE_TFTPD
511
512/* TODO: libbb candidate? */
513static len_and_sockaddr *get_sock_lsa(int s)
514{
515 len_and_sockaddr *lsa;
516 socklen_t len = 0;
517
518 if (getsockname(s, NULL, &len) != 0)
519 return NULL;
520 lsa = xzalloc(LSA_LEN_SIZE + len);
521 lsa->len = len;
522 getsockname(s, &lsa->u.sa, &lsa->len);
523 return lsa;
524}
525
526int tftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
527int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
528{
529 struct stat statbuf;
530 char block_buf[TFTP_BLOCKSIZE_DEFAULT];
531 len_and_sockaddr *our_lsa;
532 len_and_sockaddr *peer_lsa;
533 char *filename, *mode, *opt_str;
534 int result, opcode, cmd, req_modebits, open_mode, local_fd, blksize;
535
536 our_lsa = get_sock_lsa(STDIN_FILENO);
537 if (!our_lsa)
538 bb_perror_msg_and_die("stdin is not a socket");
539 peer_lsa = xzalloc(LSA_LEN_SIZE + our_lsa->len);
540 peer_lsa->len = our_lsa->len;
541
542 if (argv[1])
543 xchdir(argv[1]);
544
545 result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf),
546 0 /* flags */,
547 &peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len);
548
549 opcode = ntohs(*(uint16_t*)block_buf);
550 if (result < 4 || result >= sizeof(block_buf)
551 || block_buf[result-1] != '\0'
552 || (opcode != TFTP_RRQ && opcode != TFTP_WRQ)
553 ) {
554 bb_error_msg_and_die("malformed packet");
555 }
556 filename = block_buf + 2;
557 if (filename[0] == '.' || strstr(filename, "/.")) {
558 bb_error_msg_and_die("dot in filename");
559 }
560 mode = filename + strlen(filename) + 1;
561 if (mode >= block_buf + sizeof(block_buf)
562 || strcmp(mode, "octet") != 0
563 ) {
564 bb_error_msg_and_die("malformed packet");
565 }
566 blksize = TFTP_BLOCKSIZE_DEFAULT;
567#if ENABLE_FEATURE_TFTP_BLOCKSIZE
568 opt_str = mode + 6;
569 if (opt_str < block_buf + sizeof(block_buf)) {
570 char *res = tftp_option_get(opt_str, block_buf + sizeof(block_buf) - opt_str, "blksize");
571 if (res) {
572 int sz = xatoi_u(res);
573 if (tftp_blocksize_check(sz, 0))
574 blksize = sz;
575 }
576 }
577#endif
578 xstat(filename, &statbuf);
579 /* if opcode == TFTP_WRQ: */
580 cmd = 1; /* CMD_GET: we will receive file's data */
581 req_modebits = 0222; /* writable by anyone */
582 open_mode = O_WRONLY | O_TRUNC;
583 if (opcode == TFTP_RRQ) {
584 cmd = 2; /* CMD_PUT */
585 req_modebits = 0444; /* readable by anyone */
586 open_mode = O_RDONLY;
587 }
588 if (!S_ISREG(statbuf.st_mode)
589 || (statbuf.st_mode & req_modebits) != req_modebits
590 ) {
591 bb_error_msg_and_die("access to '%s' is denied", filename);
592 }
593 local_fd = xopen(filename, open_mode);
594
595 close(STDIN_FILENO); /* close old, possibly wildcard socket */
596 /* tftp_protocol() will create new one, bound to particular local IP */
597 result = tftp_protocol(
598 USE_GETPUT(cmd,)
599 our_lsa, peer_lsa,
600 USE_TFTP(NULL /*remote_file*/,)
601 local_fd,
602 blksize
603 );
604
605 return result;
606}
607
608#endif /* ENABLE_TFTPD */
609
460#endif /* ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT */ 610#endif /* ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT */
diff --git a/printutils/Config.in b/printutils/Config.in
index e5f18646c..e0bf71b07 100644
--- a/printutils/Config.in
+++ b/printutils/Config.in
@@ -1,4 +1,4 @@
1menu "print support" 1menu "Print Utilities"
2 2
3config LPD 3config LPD
4 bool "lpd" 4 bool "lpd"