aboutsummaryrefslogtreecommitdiff
path: root/networking/tftp.c
diff options
context:
space:
mode:
authorBernhard Reutner-Fischer <rep.dot.nop@gmail.com>2006-06-10 14:15:03 +0000
committerBernhard Reutner-Fischer <rep.dot.nop@gmail.com>2006-06-10 14:15:03 +0000
commitb25f98a417233f8c470ad61a6e191ff3aa8bd633 (patch)
treedd3a1f2b55d2a34638c89e898b62200e548dfb64 /networking/tftp.c
parent3b1936dcf9d1df4f4a814de3c372258ee63b7cb3 (diff)
downloadbusybox-w32-b25f98a417233f8c470ad61a6e191ff3aa8bd633.tar.gz
busybox-w32-b25f98a417233f8c470ad61a6e191ff3aa8bd633.tar.bz2
busybox-w32-b25f98a417233f8c470ad61a6e191ff3aa8bd633.zip
- fix two segfaults (reported by Horst Kronstorfer)
- remove dangling file if get fails (spotted and fixed by Jason Schoon) - shrink it (Bernhard Fischer) Thanks, all! text data bss dec hex filename 2684 0 0 2684 a7c networking/tftp.o.orig 2748 0 0 2748 abc networking/tftp.o.allfixed 2666 0 0 2666 a6a networking/tftp.o.+shrink
Diffstat (limited to 'networking/tftp.c')
-rw-r--r--networking/tftp.c286
1 files changed, 139 insertions, 147 deletions
diff --git a/networking/tftp.c b/networking/tftp.c
index 527e3dc11..e32c5de38 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -33,13 +33,22 @@
33 33
34#include "busybox.h" 34#include "busybox.h"
35 35
36//#define CONFIG_FEATURE_TFTP_DEBUG
37 36
38#define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */ 37#define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */
39#define TFTP_TIMEOUT 5 /* seconds */ 38#define TFTP_TIMEOUT 5 /* seconds */
39#define TFTP_NUM_RETRIES 5 /* number of retries */
40 40
41/* opcodes we support */ 41/* RFC2348 says between 8 and 65464 */
42#define TFTP_OCTECTS_MIN 8
43#define TFTP_OCTECTS_MAX 65464
44
45static const char * const MODE_OCTET = "octet";
46#define MODE_OCTET_LEN 6 /* sizeof(MODE_OCTET)*/
42 47
48static const char * const OPTION_BLOCKSIZE = "blksize";
49#define OPTION_BLOCKSIZE_LEN 8 /* sizeof(OPTION_BLOCKSIZE) */
50
51/* opcodes we support */
43#define TFTP_RRQ 1 52#define TFTP_RRQ 1
44#define TFTP_WRQ 2 53#define TFTP_WRQ 2
45#define TFTP_DATA 3 54#define TFTP_DATA 3
@@ -47,7 +56,7 @@
47#define TFTP_ERROR 5 56#define TFTP_ERROR 5
48#define TFTP_OACK 6 57#define TFTP_OACK 6
49 58
50static const char * const tftp_bb_error_msg[] = { 59static const char *const tftp_bb_error_msg[] = {
51 "Undefined error", 60 "Undefined error",
52 "File not found", 61 "File not found",
53 "Access violation", 62 "Access violation",
@@ -58,13 +67,10 @@ static const char * const tftp_bb_error_msg[] = {
58 "No such user" 67 "No such user"
59}; 68};
60 69
61#ifdef CONFIG_FEATURE_TFTP_GET 70#define tftp_cmd_get ENABLE_FEATURE_TFTP_GET
62# define tftp_cmd_get 1 71
63#else 72#if ENABLE_FEATURE_TFTP_PUT
64# define tftp_cmd_get 0 73# define tftp_cmd_put (tftp_cmd_get+ENABLE_FEATURE_TFTP_PUT)
65#endif
66#ifdef CONFIG_FEATURE_TFTP_PUT
67# define tftp_cmd_put (tftp_cmd_get+1)
68#else 74#else
69# define tftp_cmd_put 0 75# define tftp_cmd_put 0
70#endif 76#endif
@@ -81,15 +87,15 @@ static int tftp_blocksize_check(int blocksize, int bufsize)
81 */ 87 */
82 88
83 if ((bufsize && (blocksize > bufsize)) || 89 if ((bufsize && (blocksize > bufsize)) ||
84 (blocksize < 8) || (blocksize > 65464)) { 90 (blocksize < TFTP_OCTECTS_MIN) || (blocksize > TFTP_OCTECTS_MAX)) {
85 bb_error_msg("bad blocksize"); 91 bb_error_msg("bad blocksize");
86 return 0; 92 return 0;
87 } 93 }
88 94
89 return blocksize; 95 return blocksize;
90} 96}
91 97
92static char *tftp_option_get(char *buf, int len, char *option) 98static char *tftp_option_get(char *buf, int len, const char const *option)
93{ 99{
94 int opt_val = 0; 100 int opt_val = 0;
95 int opt_found = 0; 101 int opt_found = 0;
@@ -97,25 +103,24 @@ static char *tftp_option_get(char *buf, int len, char *option)
97 103
98 while (len > 0) { 104 while (len > 0) {
99 105
100 /* Make sure the options are terminated correctly */ 106 /* Make sure the options are terminated correctly */
101 107
102 for (k = 0; k < len; k++) { 108 for (k = 0; k < len; k++) {
103 if (buf[k] == '\0') { 109 if (buf[k] == '\0') {
104 break; 110 break;
105 } 111 }
106 } 112 }
107 113
108 if (k >= len) { 114 if (k >= len) {
109 break; 115 break;
110 } 116 }
111 117
112 if (opt_val == 0) { 118 if (opt_val == 0) {
113 if (strcasecmp(buf, option) == 0) { 119 if (strcasecmp(buf, option) == 0) {
114 opt_found = 1; 120 opt_found = 1;
115 } 121 }
116 } 122 } else {
117 else { 123 if (opt_found) {
118 if (opt_found) {
119 return buf; 124 return buf;
120 } 125 }
121 } 126 }
@@ -133,38 +138,34 @@ static char *tftp_option_get(char *buf, int len, char *option)
133 138
134#endif 139#endif
135 140
136static inline int tftp(const int cmd, const struct hostent *host, 141static int tftp(const int cmd, const struct hostent *host,
137 const char *remotefile, int localfd, const unsigned short port, int tftp_bufsize) 142 const char *remotefile, const int localfd,
143 const unsigned short port, int tftp_bufsize)
138{ 144{
139 const int cmd_get = cmd & tftp_cmd_get; 145#define cmd_get cmd & tftp_cmd_get
140 const int cmd_put = cmd & tftp_cmd_put; 146#define cmd_put cmd & tftp_cmd_put
141 const int bb_tftp_num_retries = 5;
142
143 struct sockaddr_in sa; 147 struct sockaddr_in sa;
144 struct sockaddr_in from; 148 struct sockaddr_in from;
145 struct timeval tv; 149 struct timeval tv;
146 socklen_t fromlen; 150 socklen_t fromlen;
147 fd_set rfds; 151 fd_set rfds;
148 char *cp;
149 unsigned short tmp;
150 int socketfd; 152 int socketfd;
151 int len; 153 int len, itmp;
152 int opcode = 0; 154 int opcode = 0;
153 int finished = 0; 155 int finished = 0;
154 int timeout = bb_tftp_num_retries; 156 int timeout = TFTP_NUM_RETRIES;
155 unsigned short block_nr = 1; 157 unsigned short block_nr = 1;
158 unsigned short tmp;
159 char *cp;
156 160
157#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE 161 USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;)
158 int want_option_ack = 0;
159#endif
160 162
161 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation 163 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
162 * size varies meaning BUFFERS_GO_ON_STACK would fail */ 164 * size varies meaning BUFFERS_GO_ON_STACK would fail */
163 char *buf=xmalloc(tftp_bufsize + 4); 165 char *buf=xmalloc(tftp_bufsize += 4);
164
165 tftp_bufsize += 4;
166 166
167 if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { /* bb_xsocket? */ 167 if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
168 /* need to unlink the localfile, so don't use bb_xsocket here. */
168 bb_perror_msg("socket"); 169 bb_perror_msg("socket");
169 return EXIT_FAILURE; 170 return EXIT_FAILURE;
170 } 171 }
@@ -180,11 +181,9 @@ static inline int tftp(const int cmd, const struct hostent *host,
180 sizeof(sa.sin_addr)); 181 sizeof(sa.sin_addr));
181 182
182 /* build opcode */ 183 /* build opcode */
183
184 if (cmd_get) { 184 if (cmd_get) {
185 opcode = TFTP_RRQ; 185 opcode = TFTP_RRQ;
186 } 186 }
187
188 if (cmd_put) { 187 if (cmd_put) {
189 opcode = TFTP_WRQ; 188 opcode = TFTP_WRQ;
190 } 189 }
@@ -194,56 +193,49 @@ static inline int tftp(const int cmd, const struct hostent *host,
194 cp = buf; 193 cp = buf;
195 194
196 /* first create the opcode part */ 195 /* first create the opcode part */
197
198 *((unsigned short *) cp) = htons(opcode); 196 *((unsigned short *) cp) = htons(opcode);
199
200 cp += 2; 197 cp += 2;
201 198
202 /* add filename and mode */ 199 /* add filename and mode */
203 200 if (((cmd_get) && (opcode == TFTP_RRQ)) ||
204 if ((cmd_get && (opcode == TFTP_RRQ)) || 201 ((cmd_put) && (opcode == TFTP_WRQ)))
205 (cmd_put && (opcode == TFTP_WRQ))) { 202 {
206 int too_long = 0; 203 int too_long = 0;
207 204
208 /* see if the filename fits into buf */ 205 /* see if the filename fits into buf
209 /* and fill in packet */ 206 * and fill in packet. */
210
211 len = strlen(remotefile) + 1; 207 len = strlen(remotefile) + 1;
212 208
213 if ((cp + len) >= &buf[tftp_bufsize - 1]) { 209 if ((cp + len) >= &buf[tftp_bufsize - 1]) {
214 too_long = 1; 210 too_long = 1;
215 } 211 } else {
216 else { 212 safe_strncpy(cp, remotefile, len);
217 safe_strncpy(cp, remotefile, len);
218 cp += len; 213 cp += len;
219 } 214 }
220 215
221 if (too_long || ((&buf[tftp_bufsize - 1] - cp) < 6)) { 216 if (too_long || ((&buf[tftp_bufsize - 1] - cp) < MODE_OCTET_LEN)) {
222 bb_error_msg("too long remote-filename"); 217 bb_error_msg("remote filename too long");
223 break; 218 break;
224 } 219 }
225 220
226 /* add "mode" part of the package */ 221 /* add "mode" part of the package */
227 222 memcpy(cp, MODE_OCTET, MODE_OCTET_LEN);
228 memcpy(cp, "octet", 6); 223 cp += MODE_OCTET_LEN;
229 cp += 6;
230 224
231#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE 225#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
232 226
233 len = tftp_bufsize - 4; /* data block size */ 227 len = tftp_bufsize - 4; /* data block size */
234 228
235 if (len != TFTP_BLOCKSIZE_DEFAULT) { 229 if (len != TFTP_BLOCKSIZE_DEFAULT) {
236 230
237 if ((&buf[tftp_bufsize - 1] - cp) < 15) { 231 if ((&buf[tftp_bufsize - 1] - cp) < 15) {
238 bb_error_msg("too long remote-filename"); 232 bb_error_msg("remote filename too long");
239 break; 233 break;
240 } 234 }
241 235
242 /* add "blksize" + number of blocks */ 236 /* add "blksize" + number of blocks */
243 237 memcpy(cp, OPTION_BLOCKSIZE, OPTION_BLOCKSIZE_LEN);
244 memcpy(cp, "blksize", 8); 238 cp += OPTION_BLOCKSIZE_LEN;
245 cp += 8;
246
247 cp += snprintf(cp, 6, "%d", len) + 1; 239 cp += snprintf(cp, 6, "%d", len) + 1;
248 240
249 want_option_ack = 1; 241 want_option_ack = 1;
@@ -253,8 +245,8 @@ static inline int tftp(const int cmd, const struct hostent *host,
253 245
254 /* add ack and data */ 246 /* add ack and data */
255 247
256 if ((cmd_get && (opcode == TFTP_ACK)) || 248 if (((cmd_get) && (opcode == TFTP_ACK)) ||
257 (cmd_put && (opcode == TFTP_DATA))) { 249 ((cmd_put) && (opcode == TFTP_DATA))) {
258 250
259 *((unsigned short *) cp) = htons(block_nr); 251 *((unsigned short *) cp) = htons(block_nr);
260 252
@@ -262,7 +254,7 @@ static inline int tftp(const int cmd, const struct hostent *host,
262 254
263 block_nr++; 255 block_nr++;
264 256
265 if (cmd_put && (opcode == TFTP_DATA)) { 257 if ((cmd_put) && (opcode == TFTP_DATA)) {
266 len = bb_full_read(localfd, cp, tftp_bufsize - 4); 258 len = bb_full_read(localfd, cp, tftp_bufsize - 4);
267 259
268 if (len < 0) { 260 if (len < 0) {
@@ -282,7 +274,7 @@ static inline int tftp(const int cmd, const struct hostent *host,
282 /* send packet */ 274 /* send packet */
283 275
284 276
285 timeout = bb_tftp_num_retries; /* re-initialize */ 277 timeout = TFTP_NUM_RETRIES; /* re-initialize */
286 do { 278 do {
287 279
288 len = cp - buf; 280 len = cp - buf;
@@ -290,11 +282,11 @@ static inline int tftp(const int cmd, const struct hostent *host,
290#ifdef CONFIG_FEATURE_TFTP_DEBUG 282#ifdef CONFIG_FEATURE_TFTP_DEBUG
291 fprintf(stderr, "sending %u bytes\n", len); 283 fprintf(stderr, "sending %u bytes\n", len);
292 for (cp = buf; cp < &buf[len]; cp++) 284 for (cp = buf; cp < &buf[len]; cp++)
293 fprintf(stderr, "%02x ", (unsigned char)*cp); 285 fprintf(stderr, "%02x ", (unsigned char) *cp);
294 fprintf(stderr, "\n"); 286 fprintf(stderr, "\n");
295#endif 287#endif
296 if (sendto(socketfd, buf, len, 0, 288 if (sendto(socketfd, buf, len, 0,
297 (struct sockaddr *) &sa, sizeof(sa)) < 0) { 289 (struct sockaddr *) &sa, sizeof(sa)) < 0) {
298 bb_perror_msg("send"); 290 bb_perror_msg("send");
299 len = -1; 291 len = -1;
300 break; 292 break;
@@ -316,10 +308,10 @@ static inline int tftp(const int cmd, const struct hostent *host,
316 FD_ZERO(&rfds); 308 FD_ZERO(&rfds);
317 FD_SET(socketfd, &rfds); 309 FD_SET(socketfd, &rfds);
318 310
319 switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { 311 itmp = select(socketfd + 1, &rfds, NULL, NULL, &tv);
320 case 1: 312 if (itmp == 1) {
321 len = recvfrom(socketfd, buf, tftp_bufsize, 0, 313 len = recvfrom(socketfd, buf, tftp_bufsize, 0,
322 (struct sockaddr *) &from, &fromlen); 314 (struct sockaddr *) &from, &fromlen);
323 315
324 if (len < 0) { 316 if (len < 0) {
325 bb_perror_msg("recvfrom"); 317 bb_perror_msg("recvfrom");
@@ -337,9 +329,9 @@ static inline int tftp(const int cmd, const struct hostent *host,
337 329
338 /* fall-through for bad packets! */ 330 /* fall-through for bad packets! */
339 /* discard the packet - treat as timeout */ 331 /* discard the packet - treat as timeout */
340 timeout = bb_tftp_num_retries; 332 timeout = TFTP_NUM_RETRIES;
341 333
342 case 0: 334 } else if (itmp == 0) {
343 bb_error_msg("timeout"); 335 bb_error_msg("timeout");
344 336
345 timeout--; 337 timeout--;
@@ -349,7 +341,7 @@ static inline int tftp(const int cmd, const struct hostent *host,
349 } 341 }
350 break; 342 break;
351 343
352 default: 344 } else {
353 bb_perror_msg("select"); 345 bb_perror_msg("select");
354 len = -1; 346 len = -1;
355 } 347 }
@@ -362,7 +354,6 @@ static inline int tftp(const int cmd, const struct hostent *host,
362 354
363 /* process received packet */ 355 /* process received packet */
364 356
365
366 opcode = ntohs(*((unsigned short *) buf)); 357 opcode = ntohs(*((unsigned short *) buf));
367 tmp = ntohs(*((unsigned short *) &buf[2])); 358 tmp = ntohs(*((unsigned short *) &buf[2]));
368 359
@@ -377,7 +368,7 @@ static inline int tftp(const int cmd, const struct hostent *host,
377 msg = &buf[4]; 368 msg = &buf[4];
378 buf[tftp_bufsize - 1] = '\0'; 369 buf[tftp_bufsize - 1] = '\0';
379 } else if (tmp < (sizeof(tftp_bb_error_msg) 370 } else if (tmp < (sizeof(tftp_bb_error_msg)
380 / sizeof(char *))) { 371 / sizeof(char *))) {
381 372
382 msg = tftp_bb_error_msg[tmp]; 373 msg = tftp_bb_error_msg[tmp];
383 } 374 }
@@ -388,55 +379,52 @@ static inline int tftp(const int cmd, const struct hostent *host,
388 379
389 break; 380 break;
390 } 381 }
391
392#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE 382#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
393 if (want_option_ack) { 383 if (want_option_ack) {
394 384
395 want_option_ack = 0; 385 want_option_ack = 0;
396 386
397 if (opcode == TFTP_OACK) { 387 if (opcode == TFTP_OACK) {
398 388
399 /* server seems to support options */ 389 /* server seems to support options */
400 390
401 char *res; 391 char *res;
402 392
403 res = tftp_option_get(&buf[2], len-2, 393 res = tftp_option_get(&buf[2], len - 2, OPTION_BLOCKSIZE);
404 "blksize");
405 394
406 if (res) { 395 if (res) {
407 int blksize = atoi(res); 396 int blksize = atoi(res);
408 397
409 if (tftp_blocksize_check(blksize, 398 if (tftp_blocksize_check(blksize, tftp_bufsize - 4)) {
410 tftp_bufsize - 4)) {
411 399
412 if (cmd_put) { 400 if (cmd_put) {
413 opcode = TFTP_DATA; 401 opcode = TFTP_DATA;
414 } 402 } else {
415 else { 403 opcode = TFTP_ACK;
416 opcode = TFTP_ACK; 404 }
417 }
418#ifdef CONFIG_FEATURE_TFTP_DEBUG 405#ifdef CONFIG_FEATURE_TFTP_DEBUG
419 fprintf(stderr, "using blksize %u\n", blksize); 406 fprintf(stderr, "using %s %u\n", OPTION_BLOCKSIZE,
407 blksize);
420#endif 408#endif
421 tftp_bufsize = blksize + 4; 409 tftp_bufsize = blksize + 4;
422 block_nr = 0; 410 block_nr = 0;
423 continue; 411 continue;
424 } 412 }
425 } 413 }
426 /* FIXME: 414 /* FIXME:
427 * we should send ERROR 8 */ 415 * we should send ERROR 8 */
428 bb_error_msg("bad server option"); 416 bb_error_msg("bad server option");
429 break; 417 break;
430 } 418 }
431 419
432 bb_error_msg("warning: blksize not supported by server" 420 bb_error_msg("warning: blksize not supported by server"
433 " - reverting to 512"); 421 " - reverting to 512");
434 422
435 tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4; 423 tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4;
436 } 424 }
437#endif 425#endif
438 426
439 if (cmd_get && (opcode == TFTP_DATA)) { 427 if ((cmd_get) && (opcode == TFTP_DATA)) {
440 428
441 if (tmp == block_nr) { 429 if (tmp == block_nr) {
442 430
@@ -455,7 +443,7 @@ static inline int tftp(const int cmd, const struct hostent *host,
455 continue; 443 continue;
456 } 444 }
457 /* in case the last ack disappeared into the ether */ 445 /* in case the last ack disappeared into the ether */
458 if ( tmp == (block_nr - 1) ) { 446 if (tmp == (block_nr - 1)) {
459 --block_nr; 447 --block_nr;
460 opcode = TFTP_ACK; 448 opcode = TFTP_ACK;
461 continue; 449 continue;
@@ -467,9 +455,9 @@ static inline int tftp(const int cmd, const struct hostent *host,
467 } 455 }
468 } 456 }
469 457
470 if (cmd_put && (opcode == TFTP_ACK)) { 458 if ((cmd_put) && (opcode == TFTP_ACK)) {
471 459
472 if (tmp == (unsigned short)(block_nr - 1)) { 460 if (tmp == (unsigned short) (block_nr - 1)) {
473 if (finished) { 461 if (finished) {
474 break; 462 break;
475 } 463 }
@@ -482,7 +470,6 @@ static inline int tftp(const int cmd, const struct hostent *host,
482 470
483#ifdef CONFIG_FEATURE_CLEAN_UP 471#ifdef CONFIG_FEATURE_CLEAN_UP
484 close(socketfd); 472 close(socketfd);
485
486 free(buf); 473 free(buf);
487#endif 474#endif
488 475
@@ -505,6 +492,7 @@ int tftp_main(int argc, char **argv)
505 492
506#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE 493#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
507 char *sblocksize = NULL; 494 char *sblocksize = NULL;
495
508#define BS "b:" 496#define BS "b:"
509#define BS_ARG , &sblocksize 497#define BS_ARG , &sblocksize
510#else 498#else
@@ -533,62 +521,66 @@ int tftp_main(int argc, char **argv)
533#elif defined(CONFIG_FEATURE_TFTP_GET) || defined(CONFIG_FEATURE_TFTP_PUT) 521#elif defined(CONFIG_FEATURE_TFTP_GET) || defined(CONFIG_FEATURE_TFTP_PUT)
534 bb_opt_complementally = GET_COMPL PUT_COMPL; 522 bb_opt_complementally = GET_COMPL PUT_COMPL;
535#else 523#else
536 /* XXX: may be should #error ? */ 524#error "Either CONFIG_FEATURE_TFTP_GET or CONFIG_FEATURE_TFTP_PUT must be defined"
537#endif 525#endif
538 526
539 527
540 cmd = bb_getopt_ulflags(argc, argv, GET PUT "l:r:" BS, 528 cmd = bb_getopt_ulflags(argc, argv, GET PUT "l:r:" BS,
541 &localfile, &remotefile BS_ARG); 529 &localfile, &remotefile BS_ARG);
542#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
543 if(sblocksize) {
544 blocksize = atoi(sblocksize);
545 if (!tftp_blocksize_check(blocksize, 0)) {
546 return EXIT_FAILURE;
547 }
548 }
549#endif
550 530
551 cmd &= (tftp_cmd_get | tftp_cmd_put); 531 cmd &= (tftp_cmd_get | tftp_cmd_put);
552#ifdef CONFIG_FEATURE_TFTP_GET 532#ifdef CONFIG_FEATURE_TFTP_GET
553 if(cmd == tftp_cmd_get) 533 if (cmd == tftp_cmd_get)
554 flags = O_WRONLY | O_CREAT | O_TRUNC; 534 flags = O_WRONLY | O_CREAT | O_TRUNC;
555#endif 535#endif
556#ifdef CONFIG_FEATURE_TFTP_PUT 536#ifdef CONFIG_FEATURE_TFTP_PUT
557 if(cmd == tftp_cmd_put) 537 if (cmd == tftp_cmd_put)
558 flags = O_RDONLY; 538 flags = O_RDONLY;
559#endif 539#endif
560 540
561 if(localfile == NULL) 541#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
562 localfile = remotefile; 542 if (sblocksize) {
563 if(remotefile == NULL) 543 blocksize = atoi(sblocksize);
564 remotefile = localfile; 544 if (!tftp_blocksize_check(blocksize, 0)) {
565 /* XXX: I corrected this, but may be wrong too. vodz */ 545 return EXIT_FAILURE;
566 if(localfile==NULL || strcmp(localfile, "-") == 0) { 546 }
567 fd = fileno((cmd==tftp_cmd_get)? stdout : stdin); 547 }
568 } else if (fd==-1) { 548#endif
569 fd = open(localfile, flags, 0644); 549
550 if (localfile == NULL)
551 localfile = remotefile;
552 if (remotefile == NULL)
553 remotefile = localfile;
554 if ((localfile == NULL && remotefile == NULL) || (argv[optind] == NULL))
555 bb_show_usage();
556
557 if (localfile == NULL || strcmp(localfile, "-") == 0) {
558 fd = (cmd == tftp_cmd_get) ? STDOUT_FILENO : STDIN_FILENO;
559 } else {
560 fd = open(localfile, flags, 0644); /* fail below */
570 } 561 }
571 if (fd < 0) { 562 if (fd < 0) {
572 bb_perror_msg_and_die("local file"); 563 bb_perror_msg_and_die("local file");
573 } 564 }
574 565
575 /* XXX: argv[optind] and/or argv[optind + 1] may be NULL! */
576 host = xgethostbyname(argv[optind]); 566 host = xgethostbyname(argv[optind]);
577 port = bb_lookup_port(argv[optind + 1], "udp", 69); 567 port = bb_lookup_port(argv[optind + 1], "udp", 69);
578 568
579#ifdef CONFIG_FEATURE_TFTP_DEBUG 569#ifdef CONFIG_FEATURE_TFTP_DEBUG
580 fprintf(stderr, "using server \"%s\", remotefile \"%s\", " 570 fprintf(stderr, "using server \"%s\", remotefile \"%s\", "
581 "localfile \"%s\".\n", 571 "localfile \"%s\".\n",
582 inet_ntoa(*((struct in_addr *) host->h_addr)), 572 inet_ntoa(*((struct in_addr *) host->h_addr)),
583 remotefile, localfile); 573 remotefile, localfile);
584#endif 574#endif
585 575
586 result = tftp(cmd, host, remotefile, fd, port, blocksize); 576 result = tftp(cmd, host, remotefile, fd, port, blocksize);
587 577
588#ifdef CONFIG_FEATURE_CLEAN_UP 578#ifdef CONFIG_FEATURE_CLEAN_UP
589 if (!(fd == STDOUT_FILENO || fd == STDIN_FILENO)) { 579 if (!(fd == STDOUT_FILENO || fd == STDIN_FILENO)) {
590 close(fd); 580 close(fd);
591 } 581 }
592#endif 582#endif
593 return(result); 583 if (cmd == tftp_cmd_get && result != EXIT_SUCCESS)
584 unlink(localfile);
585 return (result);
594} 586}