busybox/networking/tftp.c

1017 lines
29 KiB
C
Raw Normal View History

/* vi: set sw=4 ts=4: */
/*
* A simple tftp client/server for busybox.
* Tries to follow RFC1350.
* Only "octet" mode supported.
* Optional blocksize negotiation (RFC2347 + RFC2348)
*
* Copyright (C) 2001 Magnus Damm <damm@opensource.se>
*
* Parts of the code based on:
*
* atftp: Copyright (C) 2000 Jean-Pierre Lefebvre <helix@step.polymtl.ca>
* and Remi Lefebvre <remi@debian.org>
*
* utftp: Copyright (C) 1999 Uwe Ohse <uwe@ohse.de>
*
2008-03-18 05:41:46 +05:30
* tftpd added by Denys Vlasenko & Vladimir Dronnikov
*
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
//config:config TFTP
//config: bool "tftp (11 kb)"
//config: default y
//config: help
//config: Trivial File Transfer Protocol client. TFTP is usually used
//config: for simple, small transfers such as a root image
//config: for a network-enabled bootloader.
//config:
//config:config FEATURE_TFTP_PROGRESS_BAR
//config: bool "Enable progress bar"
//config: default y
//config: depends on TFTP
//config:
//config:config FEATURE_TFTP_HPA_COMPAT
//config: bool "tftp-hpa compat (support -c get/put FILE)"
//config: default y
//config: depends on TFTP
//config:
//config:config TFTPD
//config: bool "tftpd (10 kb)"
//config: default y
//config: help
//config: Trivial File Transfer Protocol server.
//config: It expects that stdin is a datagram socket and a packet
//config: is already pending on it. It will exit after one transfer.
//config: In other words: it should be run from inetd in nowait mode,
//config: or from udpsvd. Example: "udpsvd -E 0 69 tftpd DIR"
//config:
//config:config FEATURE_TFTP_GET
//config: bool "Enable 'tftp get' and/or tftpd upload code"
//config: default y
//config: depends on TFTP || TFTPD
//config: help
//config: Add support for the GET command within the TFTP client. This allows
//config: a client to retrieve a file from a TFTP server.
//config: Also enable upload support in tftpd, if tftpd is selected.
//config:
//config: Note: this option does _not_ make tftpd capable of download
//config: (the usual operation people need from it)!
//config:
//config:config FEATURE_TFTP_PUT
//config: bool "Enable 'tftp put' and/or tftpd download code"
//config: default y
//config: depends on TFTP || TFTPD
//config: help
//config: Add support for the PUT command within the TFTP client. This allows
//config: a client to transfer a file to a TFTP server.
//config: Also enable download support in tftpd, if tftpd is selected.
//config:
//config:config FEATURE_TFTP_BLOCKSIZE
//config: bool "Enable 'blksize' and 'tsize' protocol options"
//config: default y
//config: depends on TFTP || TFTPD
//config: help
//config: Allow tftp to specify block size, and tftpd to understand
//config: "blksize" and "tsize" options.
//config:
//config:config TFTP_DEBUG
//config: bool "Enable debug"
//config: default n
//config: depends on TFTP || TFTPD
//config: help
//config: Make tftp[d] print debugging messages on stderr.
//config: This is useful if you are diagnosing a bug in tftp[d].
//applet:#if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT
//applet:IF_TFTP(APPLET(tftp, BB_DIR_USR_BIN, BB_SUID_DROP))
//applet:IF_TFTPD(APPLET(tftpd, BB_DIR_USR_SBIN, BB_SUID_DROP))
//applet:#endif
//kbuild:lib-$(CONFIG_TFTP) += tftp.o
//kbuild:lib-$(CONFIG_TFTPD) += tftp.o
//usage:#define tftp_trivial_usage
//usage: "[OPTIONS] HOST [PORT]"
//usage:#define tftp_full_usage "\n\n"
//usage: "Transfer a file from/to tftp server\n"
//usage: "\n -l FILE Local FILE"
//usage: "\n -r FILE Remote FILE"
//usage: IF_FEATURE_TFTP_GET(
//usage: "\n -g Get file"
//usage: )
//usage: IF_FEATURE_TFTP_PUT(
//usage: "\n -p Put file"
//usage: )
//usage: IF_FEATURE_TFTP_BLOCKSIZE(
//usage: "\n -b SIZE Transfer blocks in bytes"
//usage: )
///////: "\n -m STR Accepted and ignored ('-m binary' compat with tftp-hpa 5.2)"
//usage:
//usage:#define tftpd_trivial_usage
//usage: "[-crl] [-u USER] [DIR]"
//usage:#define tftpd_full_usage "\n\n"
//usage: "Transfer a file on tftp client's request\n"
//usage: "\n"
//usage: "tftpd should be used as an inetd service.\n"
//usage: "tftpd's line for inetd.conf:\n"
//usage: " 69 dgram udp nowait root tftpd tftpd -l /files/to/serve\n"
//usage: "It also can be ran from udpsvd:\n"
//usage: " udpsvd -vE 0.0.0.0 69 tftpd /files/to/serve\n"
//usage: "\n -r Prohibit upload"
//usage: "\n -c Allow file creation via upload"
//usage: "\n -u USER Access files as USER"
//usage: "\n -l Log to syslog (inetd mode requires this)"
#include "libbb.h"
#include "common_bufsiz.h"
#include <syslog.h>
#if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT
#define TFTP_BLKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */
#define TFTP_BLKSIZE_DEFAULT_STR "512"
/* Was 50 ms but users asked to bump it up a bit */
#define TFTP_TIMEOUT_MS 100
#define TFTP_MAXTIMEOUT_MS 2000
#define TFTP_NUM_RETRIES 12 /* number of backed-off retries */
/* opcodes we support */
#define TFTP_RRQ 1
#define TFTP_WRQ 2
#define TFTP_DATA 3
#define TFTP_ACK 4
#define TFTP_ERROR 5
#define TFTP_OACK 6
/* error codes sent over network (we use only 0, 1, 3 and 8) */
/* generic (error message is included in the packet) */
#define ERR_UNSPEC 0
#define ERR_NOFILE 1
#define ERR_ACCESS 2
/* disk full or allocation exceeded */
#define ERR_WRITE 3
#define ERR_OP 4
#define ERR_BAD_ID 5
#define ERR_EXIST 6
#define ERR_BAD_USER 7
#define ERR_BAD_OPT 8
/* masks coming from getopt32 */
enum {
TFTP_OPT_GET = (1 << 0),
TFTP_OPT_PUT = (1 << 1),
/* pseudo option: if set, it's tftpd */
TFTPD_OPT = (1 << 7) * ENABLE_TFTPD,
TFTPD_OPT_r = (1 << 8) * ENABLE_TFTPD,
TFTPD_OPT_c = (1 << 9) * ENABLE_TFTPD,
TFTPD_OPT_u = (1 << 10) * ENABLE_TFTPD,
TFTPD_OPT_l = (1 << 11) * ENABLE_TFTPD,
};
#if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT
#define IF_GETPUT(...)
#define CMD_GET(cmd) 1
#define CMD_PUT(cmd) 0
#elif !ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
#define IF_GETPUT(...)
#define CMD_GET(cmd) 0
#define CMD_PUT(cmd) 1
#else
#define IF_GETPUT(...) __VA_ARGS__
#define CMD_GET(cmd) ((cmd) & TFTP_OPT_GET)
#define CMD_PUT(cmd) ((cmd) & TFTP_OPT_PUT)
#endif
/* NB: in the code below
* CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive
*/
struct globals {
/* u16 TFTP_ERROR; u16 reason; both network-endian, then error text: */
uint8_t error_pkt[4 + 32];
struct passwd *pw;
/* Used in tftpd_main() for initial packet */
/* Some HP PA-RISC firmware always sends fixed 516-byte requests */
char block_buf[516];
char block_buf_tail[1];
#if ENABLE_FEATURE_TFTP_PROGRESS_BAR
off_t pos;
off_t size;
const char *file;
bb_progress_t pmt;
#endif
} FIX_ALIASING;
#define G (*(struct globals*)bb_common_bufsiz1)
#define INIT_G() do { \
setup_common_bufsiz(); \
BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
} while (0)
#define G_error_pkt_reason (G.error_pkt[3])
#define G_error_pkt_str ((char*)(G.error_pkt + 4))
#if ENABLE_FEATURE_TFTP_PROGRESS_BAR && ENABLE_FEATURE_TFTP_BLOCKSIZE
static void tftp_progress_update(void)
{
bb_progress_update(&G.pmt, 0, G.pos, G.size);
}
static void tftp_progress_init(void)
{
bb_progress_init(&G.pmt, G.file);
tftp_progress_update();
}
static void tftp_progress_done(void)
{
if (is_bb_progress_inited(&G.pmt)) {
tftp_progress_update();
bb_putchar_stderr('\n');
bb_progress_free(&G.pmt);
}
}
#else
# define tftp_progress_update() ((void)0)
# define tftp_progress_init() ((void)0)
# define tftp_progress_done() ((void)0)
#endif
2001-08-20 23:17:49 +05:30
#if ENABLE_FEATURE_TFTP_BLOCKSIZE
static int tftp_blksize_check(const char *blksize_str, int maxsize)
{
/* Check if the blksize is valid:
* RFC2348 says between 8 and 65464,
* but our implementation makes it impossible
* to use blksizes smaller than 22 octets. */
unsigned blksize = bb_strtou(blksize_str, NULL, 10);
if (errno
|| (blksize < 24) || (blksize > maxsize)
) {
bb_error_msg("bad blocksize '%s'", blksize_str);
return -1;
}
# if ENABLE_TFTP_DEBUG
Optionally re-introduce bb_info_msg() Between Busybox 1.24.2 and 1.25.0 the bb_info_msg() function was eliminated and calls to it changed to be bb_error_msg(). The downside of this is that daemons now log all messages to syslog at the LOG_ERR level which makes it hard to filter errors from informational messages. This change optionally re-introduces bb_info_msg(), controlled by a new option FEATURE_SYSLOG_INFO, restores all the calls to bb_info_msg() that were removed (only in applets that set logmode to LOGMODE_SYSLOG or LOGMODE_BOTH), and also changes informational messages in ifplugd and ntpd. The code size change of this is as follows (using 'defconfig' on x86_64 with gcc 7.3.0-27ubuntu1~18.04) function old new delta bb_info_msg - 182 +182 bb_vinfo_msg - 27 +27 static.log7 194 198 +4 log8 190 191 +1 log5 190 191 +1 crondlog 45 - -45 ------------------------------------------------------------------------------ (add/remove: 2/1 grow/shrink: 3/0 up/down: 215/-45) Total: 170 bytes If you don't care about everything being logged at LOG_ERR level then when FEATURE_SYSLOG_INFO is disabled Busybox actually gets smaller: function old new delta static.log7 194 200 +6 log8 190 193 +3 log5 190 193 +3 syslog_level 1 - -1 bb_verror_msg 583 581 -2 crondlog 45 - -45 ------------------------------------------------------------------------------ (add/remove: 0/2 grow/shrink: 3/1 up/down: 12/-48) Total: -36 bytes Signed-off-by: James Byrne <james.byrne@origamienergy.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2019-04-12 22:31:51 +05:30
bb_info_msg("using blksize %u", blksize);
# endif
return blksize;
}
static char *tftp_get_option(const char *option, char *buf, int len)
{
2006-01-25 05:38:53 +05:30
int opt_val = 0;
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 options are terminated correctly */
for (k = 0; k < len; k++) {
if (buf[k] == '\0') {
goto nul_found;
}
}
return NULL;
nul_found:
if (opt_val == 0) { /* it's "name" part */
if (strcasecmp(buf, option) == 0) {
opt_found = 1;
}
} else if (opt_found) {
return buf;
}
k++;
buf += k;
len -= k;
opt_val ^= 1;
}
return NULL;
}
#endif
static int tftp_protocol(
/* NULL if tftp, !NULL if tftpd: */
len_and_sockaddr *our_lsa,
2007-02-08 04:50:32 +05:30
len_and_sockaddr *peer_lsa,
const char *local_file
IF_TFTP(, const char *remote_file)
#if !ENABLE_TFTP
# define remote_file NULL
#endif
/* 1 for tftp; 1/0 for tftpd depending whether client asked about it: */
IF_FEATURE_TFTP_BLOCKSIZE(, int want_transfer_size)
IF_FEATURE_TFTP_BLOCKSIZE(, int blksize))
{
#if !ENABLE_FEATURE_TFTP_BLOCKSIZE
enum { blksize = TFTP_BLKSIZE_DEFAULT };
#endif
struct pollfd pfd[1];
#define socket_fd (pfd[0].fd)
2006-06-10 20:02:56 +05:30
int len;
int send_len;
IF_FEATURE_TFTP_BLOCKSIZE(smallint expect_OACK = 0;)
smallint finished = 0;
uint16_t opcode;
uint16_t block_nr;
uint16_t recv_blk;
int local_fd = -1;
int retries, waittime_ms;
int io_bufsize = blksize + 4;
char *cp;
/* 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 separate
* in case we rcv a garbage pkt - we need to rexmit the last pkt.
*/
char *xbuf = xmalloc(io_bufsize);
char *rbuf = xmalloc(io_bufsize);
socket_fd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0);
setsockopt_reuseaddr(socket_fd);
if (!ENABLE_TFTP || our_lsa) { /* tftpd */
/* 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);
/* Is there an error already? Send pkt and bail out */
if (G_error_pkt_reason || G_error_pkt_str[0])
goto send_err_pkt;
if (G.pw) {
change_identity(G.pw); /* initgroups, setgid, setuid */
}
}
/* Examples of network traffic.
* Note two cases when ACKs with block# of 0 are sent.
*
* Download without options:
* tftp -> "\0\1FILENAME\0octet\0"
* "\0\3\0\1FILEDATA..." <- tftpd
* tftp -> "\0\4\0\1"
* ...
* Download with option of blksize 16384:
* tftp -> "\0\1FILENAME\0octet\0blksize\00016384\0"
* "\0\6blksize\00016384\0" <- tftpd
* tftp -> "\0\4\0\0"
* "\0\3\0\1FILEDATA..." <- tftpd
* tftp -> "\0\4\0\1"
* ...
* Upload without options:
* tftp -> "\0\2FILENAME\0octet\0"
* "\0\4\0\0" <- tftpd
* tftp -> "\0\3\0\1FILEDATA..."
* "\0\4\0\1" <- tftpd
* ...
* Upload with option of blksize 16384:
* tftp -> "\0\2FILENAME\0octet\0blksize\00016384\0"
* "\0\6blksize\00016384\0" <- tftpd
* tftp -> "\0\3\0\1FILEDATA..."
* "\0\4\0\1" <- tftpd
* ...
*/
block_nr = 1;
cp = xbuf + 2;
if (!ENABLE_TFTP || our_lsa) { /* tftpd */
/* Open file (must be after changing user) */
int open_mode = O_RDONLY;
if (CMD_GET(option_mask32)) {
open_mode = O_WRONLY | O_TRUNC | O_CREAT;
if ((option_mask32 & (TFTPD_OPT+TFTPD_OPT_c)) == TFTPD_OPT) {
/* tftpd without -c */
open_mode = O_WRONLY | O_TRUNC;
}
}
local_fd = open(local_file, open_mode, 0666);
if (local_fd < 0) {
/* sanitize name, it came from untrusted remote side */
unsigned char *p = (void *) local_file;
while (*p) {
if (*p < ' ')
*p = '?';
p++;
}
bb_perror_msg("can't open '%s'", local_file);
G_error_pkt_reason = ERR_NOFILE;
strcpy(G_error_pkt_str, "can't open file");
goto send_err_pkt_nomsg;
}
2008-06-16 13:02:40 +05:30
/* gcc 4.3.1 would NOT optimize it out as it should! */
#if ENABLE_FEATURE_TFTP_BLOCKSIZE
if (blksize != TFTP_BLKSIZE_DEFAULT || want_transfer_size) {
/* Create and send OACK packet. */
/* For the download case, block_nr is still 1 -
* we expect 1st ACK from peer to be for (block_nr-1),
* that is, for "block 0" which is our OACK pkt */
opcode = TFTP_OACK;
goto add_blksize_opt;
}
2008-06-16 13:02:40 +05:30
#endif
if (CMD_GET(option_mask32)) {
/* It's upload and we don't send OACK.
* We must ACK 1st packet (with filename)
* as if it is "block 0" */
block_nr = 0;
}
} else { /* tftp */
if (CMD_PUT(option_mask32)) {
local_fd = STDIN_FILENO;
if (local_file)
local_fd = xopen(local_file, O_RDONLY);
}
/* Removing #if, or using if() statement instead of #if may lead to
* "warning: null argument where non-null required": */
#if ENABLE_TFTP
/* tftp */
/* 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(option_mask32)) {
opcode = TFTP_RRQ;
}
/* add filename and mode */
/* fill in packet if the filename fits into xbuf */
len = strlen(remote_file);
if (len + 3 + sizeof("octet") >= io_bufsize) {
libbb: reduce the overhead of single parameter bb_error_msg() calls Back in 2007, commit 0c97c9d43707 ("'simple' error message functions by Loic Grenie") introduced bb_simple_perror_msg() to allow for a lower overhead call to bb_perror_msg() when only a string was being printed with no parameters. This saves space for some CPU architectures because it avoids the overhead of a call to a variadic function. However there has never been a simple version of bb_error_msg(), and since 2007 many new calls to bb_perror_msg() have been added that only take a single parameter and so could have been using bb_simple_perror_message(). This changeset introduces 'simple' versions of bb_info_msg(), bb_error_msg(), bb_error_msg_and_die(), bb_herror_msg() and bb_herror_msg_and_die(), and replaces all calls that only take a single parameter, or use something like ("%s", arg), with calls to the corresponding 'simple' version. Since it is likely that single parameter calls to the variadic functions may be accidentally reintroduced in the future a new debugging config option WARN_SIMPLE_MSG has been introduced. This uses some macro magic which will cause any such calls to generate a warning, but this is turned off by default to avoid use of the unpleasant macros in normal circumstances. This is a large changeset due to the number of calls that have been replaced. The only files that contain changes other than simple substitution of function calls are libbb.h, libbb/herror_msg.c, libbb/verror_msg.c and libbb/xfuncs_printf.c. In miscutils/devfsd.c, networking/udhcp/common.h and util-linux/mdev.c additonal macros have been added for logging so that single parameter and multiple parameter logging variants exist. The amount of space saved varies considerably by architecture, and was found to be as follows (for 'defconfig' using GCC 7.4): Arm: -92 bytes MIPS: -52 bytes PPC: -1836 bytes x86_64: -938 bytes Note that for the MIPS architecture only an exception had to be made disabling the 'simple' calls for 'udhcp' (in networking/udhcp/common.h) because it made these files larger on MIPS. Signed-off-by: James Byrne <james.byrne@origamienergy.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2019-07-02 15:05:03 +05:30
bb_simple_error_msg("remote filename is too long");
goto ret;
}
cp = stpcpy(cp, remote_file) + 1;
/* add "mode" part of the packet */
cp = stpcpy(cp, "octet") + 1;
# if ENABLE_FEATURE_TFTP_BLOCKSIZE
if (blksize == TFTP_BLKSIZE_DEFAULT && !want_transfer_size)
goto send_pkt;
/* Need to add option to pkt */
if ((&xbuf[io_bufsize - 1] - cp) < sizeof("blksize NNNNN tsize ") + sizeof(off_t)*3) {
libbb: reduce the overhead of single parameter bb_error_msg() calls Back in 2007, commit 0c97c9d43707 ("'simple' error message functions by Loic Grenie") introduced bb_simple_perror_msg() to allow for a lower overhead call to bb_perror_msg() when only a string was being printed with no parameters. This saves space for some CPU architectures because it avoids the overhead of a call to a variadic function. However there has never been a simple version of bb_error_msg(), and since 2007 many new calls to bb_perror_msg() have been added that only take a single parameter and so could have been using bb_simple_perror_message(). This changeset introduces 'simple' versions of bb_info_msg(), bb_error_msg(), bb_error_msg_and_die(), bb_herror_msg() and bb_herror_msg_and_die(), and replaces all calls that only take a single parameter, or use something like ("%s", arg), with calls to the corresponding 'simple' version. Since it is likely that single parameter calls to the variadic functions may be accidentally reintroduced in the future a new debugging config option WARN_SIMPLE_MSG has been introduced. This uses some macro magic which will cause any such calls to generate a warning, but this is turned off by default to avoid use of the unpleasant macros in normal circumstances. This is a large changeset due to the number of calls that have been replaced. The only files that contain changes other than simple substitution of function calls are libbb.h, libbb/herror_msg.c, libbb/verror_msg.c and libbb/xfuncs_printf.c. In miscutils/devfsd.c, networking/udhcp/common.h and util-linux/mdev.c additonal macros have been added for logging so that single parameter and multiple parameter logging variants exist. The amount of space saved varies considerably by architecture, and was found to be as follows (for 'defconfig' using GCC 7.4): Arm: -92 bytes MIPS: -52 bytes PPC: -1836 bytes x86_64: -938 bytes Note that for the MIPS architecture only an exception had to be made disabling the 'simple' calls for 'udhcp' (in networking/udhcp/common.h) because it made these files larger on MIPS. Signed-off-by: James Byrne <james.byrne@origamienergy.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2019-07-02 15:05:03 +05:30
bb_simple_error_msg("remote filename is too long");
goto ret;
}
expect_OACK = 1;
# endif
#endif /* ENABLE_TFTP */
2008-06-16 13:02:40 +05:30
#if ENABLE_FEATURE_TFTP_BLOCKSIZE
add_blksize_opt:
if (blksize != TFTP_BLKSIZE_DEFAULT) {
/* add "blksize", <nul>, blksize, <nul> */
strcpy(cp, "blksize");
cp += sizeof("blksize");
cp += snprintf(cp, 6, "%d", blksize) + 1;
}
if (want_transfer_size) {
/* add "tsize", <nul>, size, <nul> (see RFC2349) */
/* if tftp and downloading, we send "0" (local_fd is not open yet)
* and this makes server to send "tsize" option with the size */
/* if tftp and uploading, we send file size (maybe dont, to not confuse old servers???) */
/* if tftpd and downloading, we are answering to client's request */
/* if tftpd and uploading: !want_transfer_size, this code is not executed */
struct stat st;
strcpy(cp, "tsize");
cp += sizeof("tsize");
st.st_size = 0;
if (local_fd >= 0)
fstat(local_fd, &st);
cp += sprintf(cp, "%"OFF_FMT"u", (off_t)st.st_size) + 1;
# if ENABLE_FEATURE_TFTP_PROGRESS_BAR
/* Save for progress bar. If 0 (tftp downloading),
* we look at server's reply later */
G.size = st.st_size;
if (remote_file && st.st_size)
tftp_progress_init();
# endif
}
2008-06-16 13:02:40 +05:30
#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;
*((uint16_t*)cp) = htons(block_nr);
cp += 2;
block_nr++;
opcode = TFTP_ACK;
if (CMD_PUT(option_mask32)) {
opcode = TFTP_DATA;
len = full_read(local_fd, cp, blksize);
if (len < 0) {
goto send_read_err_pkt;
}
if (len != blksize) {
finished = 1;
}
cp += len;
IF_FEATURE_TFTP_PROGRESS_BAR(G.pos += len;)
}
send_pkt:
/* Send packet */
*((uint16_t*)xbuf) = htons(opcode); /* fill in opcode part */
send_len = cp - xbuf;
/* NB: send_len value is preserved in code below
* for potential resend */
retries = TFTP_NUM_RETRIES; /* re-initialize */
waittime_ms = TFTP_TIMEOUT_MS;
send_again:
#if ENABLE_TFTP_DEBUG
fprintf(stderr, "sending %u bytes\n", send_len);
for (cp = xbuf; cp < &xbuf[send_len]; cp++)
fprintf(stderr, "%02x ", (unsigned char) *cp);
fprintf(stderr, "\n");
2001-08-20 23:17:49 +05:30
#endif
xsendto(socket_fd, xbuf, send_len, &peer_lsa->u.sa, peer_lsa->len);
#if ENABLE_FEATURE_TFTP_PROGRESS_BAR
if (is_bb_progress_inited(&G.pmt))
tftp_progress_update();
#endif
/* Was it final ACK? then exit */
if (finished && (opcode == TFTP_ACK))
goto ret;
recv_again:
/* Receive packet */
/*pfd[0].fd = socket_fd;*/
pfd[0].events = POLLIN;
switch (safe_poll(pfd, 1, waittime_ms)) {
default:
/*bb_perror_msg("poll"); - done in safe_poll */
goto ret;
case 0:
retries--;
if (retries == 0) {
tftp_progress_done();
libbb: reduce the overhead of single parameter bb_error_msg() calls Back in 2007, commit 0c97c9d43707 ("'simple' error message functions by Loic Grenie") introduced bb_simple_perror_msg() to allow for a lower overhead call to bb_perror_msg() when only a string was being printed with no parameters. This saves space for some CPU architectures because it avoids the overhead of a call to a variadic function. However there has never been a simple version of bb_error_msg(), and since 2007 many new calls to bb_perror_msg() have been added that only take a single parameter and so could have been using bb_simple_perror_message(). This changeset introduces 'simple' versions of bb_info_msg(), bb_error_msg(), bb_error_msg_and_die(), bb_herror_msg() and bb_herror_msg_and_die(), and replaces all calls that only take a single parameter, or use something like ("%s", arg), with calls to the corresponding 'simple' version. Since it is likely that single parameter calls to the variadic functions may be accidentally reintroduced in the future a new debugging config option WARN_SIMPLE_MSG has been introduced. This uses some macro magic which will cause any such calls to generate a warning, but this is turned off by default to avoid use of the unpleasant macros in normal circumstances. This is a large changeset due to the number of calls that have been replaced. The only files that contain changes other than simple substitution of function calls are libbb.h, libbb/herror_msg.c, libbb/verror_msg.c and libbb/xfuncs_printf.c. In miscutils/devfsd.c, networking/udhcp/common.h and util-linux/mdev.c additonal macros have been added for logging so that single parameter and multiple parameter logging variants exist. The amount of space saved varies considerably by architecture, and was found to be as follows (for 'defconfig' using GCC 7.4): Arm: -92 bytes MIPS: -52 bytes PPC: -1836 bytes x86_64: -938 bytes Note that for the MIPS architecture only an exception had to be made disabling the 'simple' calls for 'udhcp' (in networking/udhcp/common.h) because it made these files larger on MIPS. Signed-off-by: James Byrne <james.byrne@origamienergy.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2019-07-02 15:05:03 +05:30
bb_simple_error_msg("timeout");
goto ret; /* no err packet sent */
}
/* exponential backoff with limit */
waittime_ms += waittime_ms/2;
if (waittime_ms > TFTP_MAXTIMEOUT_MS) {
waittime_ms = TFTP_MAXTIMEOUT_MS;
}
goto send_again; /* resend last sent pkt */
case 1:
if (!our_lsa) {
/* tftp (not tftpd!) receiving 1st packet */
our_lsa = ((void*)(ptrdiff_t)-1); /* not NULL */
len = recvfrom(socket_fd, rbuf, io_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. */
/* Don't full_read()!
* This is not TCP, one read == one pkt! */
len = safe_read(socket_fd, rbuf, io_bufsize);
}
if (len < 0) {
goto send_read_err_pkt;
}
if (len < 4) { /* too small? */
2008-03-18 05:41:46 +05:30
goto recv_again;
}
}
/* Process recv'ed packet */
opcode = ntohs( ((uint16_t*)rbuf)[0] );
recv_blk = ntohs( ((uint16_t*)rbuf)[1] );
#if ENABLE_TFTP_DEBUG
fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk);
2001-08-20 23:17:49 +05:30
#endif
if (opcode == TFTP_ERROR) {
static const char errcode_str[] ALIGN1 =
"\0"
"file not found\0"
"access violation\0"
"disk full\0"
"bad operation\0"
"unknown transfer id\0"
"file already exists\0"
"no such user\0"
"bad option";
const char *msg = "";
if (len > 4 && rbuf[4] != '\0') {
msg = &rbuf[4];
rbuf[io_bufsize - 1] = '\0'; /* paranoia */
} else if (recv_blk <= 8) {
msg = nth_string(errcode_str, recv_blk);
}
bb_error_msg("server error: (%u) %s", recv_blk, msg);
goto ret;
}
#if ENABLE_FEATURE_TFTP_BLOCKSIZE
if (expect_OACK) {
expect_OACK = 0;
if (opcode == TFTP_OACK) {
/* server seems to support options */
char *res;
res = tftp_get_option("blksize", &rbuf[2], len - 2);
if (res) {
blksize = tftp_blksize_check(res, blksize);
if (blksize < 0) {
G_error_pkt_reason = ERR_BAD_OPT;
goto send_err_pkt;
}
io_bufsize = blksize + 4;
}
# if ENABLE_FEATURE_TFTP_PROGRESS_BAR
if (remote_file && G.size == 0) { /* if we don't know it yet */
res = tftp_get_option("tsize", &rbuf[2], len - 2);
if (res) {
G.size = bb_strtoull(res, NULL, 10);
if (G.size)
tftp_progress_init();
}
}
# endif
if (CMD_GET(option_mask32)) {
/* We'll send ACK for OACK,
* such ACK has "block no" of 0 */
block_nr = 0;
}
continue;
}
/* rfc2347:
* "An option not acknowledged by the server
* must be ignored by the client and server
* as if it were never requested." */
if (blksize != TFTP_BLKSIZE_DEFAULT)
libbb: reduce the overhead of single parameter bb_error_msg() calls Back in 2007, commit 0c97c9d43707 ("'simple' error message functions by Loic Grenie") introduced bb_simple_perror_msg() to allow for a lower overhead call to bb_perror_msg() when only a string was being printed with no parameters. This saves space for some CPU architectures because it avoids the overhead of a call to a variadic function. However there has never been a simple version of bb_error_msg(), and since 2007 many new calls to bb_perror_msg() have been added that only take a single parameter and so could have been using bb_simple_perror_message(). This changeset introduces 'simple' versions of bb_info_msg(), bb_error_msg(), bb_error_msg_and_die(), bb_herror_msg() and bb_herror_msg_and_die(), and replaces all calls that only take a single parameter, or use something like ("%s", arg), with calls to the corresponding 'simple' version. Since it is likely that single parameter calls to the variadic functions may be accidentally reintroduced in the future a new debugging config option WARN_SIMPLE_MSG has been introduced. This uses some macro magic which will cause any such calls to generate a warning, but this is turned off by default to avoid use of the unpleasant macros in normal circumstances. This is a large changeset due to the number of calls that have been replaced. The only files that contain changes other than simple substitution of function calls are libbb.h, libbb/herror_msg.c, libbb/verror_msg.c and libbb/xfuncs_printf.c. In miscutils/devfsd.c, networking/udhcp/common.h and util-linux/mdev.c additonal macros have been added for logging so that single parameter and multiple parameter logging variants exist. The amount of space saved varies considerably by architecture, and was found to be as follows (for 'defconfig' using GCC 7.4): Arm: -92 bytes MIPS: -52 bytes PPC: -1836 bytes x86_64: -938 bytes Note that for the MIPS architecture only an exception had to be made disabling the 'simple' calls for 'udhcp' (in networking/udhcp/common.h) because it made these files larger on MIPS. Signed-off-by: James Byrne <james.byrne@origamienergy.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2019-07-02 15:05:03 +05:30
bb_simple_error_msg("falling back to blocksize "TFTP_BLKSIZE_DEFAULT_STR);
blksize = TFTP_BLKSIZE_DEFAULT;
io_bufsize = TFTP_BLKSIZE_DEFAULT + 4;
}
#endif
/* block_nr is already advanced to next block# we expect
* to get / block# we are about to send next time */
if (CMD_GET(option_mask32) && (opcode == TFTP_DATA)) {
if (recv_blk == block_nr) {
int sz;
if (local_fd == -1) {
local_fd = STDOUT_FILENO;
if (local_file)
local_fd = xopen(local_file, O_WRONLY | O_TRUNC | O_CREAT);
}
sz = full_write(local_fd, &rbuf[4], len - 4);
if (sz != len - 4) {
strcpy(G_error_pkt_str, bb_msg_write_error);
G_error_pkt_reason = ERR_WRITE;
goto send_err_pkt;
}
if (sz != blksize) {
finished = 1;
}
IF_FEATURE_TFTP_PROGRESS_BAR(G.pos += sz;)
continue; /* send ACK */
}
/* Disabled to cope with servers with Sorcerer's Apprentice Syndrome */
#if 0
if (recv_blk == (block_nr - 1)) {
/* Server lost our TFTP_ACK. Resend it */
block_nr = recv_blk;
continue;
2007-05-30 05:59:55 +05:30
}
#endif
}
if (CMD_PUT(option_mask32) && (opcode == TFTP_ACK)) {
/* did peer ACK our last DATA pkt? */
if (recv_blk == (uint16_t) (block_nr - 1)) {
if (finished)
goto ret;
continue; /* send next block */
}
}
/* Awww... recv'd packet is not recognized! */
goto recv_again;
/* why recv_again? - rfc1123 says:
* "The sender (i.e., the side originating the DATA packets)
* must never resend the current DATA packet on receipt
* of a duplicate ACK".
* DATA pkts are resent ONLY on timeout.
* Thus "goto send_again" will be a bad mistake above.
* See:
* http://en.wikipedia.org/wiki/Sorcerer's_Apprentice_Syndrome
*/
} /* end of "while (1)" */
ret:
if (ENABLE_FEATURE_CLEAN_UP) {
close(local_fd);
close(socket_fd);
free(xbuf);
free(rbuf);
}
if (!finished)
goto err;
return EXIT_SUCCESS;
send_read_err_pkt:
strcpy(G_error_pkt_str, bb_msg_read_error);
send_err_pkt:
if (G_error_pkt_str[0])
libbb: reduce the overhead of single parameter bb_error_msg() calls Back in 2007, commit 0c97c9d43707 ("'simple' error message functions by Loic Grenie") introduced bb_simple_perror_msg() to allow for a lower overhead call to bb_perror_msg() when only a string was being printed with no parameters. This saves space for some CPU architectures because it avoids the overhead of a call to a variadic function. However there has never been a simple version of bb_error_msg(), and since 2007 many new calls to bb_perror_msg() have been added that only take a single parameter and so could have been using bb_simple_perror_message(). This changeset introduces 'simple' versions of bb_info_msg(), bb_error_msg(), bb_error_msg_and_die(), bb_herror_msg() and bb_herror_msg_and_die(), and replaces all calls that only take a single parameter, or use something like ("%s", arg), with calls to the corresponding 'simple' version. Since it is likely that single parameter calls to the variadic functions may be accidentally reintroduced in the future a new debugging config option WARN_SIMPLE_MSG has been introduced. This uses some macro magic which will cause any such calls to generate a warning, but this is turned off by default to avoid use of the unpleasant macros in normal circumstances. This is a large changeset due to the number of calls that have been replaced. The only files that contain changes other than simple substitution of function calls are libbb.h, libbb/herror_msg.c, libbb/verror_msg.c and libbb/xfuncs_printf.c. In miscutils/devfsd.c, networking/udhcp/common.h and util-linux/mdev.c additonal macros have been added for logging so that single parameter and multiple parameter logging variants exist. The amount of space saved varies considerably by architecture, and was found to be as follows (for 'defconfig' using GCC 7.4): Arm: -92 bytes MIPS: -52 bytes PPC: -1836 bytes x86_64: -938 bytes Note that for the MIPS architecture only an exception had to be made disabling the 'simple' calls for 'udhcp' (in networking/udhcp/common.h) because it made these files larger on MIPS. Signed-off-by: James Byrne <james.byrne@origamienergy.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2019-07-02 15:05:03 +05:30
bb_simple_error_msg(G_error_pkt_str);
send_err_pkt_nomsg:
G.error_pkt[1] = TFTP_ERROR;
xsendto(socket_fd, G.error_pkt, 4 + 1 + strlen(G_error_pkt_str),
&peer_lsa->u.sa, peer_lsa->len);
err:
if (local_fd >= 0 && CMD_GET(option_mask32) && local_file)
unlink(local_file);
return EXIT_FAILURE;
#undef remote_file
}
#if ENABLE_TFTP
int tftp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2008-07-05 14:48:54 +05:30
int tftp_main(int argc UNUSED_PARAM, char **argv)
{
len_and_sockaddr *peer_lsa;
const char *local_file = NULL;
const char *remote_file = NULL;
# if ENABLE_FEATURE_TFTP_BLOCKSIZE
const char *blksize_str = TFTP_BLKSIZE_DEFAULT_STR;
int blksize;
# endif
int result;
int port;
INIT_G();
if (ENABLE_FEATURE_TFTP_HPA_COMPAT) {
/* As of 2019, common tftp client in Linux distros
* is one maintained by H. Peter Anvin:
* I've seen "tftp-hpa 5.2" version.
* Make the following command work:
* "tftp HOST [PORT] -m binary -c get/put FILE"
* by mangling it into "....... -g/-p -r FILE"
* and accepting and ignoring -m STR option.
*/
unsigned i = 1;
while (argv[i]) {
/* Accept not only -c, but also
* -lc, -cl, -llcclcllcc etc:
* "-l Literal mode (do not recognize HOST:FILE)"
* since we do not recognize that syntax anyway,
* might as well allow the option.
*/
if (argv[i][0] == '-' && strchr(argv[i], 'c')
/*&& argv[i][1+strspn(argv[i]+1, "lc")] == '\0'*/
) {
if (!argv[++i])
break;
if (strcmp(argv[i], "get") == 0) {
argv[i-1] = (char*)"-g";
argv[i] = (char*)"-r";
break;
}
if (strcmp(argv[i], "put") == 0) {
argv[i-1] = (char*)"-p";
argv[i] = (char*)"-r";
break;
}
}
i++;
}
}
getopt32(argv, "^"
IF_FEATURE_TFTP_GET("g") IF_FEATURE_TFTP_PUT("p")
getopt32: remove opt_complementary function old new delta vgetopt32 1318 1392 +74 runsvdir_main 703 713 +10 bb_make_directory 423 425 +2 collect_cpu 546 545 -1 opt_chars 3 - -3 opt_complementary 4 - -4 tftpd_main 567 562 -5 ntp_init 476 471 -5 zcip_main 1266 1256 -10 xxd_main 428 418 -10 whois_main 140 130 -10 who_main 463 453 -10 which_main 212 202 -10 wget_main 2535 2525 -10 watchdog_main 291 281 -10 watch_main 222 212 -10 vlock_main 399 389 -10 uuencode_main 332 322 -10 uudecode_main 316 306 -10 unlink_main 45 35 -10 udhcpd_main 1482 1472 -10 udhcpc_main 2762 2752 -10 tune2fs_main 290 280 -10 tunctl_main 366 356 -10 truncate_main 218 208 -10 tr_main 518 508 -10 time_main 1134 1124 -10 tftp_main 286 276 -10 telnetd_main 1873 1863 -10 tcpudpsvd_main 1785 1775 -10 taskset_main 521 511 -10 tar_main 1009 999 -10 tail_main 1644 1634 -10 syslogd_main 1967 1957 -10 switch_root_main 368 358 -10 svlogd_main 1454 1444 -10 sv 1296 1286 -10 stat_main 104 94 -10 start_stop_daemon_main 1028 1018 -10 split_main 542 532 -10 sort_main 796 786 -10 slattach_main 624 614 -10 shuf_main 504 494 -10 setsid_main 96 86 -10 setserial_main 1132 1122 -10 setfont_main 388 378 -10 setconsole_main 78 68 -10 sendmail_main 1209 1199 -10 sed_main 677 667 -10 script_main 1077 1067 -10 run_parts_main 325 315 -10 rtcwake_main 454 444 -10 rm_main 175 165 -10 reformime_main 119 109 -10 readlink_main 123 113 -10 rdate_main 246 236 -10 pwdx_main 189 179 -10 pstree_main 317 307 -10 pscan_main 663 653 -10 popmaildir_main 818 808 -10 pmap_main 80 70 -10 nc_main 1042 1032 -10 mv_main 558 548 -10 mountpoint_main 477 467 -10 mount_main 1264 1254 -10 modprobe_main 768 758 -10 modinfo_main 333 323 -10 mktemp_main 200 190 -10 mkswap_main 324 314 -10 mkfs_vfat_main 1489 1479 -10 microcom_main 715 705 -10 md5_sha1_sum_main 521 511 -10 man_main 867 857 -10 makedevs_main 1052 1042 -10 ls_main 563 553 -10 losetup_main 432 422 -10 loadfont_main 89 79 -10 ln_main 524 514 -10 link_main 75 65 -10 ipcalc_main 544 534 -10 iostat_main 2397 2387 -10 install_main 768 758 -10 id_main 480 470 -10 i2cset_main 1239 1229 -10 i2cget_main 380 370 -10 i2cdump_main 1482 1472 -10 i2cdetect_main 682 672 -10 hwclock_main 406 396 -10 httpd_main 741 731 -10 grep_main 837 827 -10 getty_main 1559 1549 -10 fuser_main 297 287 -10 ftpgetput_main 345 335 -10 ftpd_main 2232 2222 -10 fstrim_main 251 241 -10 fsfreeze_main 77 67 -10 fsck_minix_main 2921 2911 -10 flock_main 314 304 -10 flashcp_main 740 730 -10 flash_eraseall_main 833 823 -10 fdformat_main 532 522 -10 expand_main 680 670 -10 eject_main 335 325 -10 dumpleases_main 630 620 -10 du_main 314 304 -10 dos2unix_main 441 431 -10 diff_main 1350 1340 -10 df_main 1064 1054 -10 date_main 1095 1085 -10 cut_main 961 951 -10 cryptpw_main 228 218 -10 crontab_main 575 565 -10 crond_main 1149 1139 -10 cp_main 370 360 -10 common_traceroute_main 3834 3824 -10 common_ping_main 1767 1757 -10 comm_main 239 229 -10 cmp_main 655 645 -10 chrt_main 379 369 -10 chpst_main 704 694 -10 chpasswd_main 308 298 -10 chown_main 171 161 -10 chmod_main 158 148 -10 cat_main 428 418 -10 bzip2_main 120 110 -10 blkdiscard_main 264 254 -10 base64_main 221 211 -10 arping_main 1665 1655 -10 ar_main 556 546 -10 adjtimex_main 406 396 -10 adduser_main 882 872 -10 addgroup_main 411 401 -10 acpid_main 1198 1188 -10 optstring 11 - -11 opt_string 18 - -18 OPT_STR 25 - -25 ubi_tools_main 1288 1258 -30 ls_options 31 - -31 ------------------------------------------------------------------------------ (add/remove: 0/6 grow/shrink: 3/129 up/down: 86/-1383) Total: -1297 bytes text data bss dec hex filename 915428 485 6876 922789 e14a5 busybox_old 914629 485 6872 921986 e1182 busybox_unstripped Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2017-08-09 01:25:02 +05:30
"l:r:" IF_FEATURE_TFTP_BLOCKSIZE("b:")
IF_FEATURE_TFTP_HPA_COMPAT("m:")
getopt32: remove opt_complementary function old new delta vgetopt32 1318 1392 +74 runsvdir_main 703 713 +10 bb_make_directory 423 425 +2 collect_cpu 546 545 -1 opt_chars 3 - -3 opt_complementary 4 - -4 tftpd_main 567 562 -5 ntp_init 476 471 -5 zcip_main 1266 1256 -10 xxd_main 428 418 -10 whois_main 140 130 -10 who_main 463 453 -10 which_main 212 202 -10 wget_main 2535 2525 -10 watchdog_main 291 281 -10 watch_main 222 212 -10 vlock_main 399 389 -10 uuencode_main 332 322 -10 uudecode_main 316 306 -10 unlink_main 45 35 -10 udhcpd_main 1482 1472 -10 udhcpc_main 2762 2752 -10 tune2fs_main 290 280 -10 tunctl_main 366 356 -10 truncate_main 218 208 -10 tr_main 518 508 -10 time_main 1134 1124 -10 tftp_main 286 276 -10 telnetd_main 1873 1863 -10 tcpudpsvd_main 1785 1775 -10 taskset_main 521 511 -10 tar_main 1009 999 -10 tail_main 1644 1634 -10 syslogd_main 1967 1957 -10 switch_root_main 368 358 -10 svlogd_main 1454 1444 -10 sv 1296 1286 -10 stat_main 104 94 -10 start_stop_daemon_main 1028 1018 -10 split_main 542 532 -10 sort_main 796 786 -10 slattach_main 624 614 -10 shuf_main 504 494 -10 setsid_main 96 86 -10 setserial_main 1132 1122 -10 setfont_main 388 378 -10 setconsole_main 78 68 -10 sendmail_main 1209 1199 -10 sed_main 677 667 -10 script_main 1077 1067 -10 run_parts_main 325 315 -10 rtcwake_main 454 444 -10 rm_main 175 165 -10 reformime_main 119 109 -10 readlink_main 123 113 -10 rdate_main 246 236 -10 pwdx_main 189 179 -10 pstree_main 317 307 -10 pscan_main 663 653 -10 popmaildir_main 818 808 -10 pmap_main 80 70 -10 nc_main 1042 1032 -10 mv_main 558 548 -10 mountpoint_main 477 467 -10 mount_main 1264 1254 -10 modprobe_main 768 758 -10 modinfo_main 333 323 -10 mktemp_main 200 190 -10 mkswap_main 324 314 -10 mkfs_vfat_main 1489 1479 -10 microcom_main 715 705 -10 md5_sha1_sum_main 521 511 -10 man_main 867 857 -10 makedevs_main 1052 1042 -10 ls_main 563 553 -10 losetup_main 432 422 -10 loadfont_main 89 79 -10 ln_main 524 514 -10 link_main 75 65 -10 ipcalc_main 544 534 -10 iostat_main 2397 2387 -10 install_main 768 758 -10 id_main 480 470 -10 i2cset_main 1239 1229 -10 i2cget_main 380 370 -10 i2cdump_main 1482 1472 -10 i2cdetect_main 682 672 -10 hwclock_main 406 396 -10 httpd_main 741 731 -10 grep_main 837 827 -10 getty_main 1559 1549 -10 fuser_main 297 287 -10 ftpgetput_main 345 335 -10 ftpd_main 2232 2222 -10 fstrim_main 251 241 -10 fsfreeze_main 77 67 -10 fsck_minix_main 2921 2911 -10 flock_main 314 304 -10 flashcp_main 740 730 -10 flash_eraseall_main 833 823 -10 fdformat_main 532 522 -10 expand_main 680 670 -10 eject_main 335 325 -10 dumpleases_main 630 620 -10 du_main 314 304 -10 dos2unix_main 441 431 -10 diff_main 1350 1340 -10 df_main 1064 1054 -10 date_main 1095 1085 -10 cut_main 961 951 -10 cryptpw_main 228 218 -10 crontab_main 575 565 -10 crond_main 1149 1139 -10 cp_main 370 360 -10 common_traceroute_main 3834 3824 -10 common_ping_main 1767 1757 -10 comm_main 239 229 -10 cmp_main 655 645 -10 chrt_main 379 369 -10 chpst_main 704 694 -10 chpasswd_main 308 298 -10 chown_main 171 161 -10 chmod_main 158 148 -10 cat_main 428 418 -10 bzip2_main 120 110 -10 blkdiscard_main 264 254 -10 base64_main 221 211 -10 arping_main 1665 1655 -10 ar_main 556 546 -10 adjtimex_main 406 396 -10 adduser_main 882 872 -10 addgroup_main 411 401 -10 acpid_main 1198 1188 -10 optstring 11 - -11 opt_string 18 - -18 OPT_STR 25 - -25 ubi_tools_main 1288 1258 -30 ls_options 31 - -31 ------------------------------------------------------------------------------ (add/remove: 0/6 grow/shrink: 3/129 up/down: 86/-1383) Total: -1297 bytes text data bss dec hex filename 915428 485 6876 922789 e14a5 busybox_old 914629 485 6872 921986 e1182 busybox_unstripped Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2017-08-09 01:25:02 +05:30
"\0"
/* -p or -g is mandatory, and they are mutually exclusive */
IF_FEATURE_TFTP_GET("g:") IF_FEATURE_TFTP_PUT("p:")
IF_GETPUT("g--p:p--g:"),
&local_file, &remote_file
getopt32: remove opt_complementary function old new delta vgetopt32 1318 1392 +74 runsvdir_main 703 713 +10 bb_make_directory 423 425 +2 collect_cpu 546 545 -1 opt_chars 3 - -3 opt_complementary 4 - -4 tftpd_main 567 562 -5 ntp_init 476 471 -5 zcip_main 1266 1256 -10 xxd_main 428 418 -10 whois_main 140 130 -10 who_main 463 453 -10 which_main 212 202 -10 wget_main 2535 2525 -10 watchdog_main 291 281 -10 watch_main 222 212 -10 vlock_main 399 389 -10 uuencode_main 332 322 -10 uudecode_main 316 306 -10 unlink_main 45 35 -10 udhcpd_main 1482 1472 -10 udhcpc_main 2762 2752 -10 tune2fs_main 290 280 -10 tunctl_main 366 356 -10 truncate_main 218 208 -10 tr_main 518 508 -10 time_main 1134 1124 -10 tftp_main 286 276 -10 telnetd_main 1873 1863 -10 tcpudpsvd_main 1785 1775 -10 taskset_main 521 511 -10 tar_main 1009 999 -10 tail_main 1644 1634 -10 syslogd_main 1967 1957 -10 switch_root_main 368 358 -10 svlogd_main 1454 1444 -10 sv 1296 1286 -10 stat_main 104 94 -10 start_stop_daemon_main 1028 1018 -10 split_main 542 532 -10 sort_main 796 786 -10 slattach_main 624 614 -10 shuf_main 504 494 -10 setsid_main 96 86 -10 setserial_main 1132 1122 -10 setfont_main 388 378 -10 setconsole_main 78 68 -10 sendmail_main 1209 1199 -10 sed_main 677 667 -10 script_main 1077 1067 -10 run_parts_main 325 315 -10 rtcwake_main 454 444 -10 rm_main 175 165 -10 reformime_main 119 109 -10 readlink_main 123 113 -10 rdate_main 246 236 -10 pwdx_main 189 179 -10 pstree_main 317 307 -10 pscan_main 663 653 -10 popmaildir_main 818 808 -10 pmap_main 80 70 -10 nc_main 1042 1032 -10 mv_main 558 548 -10 mountpoint_main 477 467 -10 mount_main 1264 1254 -10 modprobe_main 768 758 -10 modinfo_main 333 323 -10 mktemp_main 200 190 -10 mkswap_main 324 314 -10 mkfs_vfat_main 1489 1479 -10 microcom_main 715 705 -10 md5_sha1_sum_main 521 511 -10 man_main 867 857 -10 makedevs_main 1052 1042 -10 ls_main 563 553 -10 losetup_main 432 422 -10 loadfont_main 89 79 -10 ln_main 524 514 -10 link_main 75 65 -10 ipcalc_main 544 534 -10 iostat_main 2397 2387 -10 install_main 768 758 -10 id_main 480 470 -10 i2cset_main 1239 1229 -10 i2cget_main 380 370 -10 i2cdump_main 1482 1472 -10 i2cdetect_main 682 672 -10 hwclock_main 406 396 -10 httpd_main 741 731 -10 grep_main 837 827 -10 getty_main 1559 1549 -10 fuser_main 297 287 -10 ftpgetput_main 345 335 -10 ftpd_main 2232 2222 -10 fstrim_main 251 241 -10 fsfreeze_main 77 67 -10 fsck_minix_main 2921 2911 -10 flock_main 314 304 -10 flashcp_main 740 730 -10 flash_eraseall_main 833 823 -10 fdformat_main 532 522 -10 expand_main 680 670 -10 eject_main 335 325 -10 dumpleases_main 630 620 -10 du_main 314 304 -10 dos2unix_main 441 431 -10 diff_main 1350 1340 -10 df_main 1064 1054 -10 date_main 1095 1085 -10 cut_main 961 951 -10 cryptpw_main 228 218 -10 crontab_main 575 565 -10 crond_main 1149 1139 -10 cp_main 370 360 -10 common_traceroute_main 3834 3824 -10 common_ping_main 1767 1757 -10 comm_main 239 229 -10 cmp_main 655 645 -10 chrt_main 379 369 -10 chpst_main 704 694 -10 chpasswd_main 308 298 -10 chown_main 171 161 -10 chmod_main 158 148 -10 cat_main 428 418 -10 bzip2_main 120 110 -10 blkdiscard_main 264 254 -10 base64_main 221 211 -10 arping_main 1665 1655 -10 ar_main 556 546 -10 adjtimex_main 406 396 -10 adduser_main 882 872 -10 addgroup_main 411 401 -10 acpid_main 1198 1188 -10 optstring 11 - -11 opt_string 18 - -18 OPT_STR 25 - -25 ubi_tools_main 1288 1258 -30 ls_options 31 - -31 ------------------------------------------------------------------------------ (add/remove: 0/6 grow/shrink: 3/129 up/down: 86/-1383) Total: -1297 bytes text data bss dec hex filename 915428 485 6876 922789 e14a5 busybox_old 914629 485 6872 921986 e1182 busybox_unstripped Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2017-08-09 01:25:02 +05:30
IF_FEATURE_TFTP_BLOCKSIZE(, &blksize_str)
IF_FEATURE_TFTP_HPA_COMPAT(, NULL)
getopt32: remove opt_complementary function old new delta vgetopt32 1318 1392 +74 runsvdir_main 703 713 +10 bb_make_directory 423 425 +2 collect_cpu 546 545 -1 opt_chars 3 - -3 opt_complementary 4 - -4 tftpd_main 567 562 -5 ntp_init 476 471 -5 zcip_main 1266 1256 -10 xxd_main 428 418 -10 whois_main 140 130 -10 who_main 463 453 -10 which_main 212 202 -10 wget_main 2535 2525 -10 watchdog_main 291 281 -10 watch_main 222 212 -10 vlock_main 399 389 -10 uuencode_main 332 322 -10 uudecode_main 316 306 -10 unlink_main 45 35 -10 udhcpd_main 1482 1472 -10 udhcpc_main 2762 2752 -10 tune2fs_main 290 280 -10 tunctl_main 366 356 -10 truncate_main 218 208 -10 tr_main 518 508 -10 time_main 1134 1124 -10 tftp_main 286 276 -10 telnetd_main 1873 1863 -10 tcpudpsvd_main 1785 1775 -10 taskset_main 521 511 -10 tar_main 1009 999 -10 tail_main 1644 1634 -10 syslogd_main 1967 1957 -10 switch_root_main 368 358 -10 svlogd_main 1454 1444 -10 sv 1296 1286 -10 stat_main 104 94 -10 start_stop_daemon_main 1028 1018 -10 split_main 542 532 -10 sort_main 796 786 -10 slattach_main 624 614 -10 shuf_main 504 494 -10 setsid_main 96 86 -10 setserial_main 1132 1122 -10 setfont_main 388 378 -10 setconsole_main 78 68 -10 sendmail_main 1209 1199 -10 sed_main 677 667 -10 script_main 1077 1067 -10 run_parts_main 325 315 -10 rtcwake_main 454 444 -10 rm_main 175 165 -10 reformime_main 119 109 -10 readlink_main 123 113 -10 rdate_main 246 236 -10 pwdx_main 189 179 -10 pstree_main 317 307 -10 pscan_main 663 653 -10 popmaildir_main 818 808 -10 pmap_main 80 70 -10 nc_main 1042 1032 -10 mv_main 558 548 -10 mountpoint_main 477 467 -10 mount_main 1264 1254 -10 modprobe_main 768 758 -10 modinfo_main 333 323 -10 mktemp_main 200 190 -10 mkswap_main 324 314 -10 mkfs_vfat_main 1489 1479 -10 microcom_main 715 705 -10 md5_sha1_sum_main 521 511 -10 man_main 867 857 -10 makedevs_main 1052 1042 -10 ls_main 563 553 -10 losetup_main 432 422 -10 loadfont_main 89 79 -10 ln_main 524 514 -10 link_main 75 65 -10 ipcalc_main 544 534 -10 iostat_main 2397 2387 -10 install_main 768 758 -10 id_main 480 470 -10 i2cset_main 1239 1229 -10 i2cget_main 380 370 -10 i2cdump_main 1482 1472 -10 i2cdetect_main 682 672 -10 hwclock_main 406 396 -10 httpd_main 741 731 -10 grep_main 837 827 -10 getty_main 1559 1549 -10 fuser_main 297 287 -10 ftpgetput_main 345 335 -10 ftpd_main 2232 2222 -10 fstrim_main 251 241 -10 fsfreeze_main 77 67 -10 fsck_minix_main 2921 2911 -10 flock_main 314 304 -10 flashcp_main 740 730 -10 flash_eraseall_main 833 823 -10 fdformat_main 532 522 -10 expand_main 680 670 -10 eject_main 335 325 -10 dumpleases_main 630 620 -10 du_main 314 304 -10 dos2unix_main 441 431 -10 diff_main 1350 1340 -10 df_main 1064 1054 -10 date_main 1095 1085 -10 cut_main 961 951 -10 cryptpw_main 228 218 -10 crontab_main 575 565 -10 crond_main 1149 1139 -10 cp_main 370 360 -10 common_traceroute_main 3834 3824 -10 common_ping_main 1767 1757 -10 comm_main 239 229 -10 cmp_main 655 645 -10 chrt_main 379 369 -10 chpst_main 704 694 -10 chpasswd_main 308 298 -10 chown_main 171 161 -10 chmod_main 158 148 -10 cat_main 428 418 -10 bzip2_main 120 110 -10 blkdiscard_main 264 254 -10 base64_main 221 211 -10 arping_main 1665 1655 -10 ar_main 556 546 -10 adjtimex_main 406 396 -10 adduser_main 882 872 -10 addgroup_main 411 401 -10 acpid_main 1198 1188 -10 optstring 11 - -11 opt_string 18 - -18 OPT_STR 25 - -25 ubi_tools_main 1288 1258 -30 ls_options 31 - -31 ------------------------------------------------------------------------------ (add/remove: 0/6 grow/shrink: 3/129 up/down: 86/-1383) Total: -1297 bytes text data bss dec hex filename 915428 485 6876 922789 e14a5 busybox_old 914629 485 6872 921986 e1182 busybox_unstripped Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2017-08-09 01:25:02 +05:30
);
argv += optind;
# if ENABLE_FEATURE_TFTP_BLOCKSIZE
/* Check if the blksize is valid:
* RFC2348 says between 8 and 65464 */
blksize = tftp_blksize_check(blksize_str, 65564);
if (blksize < 0) {
//bb_error_msg("bad block size");
return EXIT_FAILURE;
}
# endif
if (remote_file) {
if (!local_file) {
const char *slash = strrchr(remote_file, '/');
local_file = slash ? slash + 1 : remote_file;
}
} else {
remote_file = local_file;
}
/* Error if filename or host is not known */
if (!remote_file || !argv[0])
bb_show_usage();
port = bb_lookup_port(argv[1], "udp", 69);
peer_lsa = xhost2sockaddr(argv[0], port);
# if ENABLE_TFTP_DEBUG
fprintf(stderr, "using server '%s', remote_file '%s', local_file '%s'\n",
xmalloc_sockaddr2dotted(&peer_lsa->u.sa),
remote_file, local_file);
# endif
# if ENABLE_FEATURE_TFTP_PROGRESS_BAR
G.file = remote_file;
# endif
result = tftp_protocol(
NULL /*our_lsa*/, peer_lsa,
(LONE_DASH(local_file) ? NULL : local_file), remote_file
IF_FEATURE_TFTP_BLOCKSIZE(, 1 /* want_transfer_size */)
IF_FEATURE_TFTP_BLOCKSIZE(, blksize)
);
tftp_progress_done();
2006-10-06 04:42:49 +05:30
return result;
}
#endif /* ENABLE_TFTP */
#if ENABLE_TFTPD
int tftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2008-07-05 14:48:54 +05:30
int tftpd_main(int argc UNUSED_PARAM, char **argv)
{
len_and_sockaddr *our_lsa;
len_and_sockaddr *peer_lsa;
char *mode, *user_opt;
char *local_file = local_file;
const char *error_msg;
int opt, result, opcode;
IF_FEATURE_TFTP_BLOCKSIZE(int blksize = TFTP_BLKSIZE_DEFAULT;)
IF_FEATURE_TFTP_BLOCKSIZE(int want_transfer_size = 0;)
INIT_G();
our_lsa = get_sock_lsa(STDIN_FILENO);
if (!our_lsa) {
/* This is confusing:
*bb_error_msg_and_die("stdin is not a socket");
* Better: */
bb_show_usage();
/* Help text says that tftpd must be used as inetd service,
* which is by far the most usual cause of get_sock_lsa
* failure */
}
peer_lsa = xzalloc(LSA_LEN_SIZE + our_lsa->len);
peer_lsa->len = our_lsa->len;
/* Shifting to not collide with TFTP_OPTs */
opt = option_mask32 = TFTPD_OPT | (getopt32(argv, "rcu:l", &user_opt) << 8);
argv += optind;
if (opt & TFTPD_OPT_l) {
openlog(applet_name, LOG_PID, LOG_DAEMON);
logmode = LOGMODE_SYSLOG;
}
if (opt & TFTPD_OPT_u) {
/* Must be before xchroot */
G.pw = xgetpwnam(user_opt);
}
if (argv[0]) {
xchroot(argv[0]);
}
result = recv_from_to(STDIN_FILENO,
G.block_buf, sizeof(G.block_buf) + 1,
/* ^^^ sizeof+1 to reliably detect oversized input */
0 /* flags */,
&peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len);
error_msg = "malformed packet";
opcode = ntohs(*(uint16_t*)G.block_buf);
if (result < 4 || result > sizeof(G.block_buf)
/*|| G.block_buf[result-1] != '\0' - bug compatibility, see below */
|| (IF_FEATURE_TFTP_PUT(opcode != TFTP_RRQ) /* not download */
IF_GETPUT(&&)
IF_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */
)
) {
goto err;
}
/* Some HP PA-RISC firmware always sends fixed 516-byte requests,
* with trailing garbage.
* Support that by not requiring NUL to be the last byte (see above).
* To make strXYZ() ops safe, force NUL termination:
*/
G.block_buf_tail[0] = '\0';
local_file = G.block_buf + 2;
if (local_file[0] == '.' || strstr(local_file, "/.")) {
error_msg = "dot in file name";
goto err;
}
mode = local_file + strlen(local_file) + 1;
/* RFC 1350 says mode string is case independent */
if (mode >= G.block_buf + result || strcasecmp(mode, "octet") != 0) {
error_msg = "mode is not 'octet'";
goto err;
}
# if ENABLE_FEATURE_TFTP_BLOCKSIZE
{
char *res;
char *opt_str = mode + sizeof("octet");
int opt_len = G.block_buf + result - opt_str;
if (opt_len > 0) {
res = tftp_get_option("blksize", opt_str, opt_len);
if (res) {
blksize = tftp_blksize_check(res, 65564);
if (blksize < 0) {
G_error_pkt_reason = ERR_BAD_OPT;
/* will just send error pkt */
goto do_proto;
}
}
if (opcode != TFTP_WRQ /* download? */
/* did client ask us about file size? */
&& tftp_get_option("tsize", opt_str, opt_len)
) {
want_transfer_size = 1;
}
}
}
# endif
if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) {
if (opt & TFTPD_OPT_r) {
/* This would mean "disk full" - not true */
/*G_error_pkt_reason = ERR_WRITE;*/
error_msg = bb_msg_write_error;
goto err;
}
IF_GETPUT(option_mask32 |= TFTP_OPT_GET;) /* will receive file's data */
} else {
IF_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */
}
/* NB: if G_error_pkt_str or G_error_pkt_reason is set up,
* tftp_protocol() just sends one error pkt and returns */
do_proto:
close(STDIN_FILENO); /* close old, possibly wildcard socket */
/* tftp_protocol() will create new one, bound to particular local IP */
result = tftp_protocol(
our_lsa, peer_lsa,
local_file
IF_TFTP(, NULL /*remote_file*/)
IF_FEATURE_TFTP_BLOCKSIZE(, want_transfer_size)
IF_FEATURE_TFTP_BLOCKSIZE(, blksize)
);
return result;
err:
strcpy(G_error_pkt_str, error_msg);
goto do_proto;
}
#endif /* ENABLE_TFTPD */
#endif /* ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT */