X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=networking%2Ftftp.c;h=bdba16727bf27da7dc62c7d6330285be0f8ea3b2;hb=c44bc986b738977c5cd9741d9752a41ac022602f;hp=334d03b6ab4e3f6e0d98e7e1034b828fcf283bb7;hpb=f3133c414989a1409d79db43a426f122dc06cbed;p=oweals%2Fbusybox.git diff --git a/networking/tftp.c b/networking/tftp.c index 334d03b6a..bdba16727 100644 --- a/networking/tftp.c +++ b/networking/tftp.c @@ -1,42 +1,29 @@ -/* ------------------------------------------------------------------------- */ -/* tftp.c */ -/* */ -/* A simple tftp client for busybox. */ -/* Tries to follow RFC1350. */ -/* Only "octet" mode supported. */ -/* Optional blocksize negotiation (RFC2347 + RFC2348) */ -/* */ -/* Copyright (C) 2001 Magnus Damm */ -/* */ -/* Parts of the code based on: */ -/* */ -/* atftp: Copyright (C) 2000 Jean-Pierre Lefebvre */ -/* and Remi Lefebvre */ -/* */ -/* utftp: Copyright (C) 1999 Uwe Ohse */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ -/* General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* */ -/* ------------------------------------------------------------------------- */ +/* vi: set sw=4 ts=4: */ +/* ------------------------------------------------------------------------- + * tftp.c + * + * A simple tftp client for busybox. + * Tries to follow RFC1350. + * Only "octet" mode supported. + * Optional blocksize negotiation (RFC2347 + RFC2348) + * + * Copyright (C) 2001 Magnus Damm + * + * Parts of the code based on: + * + * atftp: Copyright (C) 2000 Jean-Pierre Lefebvre + * and Remi Lefebvre + * + * utftp: Copyright (C) 1999 Uwe Ohse + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * ------------------------------------------------------------------------- */ #include #include #include #include #include -#include #include #include #include @@ -60,7 +47,7 @@ #define TFTP_ERROR 5 #define TFTP_OACK 6 -static const char *tftp_bb_error_msg[] = { +static const char * const tftp_bb_error_msg[] = { "Undefined error", "File not found", "Access violation", @@ -71,20 +58,29 @@ static const char *tftp_bb_error_msg[] = { "No such user" }; -static const int tftp_cmd_get = 1; -static const int tftp_cmd_put = 2; +#ifdef CONFIG_FEATURE_TFTP_GET +# define tftp_cmd_get 1 +#else +# define tftp_cmd_get 0 +#endif +#ifdef CONFIG_FEATURE_TFTP_PUT +# define tftp_cmd_put (tftp_cmd_get+1) +#else +# define tftp_cmd_put 0 +#endif + #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE static int tftp_blocksize_check(int blocksize, int bufsize) { - /* Check if the blocksize is valid: + /* Check if the blocksize is valid: * RFC2348 says between 8 and 65464, * but our implementation makes it impossible * to use blocksizes smaller than 22 octets. */ - if ((bufsize && (blocksize > bufsize)) || + if ((bufsize && (blocksize > bufsize)) || (blocksize < 8) || (blocksize > 65464)) { bb_error_msg("bad blocksize"); return 0; @@ -95,7 +91,7 @@ static int tftp_blocksize_check(int blocksize, int bufsize) static char *tftp_option_get(char *buf, int len, char *option) { - int opt_val = 0; + int opt_val = 0; int opt_found = 0; int k; @@ -168,7 +164,7 @@ static inline int tftp(const int cmd, const struct hostent *host, tftp_bufsize += 4; - if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { /* bb_xsocket? */ bb_perror_msg("socket"); return EXIT_FAILURE; } @@ -207,7 +203,7 @@ static inline int tftp(const int cmd, const struct hostent *host, if ((cmd_get && (opcode == TFTP_RRQ)) || (cmd_put && (opcode == TFTP_WRQ))) { - int too_long = 0; + int too_long = 0; /* see if the filename fits into buf */ /* and fill in packet */ @@ -320,7 +316,7 @@ static inline int tftp(const int cmd, const struct hostent *host, FD_ZERO(&rfds); FD_SET(socketfd, &rfds); - switch (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) { + switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { case 1: len = recvfrom(socketfd, buf, tftp_bufsize, 0, (struct sockaddr *) &from, &fromlen); @@ -375,7 +371,7 @@ static inline int tftp(const int cmd, const struct hostent *host, #endif if (opcode == TFTP_ERROR) { - char *msg = NULL; + const char *msg = NULL; if (buf[4] != '\0') { msg = &buf[4]; @@ -383,7 +379,7 @@ static inline int tftp(const int cmd, const struct hostent *host, } else if (tmp < (sizeof(tftp_bb_error_msg) / sizeof(char *))) { - msg = (char *) tftp_bb_error_msg[tmp]; + msg = tftp_bb_error_msg[tmp]; } if (msg) { @@ -409,7 +405,7 @@ static inline int tftp(const int cmd, const struct hostent *host, if (res) { int blksize = atoi(res); - + if (tftp_blocksize_check(blksize, tftp_bufsize - 4)) { @@ -443,7 +439,7 @@ static inline int tftp(const int cmd, const struct hostent *host, if (cmd_get && (opcode == TFTP_DATA)) { if (tmp == block_nr) { - + len = bb_full_write(localfd, &buf[4], len - 4); if (len < 0) { @@ -463,6 +459,11 @@ static inline int tftp(const int cmd, const struct hostent *host, --block_nr; opcode = TFTP_ACK; continue; + } else if (tmp + 1 == block_nr) { + /* Server lost our TFTP_ACK. Resend it */ + block_nr = tmp; + opcode = TFTP_ACK; + continue; } } @@ -482,7 +483,7 @@ static inline int tftp(const int cmd, const struct hostent *host, #ifdef CONFIG_FEATURE_CLEAN_UP close(socketfd); - free(buf); + free(buf); #endif return finished ? EXIT_SUCCESS : EXIT_FAILURE; @@ -497,78 +498,81 @@ int tftp_main(int argc, char **argv) int cmd = 0; int fd = -1; int flags = 0; - int opt; int result; int blocksize = TFTP_BLOCKSIZE_DEFAULT; /* figure out what to pass to getopt */ #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE + char *sblocksize = NULL; #define BS "b:" +#define BS_ARG , &sblocksize #else #define BS +#define BS_ARG #endif #ifdef CONFIG_FEATURE_TFTP_GET #define GET "g" +#define GET_COMPL ":g" #else #define GET +#define GET_COMPL #endif #ifdef CONFIG_FEATURE_TFTP_PUT #define PUT "p" +#define PUT_COMPL ":p" #else #define PUT +#define PUT_COMPL #endif - while ((opt = getopt(argc, argv, BS GET PUT "l:r:")) != -1) { - switch (opt) { +#if defined(CONFIG_FEATURE_TFTP_GET) && defined(CONFIG_FEATURE_TFTP_PUT) + bb_opt_complementally = GET_COMPL PUT_COMPL ":?g--p:p--g"; +#elif defined(CONFIG_FEATURE_TFTP_GET) || defined(CONFIG_FEATURE_TFTP_PUT) + bb_opt_complementally = GET_COMPL PUT_COMPL; +#else + /* XXX: may be should #error ? */ +#endif + + + cmd = bb_getopt_ulflags(argc, argv, GET PUT "l:r:" BS, + &localfile, &remotefile BS_ARG); #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE - case 'b': - blocksize = atoi(optarg); - if (!tftp_blocksize_check(blocksize, 0)) { - return EXIT_FAILURE; - } - break; + if(sblocksize) { + blocksize = atoi(sblocksize); + if (!tftp_blocksize_check(blocksize, 0)) { + return EXIT_FAILURE; + } + } #endif + + cmd &= (tftp_cmd_get | tftp_cmd_put); #ifdef CONFIG_FEATURE_TFTP_GET - case 'g': - cmd = tftp_cmd_get; - flags = O_WRONLY | O_CREAT | O_TRUNC; - break; + if(cmd == tftp_cmd_get) + flags = O_WRONLY | O_CREAT | O_TRUNC; #endif #ifdef CONFIG_FEATURE_TFTP_PUT - case 'p': - cmd = tftp_cmd_put; - flags = O_RDONLY; - break; + if(cmd == tftp_cmd_put) + flags = O_RDONLY; #endif - case 'l': - localfile = optarg; - break; - case 'r': - remotefile = optarg; - break; - } - } - if ((cmd == 0) || (optind == argc)) { - bb_show_usage(); - } - if(localfile && strcmp(localfile, "-") == 0) { - fd = fileno((cmd==tftp_cmd_get)? stdout : stdin); - } if(localfile == NULL) localfile = remotefile; if(remotefile == NULL) remotefile = localfile; - if (fd==-1) { + /* XXX: I corrected this, but may be wrong too. vodz */ + if(localfile==NULL || strcmp(localfile, "-") == 0) { + fd = fileno((cmd==tftp_cmd_get)? stdout : stdin); + } else if (fd==-1) { fd = open(localfile, flags, 0644); } if (fd < 0) { bb_perror_msg_and_die("local file"); } + /* XXX: argv[optind] and/or argv[optind + 1] may be NULL! */ host = xgethostbyname(argv[optind]); port = bb_lookup_port(argv[optind + 1], "udp", 69);