svn commit: trunk/busybox: include ipsvd networking printutils

vda at busybox.net vda at busybox.net
Mon Mar 17 09:10:40 UTC 2008


Author: vda
Date: 2008-03-17 02:10:39 -0700 (Mon, 17 Mar 2008)
New Revision: 21357

Log:
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



Modified:
   trunk/busybox/TODO_config_nommu
   trunk/busybox/include/applets.h
   trunk/busybox/include/usage.h
   trunk/busybox/ipsvd/Config.in
   trunk/busybox/ipsvd/tcpudp.c
   trunk/busybox/networking/Config.in
   trunk/busybox/networking/Kbuild
   trunk/busybox/networking/tftp.c
   trunk/busybox/printutils/Config.in


Changeset:
Modified: trunk/busybox/TODO_config_nommu
===================================================================
--- trunk/busybox/TODO_config_nommu	2008-03-17 09:09:09 UTC (rev 21356)
+++ trunk/busybox/TODO_config_nommu	2008-03-17 09:10:39 UTC (rev 21357)
@@ -835,14 +835,14 @@
 # CONFIG_SESTATUS is not set
 
 #
-# print support
+# Print Utilities
 #
 CONFIG_LPD=y
 CONFIG_LPR=y
 CONFIG_LPQ=y
 
 #
-# ipsvd utilities
+# ipsvd Utilities
 #
 CONFIG_TCPSVD=y
 CONFIG_UDPSVD=y

Modified: trunk/busybox/include/applets.h
===================================================================
--- trunk/busybox/include/applets.h	2008-03-17 09:09:09 UTC (rev 21356)
+++ trunk/busybox/include/applets.h	2008-03-17 09:10:39 UTC (rev 21357)
@@ -355,6 +355,7 @@
 USE_TEST(APPLET_NOEXEC(test, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test))
 #if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT
 USE_TFTP(APPLET(tftp, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+USE_TFTPD(APPLET(tftpd, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 #endif
 USE_TIME(APPLET(time, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 USE_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_NEVER))

Modified: trunk/busybox/include/usage.h
===================================================================
--- trunk/busybox/include/usage.h	2008-03-17 09:09:09 UTC (rev 21356)
+++ trunk/busybox/include/usage.h	2008-03-17 09:10:39 UTC (rev 21357)
@@ -3961,7 +3961,7 @@
 #define tftp_trivial_usage \
        "[OPTION]... HOST [PORT]"
 #define tftp_full_usage \
-       "Transfer a file from/to tftp server using \"octet\" mode\n" \
+       "Transfer a file from/to tftp server\n" \
      "\nOptions:" \
      "\n	-l FILE	Local FILE" \
      "\n	-r FILE	Remote FILE" \
@@ -3974,6 +3974,12 @@
 	USE_FEATURE_TFTP_BLOCKSIZE( \
      "\n	-b SIZE	Transfer blocks of SIZE octets" \
 	)
+
+#define tftpd_trivial_usage \
+       "[DIR]"
+#define tftpd_full_usage \
+       "Transfer a file on request from a tftp client" \
+
 #define time_trivial_usage \
        "[OPTION]... COMMAND [ARGS...]"
 #define time_full_usage \

Modified: trunk/busybox/ipsvd/Config.in
===================================================================
--- trunk/busybox/ipsvd/Config.in	2008-03-17 09:09:09 UTC (rev 21356)
+++ trunk/busybox/ipsvd/Config.in	2008-03-17 09:10:39 UTC (rev 21357)
@@ -3,7 +3,7 @@
 # see scripts/kbuild/config-language.txt.
 #
 
-menu "ipsvd utilities"
+menu "ipsvd Utilities"
 
 config TCPSVD
 	bool "tcpsvd"

Modified: trunk/busybox/ipsvd/tcpudp.c
===================================================================
--- trunk/busybox/ipsvd/tcpudp.c	2008-03-17 09:09:09 UTC (rev 21356)
+++ trunk/busybox/ipsvd/tcpudp.c	2008-03-17 09:10:39 UTC (rev 21357)
@@ -322,7 +322,7 @@
 		/* In case recv_from_to won't be able to recover local addr.
 		 * Also sets port - recv_from_to is unable to do it. */
 		local = *lsa;
-		conn = recv_from_to(sock, NULL, 0, MSG_DONTWAIT | MSG_PEEK,
+		conn = recv_from_to(sock, NULL, 0, MSG_PEEK,
 				&remote.u.sa, &local.u.sa, sa_len);
 	}
 	sig_block(SIGCHLD);

Modified: trunk/busybox/networking/Config.in
===================================================================
--- trunk/busybox/networking/Config.in	2008-03-17 09:09:09 UTC (rev 21356)
+++ trunk/busybox/networking/Config.in	2008-03-17 09:10:39 UTC (rev 21357)
@@ -774,28 +774,41 @@
 	  is usually used for simple, small transfers such as a root image
 	  for a network-enabled bootloader.
 
+config TFTPD
+	bool "tftpd"
+	default n
+	help
+	  This enables the Trivial File Transfer Protocol server program.
+	  It expects that stdin is a datagram socket and a packet
+	  is already pending on it. It will exit after one transfer.
+	  In other words: it should be run from inetd in nowait mode,
+	  or from udpsvd. Example: "udpsvd -E 0 69 tftpd DIR"
+
 config FEATURE_TFTP_GET
 	bool "Enable \"get\" command"
 	default y
-	depends on TFTP
+	depends on TFTP || TFTPD
 	help
 	  Add support for the GET command within the TFTP client.  This allows
 	  a client to retrieve a file from a TFTP server.
+	  Also enable upload support in tftpd, if tftpd is selected.
 
 config FEATURE_TFTP_PUT
 	bool "Enable \"put\" command"
 	default y
-	depends on TFTP
+	depends on TFTP || TFTPD
 	help
 	  Add support for the PUT command within the TFTP client.  This allows
 	  a client to transfer a file to a TFTP server.
+	  Also enable download support in tftpd, if tftpd is selected.
 
 config FEATURE_TFTP_BLOCKSIZE
-	bool "Enable \"blocksize\" command"
+	bool "Enable \"blksize\" protocol option"
 	default n
-	depends on TFTP
+	depends on TFTP || TFTPD
 	help
-	  Allow the client to specify the desired block size for transfers.
+	  Allow tftp to specify block size, and tftpd to understand
+	  "blksize" option.
 
 config DEBUG_TFTP
 	bool "Enable debug"

Modified: trunk/busybox/networking/Kbuild
===================================================================
--- trunk/busybox/networking/Kbuild	2008-03-17 09:09:09 UTC (rev 21356)
+++ trunk/busybox/networking/Kbuild	2008-03-17 09:10:39 UTC (rev 21357)
@@ -35,6 +35,7 @@
 lib-$(CONFIG_TELNET)       += telnet.o
 lib-$(CONFIG_TELNETD)      += telnetd.o
 lib-$(CONFIG_TFTP)         += tftp.o
+lib-$(CONFIG_TFTPD)        += tftp.o
 lib-$(CONFIG_TRACEROUTE)   += traceroute.o
 lib-$(CONFIG_VCONFIG)      += vconfig.o
 lib-$(CONFIG_WGET)         += wget.o

Modified: trunk/busybox/networking/tftp.c
===================================================================
--- trunk/busybox/networking/tftp.c	2008-03-17 09:09:09 UTC (rev 21356)
+++ trunk/busybox/networking/tftp.c	2008-03-17 09:10:39 UTC (rev 21357)
@@ -2,7 +2,7 @@
 /* -------------------------------------------------------------------------
  * tftp.c
  *
- * A simple tftp client for busybox.
+ * A simple tftp client/server for busybox.
  * Tries to follow RFC1350.
  * Only "octet" mode supported.
  * Optional blocksize negotiation (RFC2347 + RFC2348)
@@ -16,6 +16,8 @@
  *
  * utftp:  Copyright (C) 1999 Uwe Ohse <uwe at ohse.de>
  *
+ * tftpd added by Denys Vlasenko
+ *
  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  * ------------------------------------------------------------------------- */
 
@@ -46,7 +48,7 @@
 #define CMD_PUT(cmd) 1
 #else
 #define USE_GETPUT(...) __VA_ARGS__
-/* masks coming from getpot32 */
+/* masks coming from getopt32 */
 #define CMD_GET(cmd) ((cmd) & 1)
 #define CMD_PUT(cmd) ((cmd) & 2)
 #endif
@@ -64,14 +66,12 @@
 	 * but our implementation makes it impossible
 	 * to use blocksizes smaller than 22 octets.
 	 */
-
 	if ((bufsize && (blocksize > bufsize))
-	 || (blocksize < 8) || (blocksize > 65564)
+	 || (blocksize < 24) || (blocksize > 65564)
 	) {
 		bb_error_msg("bad blocksize");
 		return 0;
 	}
-
 	return blocksize;
 }
 
@@ -81,8 +81,11 @@
 	int opt_found = 0;
 	int k;
 
+	/* buf points to:
+	 * "opt_name<NUL>opt_val<NUL>opt_name2<NUL>opt_val2<NUL>..." */
+
 	while (len > 0) {
-		/* Make sure the options are terminated correctly */
+		/* Make sure options are terminated correctly */
 		for (k = 0; k < len; k++) {
 			if (buf[k] == '\0') {
 				goto nul_found;
@@ -90,7 +93,7 @@
 		}
 		return NULL;
  nul_found:
-		if (opt_val == 0) {
+		if (opt_val == 0) { /* it's "name" part */
 			if (strcasecmp(buf, option) == 0) {
 				opt_found = 1;
 			}
@@ -109,77 +112,116 @@
 
 #endif
 
-static int tftp( USE_GETPUT(const int cmd,)
+static int tftp_protocol(
+		USE_GETPUT(int cmd,)
+		len_and_sockaddr *our_lsa,
 		len_and_sockaddr *peer_lsa,
-		const char *remotefile, const int localfd,
-		unsigned port, int tftp_bufsize)
+		USE_TFTP(const char *remote_file,)
+		int local_fd,
+		int blocksize)
 {
+#if !ENABLE_TFTP
+#define remote_file NULL
+#endif
 	struct pollfd pfd[1];
-#define socketfd (pfd[0].fd)
+#define socket_fd (pfd[0].fd)
 	int len;
 	int send_len;
 	USE_FEATURE_TFTP_BLOCKSIZE(smallint want_option_ack = 0;)
 	smallint finished = 0;
 	uint16_t opcode;
-	uint16_t block_nr = 1;
+	uint16_t block_nr;
 	uint16_t recv_blk;
 	int retries, waittime_ms;
+	int tftp_bufsize = blocksize + 4;
 	char *cp;
-
-	unsigned org_port;
-	len_and_sockaddr *const from = alloca(LSA_LEN_SIZE + peer_lsa->len);
-
 	/* Can't use RESERVE_CONFIG_BUFFER here since the allocation
 	 * size varies meaning BUFFERS_GO_ON_STACK would fail */
 	/* We must keep the transmit and receive buffers seperate */
 	/* In case we rcv a garbage pkt and we need to rexmit the last pkt */
-	char *xbuf = xmalloc(tftp_bufsize += 4);
+	char *xbuf = xmalloc(tftp_bufsize);
 	char *rbuf = xmalloc(tftp_bufsize);
 
-	port = org_port = htons(port);
+	socket_fd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0);
+	setsockopt_reuseaddr(socket_fd);
 
-	socketfd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0);
+	if (!ENABLE_TFTP || our_lsa) {
+		/* tftpd */
+		block_nr = 0;
 
-	/* build opcode */
-	opcode = TFTP_WRQ;
-	if (CMD_GET(cmd)) {
-		opcode = TFTP_RRQ;
-	}
-	cp = xbuf + 2;
-	/* add filename and mode */
-	/* fill in packet if the filename fits into xbuf */
-	len = strlen(remotefile) + 1;
-	if (2 + len + sizeof("octet") >= tftp_bufsize) {
-		bb_error_msg("remote filename is too long");
-		goto ret;
-	}
-	strcpy(cp, remotefile);
-	cp += len;
-	/* add "mode" part of the package */
-	strcpy(cp, "octet");
-	cp += sizeof("octet");
+		/* Create a socket which is:
+		 * 1. bound to IP:port peer sent 1st datagram to,
+		 * 2. connected to peer's IP:port
+		 * This way we will answer from the IP:port peer
+		 * expects, will not get any other packets on
+		 * the socket, and also plain read/write will work. */
+		xbind(socket_fd, &our_lsa->u.sa, our_lsa->len);
+		xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len);
 
 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
-	len = tftp_bufsize - 4;	/* data block size */
-	if (len != TFTP_BLOCKSIZE_DEFAULT) {
-		/* rfc2348 says that 65464 is a max allowed value */
-		if ((&xbuf[tftp_bufsize - 1] - cp) < sizeof("blksize NNNNN")) {
+		if (blocksize != TFTP_BLOCKSIZE_DEFAULT) {
+			/* Create and send OACK packet */
+			opcode = TFTP_OACK;
+			cp = xbuf + 2;
+			goto add_blksize_opt;
+		}
+		/* else: just fall into while (1) loop below */
+#endif
+	} else {
+		/* tftp */
+		block_nr = 1;
+
+		/* We can't (and don't really need to) bind the socket:
+		 * we don't know from which local IP datagrams will be sent,
+		 * but kernel will pick the same IP every time (unless routing
+		 * table is changed), thus peer will see dgrams consistently
+		 * coming from the same IP.
+		 * We would like to connect the socket, but since peer's
+		 * UDP code can be less perfect than ours, _peer's_ IP:port
+		 * in replies may differ from IP:port we used to send
+		 * our first packet. We can connect() only when we get
+		 * first reply. */
+
+		/* build opcode */
+		opcode = TFTP_WRQ;
+		if (CMD_GET(cmd)) {
+			opcode = TFTP_RRQ;
+		}
+		cp = xbuf + 2;
+		/* add filename and mode */
+		/* fill in packet if the filename fits into xbuf */
+		len = strlen(remote_file) + 1;
+		if (2 + len + sizeof("octet") >= tftp_bufsize) {
 			bb_error_msg("remote filename is too long");
 			goto ret;
 		}
-		/* add "blksize", <nul>, blocksize */
-		strcpy(cp, "blksize");
-		cp += sizeof("blksize");
-		cp += snprintf(cp, 6, "%d", len) + 1;
-		want_option_ack = 1;
+		strcpy(cp, remote_file);
+		cp += len;
+		/* add "mode" part of the package */
+		strcpy(cp, "octet");
+		cp += sizeof("octet");
+
+#if ENABLE_FEATURE_TFTP_BLOCKSIZE
+		if (blocksize != TFTP_BLOCKSIZE_DEFAULT) {
+			/* rfc2348 says that 65464 is a max allowed value */
+			if ((&xbuf[tftp_bufsize - 1] - cp) < sizeof("blksize NNNNN")) {
+				bb_error_msg("remote filename is too long");
+				goto ret;
+			}
+			want_option_ack = 1;
+ add_blksize_opt:
+			/* add "blksize", <nul>, blocksize, <nul> */
+			strcpy(cp, "blksize");
+			cp += sizeof("blksize");
+			cp += snprintf(cp, 6, "%d", blocksize) + 1;
+		}
+#endif
+		/* First packet is built, so skip packet generation */
+		goto send_pkt;
 	}
-#endif
-	/* First packet is built, so skip packet generation */
-	goto send_pkt;
 
 	/* Using mostly goto's - continue/break will be less clear
 	 * in where we actually jump to */
-
 	while (1) {
 		/* Build ACK or DATA */
 		cp = xbuf + 2;
@@ -189,7 +231,7 @@
 		opcode = TFTP_ACK;
 		if (CMD_PUT(cmd)) {
 			opcode = TFTP_DATA;
-			len = full_read(localfd, cp, tftp_bufsize - 4);
+			len = full_read(local_fd, cp, tftp_bufsize - 4);
 			if (len < 0) {
 				bb_perror_msg(bb_msg_read_error);
 				goto ret;
@@ -216,36 +258,36 @@
 			fprintf(stderr, "%02x ", (unsigned char) *cp);
 		fprintf(stderr, "\n");
 #endif
-		xsendto(socketfd, xbuf, send_len, &peer_lsa->u.sa, peer_lsa->len);
+		xsendto(socket_fd, xbuf, send_len, &peer_lsa->u.sa, peer_lsa->len);
 		/* Was it final ACK? then exit */
 		if (finished && (opcode == TFTP_ACK))
 			goto ret;
 
  recv_again:
 		/* Receive packet */
-		/*pfd[0].fd = socketfd;*/
+		/*pfd[0].fd = socket_fd;*/
 		pfd[0].events = POLLIN;
 		switch (safe_poll(pfd, 1, waittime_ms)) {
-			unsigned from_port;
 		case 1:
-			from->len = peer_lsa->len;
-			memset(&from->u.sa, 0, peer_lsa->len);
-			len = recvfrom(socketfd, rbuf, tftp_bufsize, 0,
-						&from->u.sa, &from->len);
+			if (!our_lsa) {
+				/* tftp (not tftpd!) receiving 1st packet */
+				our_lsa = ((void*)(ptrdiff_t)-1); /* not NULL */
+				len = recvfrom(socket_fd, rbuf, tftp_bufsize, 0,
+						&peer_lsa->u.sa, &peer_lsa->len);
+				/* Our first dgram went to port 69
+				 * but reply may come from different one.
+				 * Remember and use this new port (and IP) */
+				if (len >= 0)
+					xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len);
+			} else {
+				/* tftpd, or not the very first packet:
+				 * socket is connect()ed, can just read from it. */
+				len = safe_read(socket_fd, rbuf, tftp_bufsize);
+			}
 			if (len < 0) {
-				bb_perror_msg("recvfrom");
+				bb_perror_msg("read");
 				goto ret;
 			}
-			from_port = get_nport(&from->u.sa);
-			if (port == org_port) {
-				/* Our first query went to port 69
-				 * but reply will come from different one.
-				 * Remember and use this new port */
-				port = from_port;
-				set_nport(peer_lsa, from_port);
-			}
-			if (port != from_port)
-				goto recv_again;
 			goto process_pkt;
 		case 0:
 			retries--;
@@ -316,7 +358,7 @@
 						/*static const uint16_t error_8[2] = { htons(TFTP_ERROR), htons(8) };*/
 						/* thus we open-code big-endian layout */
 						static const uint8_t error_8[4] = { 0,TFTP_ERROR, 0,8 };
-						xsendto(socketfd, error_8, 4, &peer_lsa->u.sa, peer_lsa->len);
+						xsendto(socket_fd, error_8, 4, &peer_lsa->u.sa, peer_lsa->len);
 						bb_error_msg("server proposes bad blksize %d, exiting", blksize);
 						goto ret;
 					}
@@ -345,7 +387,7 @@
 
 		if (CMD_GET(cmd) && (opcode == TFTP_DATA)) {
 			if (recv_blk == block_nr) {
-				len = full_write(localfd, &rbuf[4], len - 4);
+				len = full_write(local_fd, &rbuf[4], len - 4);
 				if (len < 0) {
 					bb_perror_msg(bb_msg_write_error);
 					goto ret;
@@ -363,7 +405,7 @@
 		}
 
 		if (CMD_PUT(cmd) && (opcode == TFTP_ACK)) {
-			/* did server ACK our last DATA pkt? */
+			/* did peer ACK our last DATA pkt? */
 			if (recv_blk == (uint16_t) (block_nr - 1)) {
 				if (finished)
 					goto ret;
@@ -381,25 +423,27 @@
 		 * See:
 		 * http://en.wikipedia.org/wiki/Sorcerer's_Apprentice_Syndrome
 		 */
-	}
+	} /* end of "while (1)" */
  ret:
 	if (ENABLE_FEATURE_CLEAN_UP) {
-		close(socketfd);
+		close(socket_fd);
 		free(xbuf);
 		free(rbuf);
 	}
 	return finished == 0; /* returns 1 on failure */
 }
 
+#if ENABLE_TFTP
+
 int tftp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv)
 {
 	len_and_sockaddr *peer_lsa;
-	const char *localfile = NULL;
-	const char *remotefile = NULL;
+	const char *local_file = NULL;
+	const char *remote_file = NULL;
 	int port;
 	USE_GETPUT(int cmd;)
-	int fd = -1;
+	int local_fd;
 	int flags = 0;
 	int result;
 	int blocksize = TFTP_BLOCKSIZE_DEFAULT;
@@ -412,7 +456,7 @@
 	USE_GETPUT(cmd =) getopt32(argv,
 			USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p")
 				"l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"),
-			&localfile, &remotefile
+			&local_file, &remote_file
 			USE_FEATURE_TFTP_BLOCKSIZE(, &blocksize));
 	argv += optind;
 
@@ -425,36 +469,142 @@
 		return EXIT_FAILURE;
 #endif
 
-	if (!localfile)
-		localfile = remotefile;
-	if (!remotefile)
-		remotefile = localfile;
+	if (!local_file)
+		local_file = remote_file;
+	if (!remote_file)
+		remote_file = local_file;
 	/* Error if filename or host is not known */
-	if (!remotefile || !argv[0])
+	if (!remote_file || !argv[0])
 		bb_show_usage();
 
-	fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO;
-	if (!LONE_DASH(localfile)) {
-		fd = xopen(localfile, flags);
+	local_fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO;
+	if (!LONE_DASH(local_file)) {
+		local_fd = xopen(local_file, flags);
 	}
 
 	port = bb_lookup_port(argv[1], "udp", 69);
 	peer_lsa = xhost2sockaddr(argv[0], port);
 
 #if ENABLE_DEBUG_TFTP
-	fprintf(stderr, "using server '%s', remotefile '%s', localfile '%s'\n",
+	fprintf(stderr, "using server '%s', remote_file '%s', local_file '%s'\n",
 			xmalloc_sockaddr2dotted(&peer_lsa->u.sa),
-			remotefile, localfile);
+			remote_file, local_file);
 #endif
 
-	result = tftp( USE_GETPUT(cmd,) peer_lsa, remotefile, fd, port, blocksize);
+	result = tftp_protocol(
+			USE_GETPUT(cmd,)
+			NULL /* our_lsa*/,
+			peer_lsa,
+			remote_file, local_fd, blocksize);
 
 	if (ENABLE_FEATURE_CLEAN_UP)
-		close(fd);
-	if (result != EXIT_SUCCESS && !LONE_DASH(localfile) && CMD_GET(cmd)) {
-		unlink(localfile);
+		close(local_fd);
+	if (result != EXIT_SUCCESS && !LONE_DASH(local_file) && CMD_GET(cmd)) {
+		unlink(local_file);
 	}
 	return result;
 }
 
+#endif /* ENABLE_TFTP */
+
+#if ENABLE_TFTPD
+
+/* TODO: libbb candidate? */
+static len_and_sockaddr *get_sock_lsa(int s)
+{
+	len_and_sockaddr *lsa;
+	socklen_t len = 0;
+
+	if (getsockname(s, NULL, &len) != 0)
+		return NULL;
+	lsa = xzalloc(LSA_LEN_SIZE + len);
+	lsa->len = len;
+	getsockname(s, &lsa->u.sa, &lsa->len);
+	return lsa;
+}
+
+int tftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
+{
+	struct stat statbuf;
+	char block_buf[TFTP_BLOCKSIZE_DEFAULT];
+	len_and_sockaddr *our_lsa;
+	len_and_sockaddr *peer_lsa;
+	char *filename, *mode, *opt_str;
+	int result, opcode, cmd, req_modebits, open_mode, local_fd, blksize;
+
+	our_lsa = get_sock_lsa(STDIN_FILENO);
+	if (!our_lsa)
+		bb_perror_msg_and_die("stdin is not a socket");
+	peer_lsa = xzalloc(LSA_LEN_SIZE + our_lsa->len);
+	peer_lsa->len = our_lsa->len;
+
+	if (argv[1])
+		xchdir(argv[1]);
+
+	result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf),
+			0 /* flags */,
+			&peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len);
+
+	opcode = ntohs(*(uint16_t*)block_buf);
+	if (result < 4 || result >= sizeof(block_buf)
+	 || block_buf[result-1] != '\0'
+	 || (opcode != TFTP_RRQ && opcode != TFTP_WRQ)
+	) {
+		bb_error_msg_and_die("malformed packet");
+	}
+	filename = block_buf + 2;
+	if (filename[0] == '.' || strstr(filename, "/.")) {
+		bb_error_msg_and_die("dot in filename");
+	}
+	mode = filename + strlen(filename) + 1;
+	if (mode >= block_buf + sizeof(block_buf)
+	 || strcmp(mode, "octet") != 0
+	) {
+		bb_error_msg_and_die("malformed packet");
+	}
+	blksize = TFTP_BLOCKSIZE_DEFAULT;
+#if ENABLE_FEATURE_TFTP_BLOCKSIZE
+	opt_str = mode + 6;
+	if (opt_str < block_buf + sizeof(block_buf)) {
+		char *res = tftp_option_get(opt_str, block_buf + sizeof(block_buf) - opt_str, "blksize");
+		if (res) {
+			int sz = xatoi_u(res);
+			if (tftp_blocksize_check(sz, 0))
+				blksize = sz;
+		}
+	}
+#endif
+	xstat(filename, &statbuf);
+	/* if opcode == TFTP_WRQ: */
+	cmd = 1; /* CMD_GET: we will receive file's data */
+	req_modebits = 0222; /* writable by anyone */
+	open_mode = O_WRONLY | O_TRUNC;
+	if (opcode == TFTP_RRQ) {
+		cmd = 2; /* CMD_PUT */
+		req_modebits = 0444; /* readable by anyone */
+		open_mode = O_RDONLY;
+	}
+	if (!S_ISREG(statbuf.st_mode)
+	 || (statbuf.st_mode & req_modebits) != req_modebits
+	) {
+		bb_error_msg_and_die("access to '%s' is denied", filename);
+	}
+	local_fd = xopen(filename, open_mode);
+
+	close(STDIN_FILENO); /* close old, possibly wildcard socket */
+	/* tftp_protocol() will create new one, bound to particular local IP */
+	result = tftp_protocol(
+		USE_GETPUT(cmd,)
+		our_lsa, peer_lsa,
+		USE_TFTP(NULL /*remote_file*/,)
+		local_fd,
+		blksize
+	);
+
+	return result;
+}
+
+#endif /* ENABLE_TFTPD */
+
 #endif /* ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT */

Modified: trunk/busybox/printutils/Config.in
===================================================================
--- trunk/busybox/printutils/Config.in	2008-03-17 09:09:09 UTC (rev 21356)
+++ trunk/busybox/printutils/Config.in	2008-03-17 09:10:39 UTC (rev 21357)
@@ -1,4 +1,4 @@
-menu "print support"
+menu "Print Utilities"
 
 config LPD
 	bool "lpd"




More information about the busybox-cvs mailing list