blob: 1e1105b4548993e3233281e499795a4639adfc42 [file] [log] [blame]
Mark Whitley450736c2001-03-02 19:08:50 +00001/* ------------------------------------------------------------------------- */
2/* tftp.c */
3/* */
4/* A simple tftp client for busybox. */
5/* Tries to follow RFC1350. */
Glenn L McGrathad117d82001-10-05 04:40:37 +00006/* Only "octet" mode supported. */
7/* Optional blocksize negotiation (RFC2347 + RFC2348) */
Mark Whitley450736c2001-03-02 19:08:50 +00008/* */
9/* Copyright (C) 2001 Magnus Damm <damm@opensource.se> */
10/* */
11/* Parts of the code based on: */
12/* */
13/* atftp: Copyright (C) 2000 Jean-Pierre Lefebvre <helix@step.polymtl.ca> */
14/* and Remi Lefebvre <remi@debian.org> */
15/* */
16/* utftp: Copyright (C) 1999 Uwe Ohse <uwe@ohse.de> */
17/* */
18/* This program is free software; you can redistribute it and/or modify */
19/* it under the terms of the GNU General Public License as published by */
20/* the Free Software Foundation; either version 2 of the License, or */
21/* (at your option) any later version. */
22/* */
23/* This program is distributed in the hope that it will be useful, */
24/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
25/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
26/* General Public License for more details. */
27/* */
28/* You should have received a copy of the GNU General Public License */
29/* along with this program; if not, write to the Free Software */
30/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
31/* */
32/* ------------------------------------------------------------------------- */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <sys/types.h>
38#include <sys/socket.h>
39#include <sys/time.h>
40#include <sys/stat.h>
41#include <netdb.h>
42#include <netinet/in.h>
43#include <arpa/inet.h>
44#include <unistd.h>
45#include <fcntl.h>
46
47#include "busybox.h"
48
Eric Andersenbdfd0d72001-10-24 05:00:29 +000049//#define CONFIG_FEATURE_TFTP_DEBUG
Mark Whitley450736c2001-03-02 19:08:50 +000050
Glenn L McGrathad117d82001-10-05 04:40:37 +000051#define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */
52#define TFTP_TIMEOUT 5 /* seconds */
53
54/* opcodes we support */
55
56#define TFTP_RRQ 1
57#define TFTP_WRQ 2
58#define TFTP_DATA 3
59#define TFTP_ACK 4
60#define TFTP_ERROR 5
61#define TFTP_OACK 6
62
Mark Whitley450736c2001-03-02 19:08:50 +000063static const char *tftp_error_msg[] = {
64 "Undefined error",
65 "File not found",
66 "Access violation",
67 "Disk full or allocation error",
68 "Illegal TFTP operation",
69 "Unknown transfer ID",
70 "File already exists",
71 "No such user"
72};
73
Eric Andersen76fa8ea2001-08-20 17:47:49 +000074const int tftp_cmd_get = 1;
75const int tftp_cmd_put = 2;
76
Eric Andersenbdfd0d72001-10-24 05:00:29 +000077#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
Glenn L McGrathad117d82001-10-05 04:40:37 +000078
79static int tftp_blocksize_check(int blocksize, int bufsize)
80{
81 /* Check if the blocksize is valid:
82 * RFC2348 says between 8 and 65464,
83 * but our implementation makes it impossible
84 * to use blocksizes smaller than 22 octets.
85 */
86
87 if ((bufsize && (blocksize > bufsize)) ||
88 (blocksize < 8) || (blocksize > 65464)) {
89 error_msg("bad blocksize");
90 return 0;
91 }
92
93 return blocksize;
94}
95
96static char *tftp_option_get(char *buf, int len, char *option)
97{
98 int opt_val = 0;
99 int opt_found = 0;
100 int k;
101
102 while (len > 0) {
103
104 /* Make sure the options are terminated correctly */
105
106 for (k = 0; k < len; k++) {
107 if (buf[k] == '\0') {
108 break;
109 }
110 }
111
112 if (k >= len) {
113 break;
114 }
115
116 if (opt_val == 0) {
117 if (strcasecmp(buf, option) == 0) {
118 opt_found = 1;
119 }
120 }
121 else {
122 if (opt_found) {
123 return buf;
124 }
125 }
126
127 k++;
128
129 buf += k;
130 len -= k;
131
132 opt_val ^= 1;
133 }
134
135 return NULL;
136}
137
138#endif
139
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000140static inline int tftp(const int cmd, const struct hostent *host,
Glenn L McGrathad117d82001-10-05 04:40:37 +0000141 const char *remotefile, int localfd, const int port, int tftp_bufsize)
Mark Whitley450736c2001-03-02 19:08:50 +0000142{
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000143 const int cmd_get = cmd & tftp_cmd_get;
144 const int cmd_put = cmd & tftp_cmd_put;
145 const int bb_tftp_num_retries = 5;
146
Mark Whitley450736c2001-03-02 19:08:50 +0000147 struct sockaddr_in sa;
Mark Whitley450736c2001-03-02 19:08:50 +0000148 struct sockaddr_in from;
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000149 struct timeval tv;
Mark Whitley450736c2001-03-02 19:08:50 +0000150 socklen_t fromlen;
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000151 fd_set rfds;
Mark Whitley450736c2001-03-02 19:08:50 +0000152 char *cp;
153 unsigned short tmp;
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000154 int socketfd;
155 int len;
156 int opcode = 0;
157 int finished = 0;
158 int timeout = bb_tftp_num_retries;
159 int block_nr = 1;
Glenn L McGrathad117d82001-10-05 04:40:37 +0000160
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000161#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
Glenn L McGrathad117d82001-10-05 04:40:37 +0000162 int want_option_ack = 0;
163#endif
164
Eric Andersen744a1942001-11-10 11:16:39 +0000165 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
166 * size varies meaning BUFFERS_GO_ON_STACK would fail */
167 char *buf=xmalloc(tftp_bufsize + 4);
Mark Whitley450736c2001-03-02 19:08:50 +0000168
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000169 tftp_bufsize += 4;
Mark Whitley450736c2001-03-02 19:08:50 +0000170
171 if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
172 perror_msg("socket");
Mark Whitley8bb7df42001-03-06 20:58:48 +0000173 return EXIT_FAILURE;
Mark Whitley450736c2001-03-02 19:08:50 +0000174 }
175
176 len = sizeof(sa);
177
178 memset(&sa, 0, len);
Eric Andersene76c3b02001-04-05 03:14:39 +0000179 bind(socketfd, (struct sockaddr *)&sa, len);
Mark Whitley450736c2001-03-02 19:08:50 +0000180
181 sa.sin_family = host->h_addrtype;
182 sa.sin_port = htons(port);
183 memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr,
184 sizeof(sa.sin_addr));
185
186 /* build opcode */
187
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000188 if (cmd_get) {
Glenn L McGrathad117d82001-10-05 04:40:37 +0000189 opcode = TFTP_RRQ;
Mark Whitley450736c2001-03-02 19:08:50 +0000190 }
191
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000192 if (cmd_put) {
Glenn L McGrathad117d82001-10-05 04:40:37 +0000193 opcode = TFTP_WRQ;
Mark Whitley450736c2001-03-02 19:08:50 +0000194 }
195
196 while (1) {
197
Mark Whitley450736c2001-03-02 19:08:50 +0000198 cp = buf;
199
Glenn L McGrathad117d82001-10-05 04:40:37 +0000200 /* first create the opcode part */
201
Mark Whitley450736c2001-03-02 19:08:50 +0000202 *((unsigned short *) cp) = htons(opcode);
203
204 cp += 2;
205
206 /* add filename and mode */
207
Glenn L McGrathad117d82001-10-05 04:40:37 +0000208 if ((cmd_get && (opcode == TFTP_RRQ)) ||
209 (cmd_put && (opcode == TFTP_WRQ))) {
210 int too_long = 0;
Mark Whitley450736c2001-03-02 19:08:50 +0000211
Glenn L McGrathad117d82001-10-05 04:40:37 +0000212 /* see if the filename fits into buf */
213 /* and fill in packet */
214
215 len = strlen(remotefile) + 1;
216
217 if ((cp + len) >= &buf[tftp_bufsize - 1]) {
218 too_long = 1;
Mark Whitley450736c2001-03-02 19:08:50 +0000219 }
Glenn L McGrathad117d82001-10-05 04:40:37 +0000220 else {
221 safe_strncpy(cp, remotefile, len);
222 cp += len;
223 }
224
225 if (too_long || ((&buf[tftp_bufsize - 1] - cp) < 6)) {
226 error_msg("too long remote-filename");
Mark Whitley450736c2001-03-02 19:08:50 +0000227 break;
228 }
229
Glenn L McGrathad117d82001-10-05 04:40:37 +0000230 /* add "mode" part of the package */
231
232 memcpy(cp, "octet", 6);
233 cp += 6;
234
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000235#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
Glenn L McGrathad117d82001-10-05 04:40:37 +0000236
237 len = tftp_bufsize - 4; /* data block size */
238
239 if (len != TFTP_BLOCKSIZE_DEFAULT) {
240
241 if ((&buf[tftp_bufsize - 1] - cp) < 15) {
242 error_msg("too long remote-filename");
243 break;
244 }
245
246 /* add "blksize" + number of blocks */
247
248 memcpy(cp, "blksize", 8);
249 cp += 8;
250
251 cp += snprintf(cp, 6, "%d", len) + 1;
252
253 want_option_ack = 1;
254 }
255#endif
Mark Whitley450736c2001-03-02 19:08:50 +0000256 }
257
258 /* add ack and data */
259
Glenn L McGrathad117d82001-10-05 04:40:37 +0000260 if ((cmd_get && (opcode == TFTP_ACK)) ||
261 (cmd_put && (opcode == TFTP_DATA))) {
Mark Whitley450736c2001-03-02 19:08:50 +0000262
263 *((unsigned short *) cp) = htons(block_nr);
264
265 cp += 2;
266
267 block_nr++;
268
Glenn L McGrathad117d82001-10-05 04:40:37 +0000269 if (cmd_put && (opcode == TFTP_DATA)) {
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000270 len = read(localfd, cp, tftp_bufsize - 4);
Mark Whitley450736c2001-03-02 19:08:50 +0000271
272 if (len < 0) {
273 perror_msg("read");
274 break;
275 }
276
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000277 if (len != (tftp_bufsize - 4)) {
Mark Whitley450736c2001-03-02 19:08:50 +0000278 finished++;
279 }
280
281 cp += len;
282 } else if (finished) {
283 break;
284 }
285 }
286
287
288 /* send packet */
289
290
291 do {
292
293 len = cp - buf;
294
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000295#ifdef CONFIG_FEATURE_TFTP_DEBUG
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000296 printf("sending %u bytes\n", len);
297 for (cp = buf; cp < &buf[len]; cp++)
298 printf("%02x ", *cp);
299 printf("\n");
300#endif
Mark Whitley450736c2001-03-02 19:08:50 +0000301 if (sendto(socketfd, buf, len, 0,
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000302 (struct sockaddr *) &sa, sizeof(sa)) < 0) {
Mark Whitley8bb7df42001-03-06 20:58:48 +0000303 perror_msg("send");
Mark Whitley450736c2001-03-02 19:08:50 +0000304 len = -1;
305 break;
306 }
307
308
309 /* receive packet */
310
311
312 memset(&from, 0, sizeof(from));
313 fromlen = sizeof(from);
314
Glenn L McGrathad117d82001-10-05 04:40:37 +0000315 tv.tv_sec = TFTP_TIMEOUT;
Mark Whitley450736c2001-03-02 19:08:50 +0000316 tv.tv_usec = 0;
317
318 FD_ZERO(&rfds);
319 FD_SET(socketfd, &rfds);
320
321 switch (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) {
322 case 1:
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000323 len = recvfrom(socketfd, buf, tftp_bufsize, 0,
324 (struct sockaddr *) &from, &fromlen);
Mark Whitley450736c2001-03-02 19:08:50 +0000325
326 if (len < 0) {
327 perror_msg("recvfrom");
328 break;
329 }
330
331 timeout = 0;
332
333 if (sa.sin_port == htons(port)) {
334 sa.sin_port = from.sin_port;
Mark Whitley450736c2001-03-02 19:08:50 +0000335 }
Mark Whitley450736c2001-03-02 19:08:50 +0000336 if (sa.sin_port == from.sin_port) {
337 break;
338 }
339
340 /* fall-through for bad packets! */
341 /* discard the packet - treat as timeout */
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000342 timeout = bb_tftp_num_retries;
Mark Whitley450736c2001-03-02 19:08:50 +0000343
344 case 0:
Mark Whitley8bb7df42001-03-06 20:58:48 +0000345 error_msg("timeout");
Mark Whitley450736c2001-03-02 19:08:50 +0000346
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000347 if (timeout == 0) {
Mark Whitley450736c2001-03-02 19:08:50 +0000348 len = -1;
Mark Whitley8bb7df42001-03-06 20:58:48 +0000349 error_msg("last timeout");
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000350 } else {
351 timeout--;
Mark Whitley450736c2001-03-02 19:08:50 +0000352 }
353 break;
354
355 default:
356 perror_msg("select");
357 len = -1;
358 }
359
360 } while (timeout && (len >= 0));
361
362 if (len < 0) {
363 break;
364 }
365
366 /* process received packet */
367
368
369 opcode = ntohs(*((unsigned short *) buf));
370 tmp = ntohs(*((unsigned short *) &buf[2]));
371
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000372#ifdef CONFIG_FEATURE_TFTP_DEBUG
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000373 printf("received %d bytes: %04x %04x\n", len, opcode, tmp);
374#endif
Mark Whitley450736c2001-03-02 19:08:50 +0000375
Glenn L McGrathad117d82001-10-05 04:40:37 +0000376 if (opcode == TFTP_ERROR) {
377 char *msg = NULL;
378
379 if (buf[4] != '\0') {
380 msg = &buf[4];
381 buf[tftp_bufsize - 1] = '\0';
382 } else if (tmp < (sizeof(tftp_error_msg)
383 / sizeof(char *))) {
384
385 msg = (char *) tftp_error_msg[tmp];
386 }
387
388 if (msg) {
389 error_msg("server says: %s", msg);
390 }
391
392 break;
393 }
394
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000395#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
Glenn L McGrathad117d82001-10-05 04:40:37 +0000396 if (want_option_ack) {
397
398 want_option_ack = 0;
399
400 if (opcode == TFTP_OACK) {
401
402 /* server seems to support options */
403
404 char *res;
405
406 res = tftp_option_get(&buf[2], len-2,
407 "blksize");
408
409 if (res) {
410 int foo = atoi(res);
411
412 if (tftp_blocksize_check(foo,
413 tftp_bufsize - 4)) {
414
415 if (cmd_put) {
416 opcode = TFTP_DATA;
417 }
418 else {
419 opcode = TFTP_ACK;
420 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000421#ifdef CONFIG_FEATURE_TFTP_DEBUG
Glenn L McGrathad117d82001-10-05 04:40:37 +0000422 printf("using blksize %u\n");
423#endif
424 tftp_bufsize = foo + 4;
425 block_nr = 0;
426 continue;
427 }
428 }
429 /* FIXME:
430 * we should send ERROR 8 */
431 error_msg("bad server option");
432 break;
433 }
434
435 error_msg("warning: blksize not supported by server"
436 " - reverting to 512");
437
438 tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4;
439 }
440#endif
441
442 if (cmd_get && (opcode == TFTP_DATA)) {
Mark Whitley450736c2001-03-02 19:08:50 +0000443
444 if (tmp == block_nr) {
Glenn L McGrathad117d82001-10-05 04:40:37 +0000445
Mark Whitley450736c2001-03-02 19:08:50 +0000446 len = write(localfd, &buf[4], len - 4);
447
448 if (len < 0) {
449 perror_msg("write");
450 break;
451 }
452
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000453 if (len != (tftp_bufsize - 4)) {
Mark Whitley450736c2001-03-02 19:08:50 +0000454 finished++;
455 }
456
Glenn L McGrathad117d82001-10-05 04:40:37 +0000457 opcode = TFTP_ACK;
Mark Whitley450736c2001-03-02 19:08:50 +0000458 continue;
459 }
460 }
461
Glenn L McGrathad117d82001-10-05 04:40:37 +0000462 if (cmd_put && (opcode == TFTP_ACK)) {
Mark Whitley450736c2001-03-02 19:08:50 +0000463
464 if (tmp == (block_nr - 1)) {
465 if (finished) {
466 break;
467 }
468
Glenn L McGrathad117d82001-10-05 04:40:37 +0000469 opcode = TFTP_DATA;
Mark Whitley450736c2001-03-02 19:08:50 +0000470 continue;
471 }
472 }
Mark Whitley450736c2001-03-02 19:08:50 +0000473 }
474
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000475#ifdef CONFIG_FEATURE_CLEAN_UP
Mark Whitley450736c2001-03-02 19:08:50 +0000476 close(socketfd);
477
Eric Andersen5ad22c92002-10-25 12:14:02 +0000478 free(buf);
Glenn L McGrathad117d82001-10-05 04:40:37 +0000479#endif
480
Mark Whitley8bb7df42001-03-06 20:58:48 +0000481 return finished ? EXIT_SUCCESS : EXIT_FAILURE;
Mark Whitley450736c2001-03-02 19:08:50 +0000482}
483
484int tftp_main(int argc, char **argv)
485{
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000486 struct hostent *host = NULL;
487 char *localfile = NULL;
488 char *remotefile = NULL;
489 int port = 69;
490 int cmd = 0;
491 int fd = -1;
492 int flags = 0;
493 int opt;
494 int result;
Glenn L McGrathad117d82001-10-05 04:40:37 +0000495 int blocksize = TFTP_BLOCKSIZE_DEFAULT;
Mark Whitley450736c2001-03-02 19:08:50 +0000496
Glenn L McGrathad117d82001-10-05 04:40:37 +0000497 /* figure out what to pass to getopt */
498
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000499#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
Glenn L McGrathad117d82001-10-05 04:40:37 +0000500#define BS "b:"
501#else
502#define BS
503#endif
504
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000505#ifdef CONFIG_FEATURE_TFTP_GET
Glenn L McGrathad117d82001-10-05 04:40:37 +0000506#define GET "g"
507#else
508#define GET
509#endif
510
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000511#ifdef CONFIG_FEATURE_TFTP_PUT
Glenn L McGrathad117d82001-10-05 04:40:37 +0000512#define PUT "p"
513#else
514#define PUT
515#endif
516
517 while ((opt = getopt(argc, argv, BS GET PUT "l:r:")) != -1) {
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000518 switch (opt) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000519#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000520 case 'b':
521 blocksize = atoi(optarg);
Glenn L McGrathad117d82001-10-05 04:40:37 +0000522 if (!tftp_blocksize_check(blocksize, 0)) {
523 return EXIT_FAILURE;
524 }
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000525 break;
Glenn L McGrathad117d82001-10-05 04:40:37 +0000526#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000527#ifdef CONFIG_FEATURE_TFTP_GET
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000528 case 'g':
529 cmd = tftp_cmd_get;
Mark Whitley450736c2001-03-02 19:08:50 +0000530 flags = O_WRONLY | O_CREAT;
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000531 break;
532#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000533#ifdef CONFIG_FEATURE_TFTP_PUT
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000534 case 'p':
535 cmd = tftp_cmd_put;
Mark Whitley450736c2001-03-02 19:08:50 +0000536 flags = O_RDONLY;
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000537 break;
538#endif
539 case 'l':
540 localfile = xstrdup(optarg);
541 break;
542 case 'r':
543 remotefile = xstrdup(optarg);
544 break;
Mark Whitley450736c2001-03-02 19:08:50 +0000545 }
Mark Whitley450736c2001-03-02 19:08:50 +0000546 }
547
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000548 if ((cmd == 0) || (optind == argc)) {
Mark Whitley450736c2001-03-02 19:08:50 +0000549 show_usage();
550 }
Eric Andersen744ec1d2002-04-15 07:40:27 +0000551 if(localfile && strcmp(localfile, "-") == 0) {
Eric Andersen7829b8d2002-09-10 06:03:31 +0000552 fd = fileno((cmd==tftp_cmd_get)? stdout : stdin);
Eric Andersena66a43e2002-04-13 09:30:25 +0000553 }
Eric Andersen744ec1d2002-04-15 07:40:27 +0000554 if(localfile == NULL)
555 localfile = remotefile;
556 if(remotefile == NULL)
557 remotefile = localfile;
Eric Andersena66a43e2002-04-13 09:30:25 +0000558 if (fd==-1) {
559 fd = open(localfile, flags, 0644);
560 }
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000561 if (fd < 0) {
Mark Whitley450736c2001-03-02 19:08:50 +0000562 perror_msg_and_die("local file");
563 }
564
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000565 host = xgethostbyname(argv[optind]);
Mark Whitley450736c2001-03-02 19:08:50 +0000566
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000567 if (optind + 2 == argc) {
568 port = atoi(argv[optind + 1]);
569 }
570
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000571#ifdef CONFIG_FEATURE_TFTP_DEBUG
Glenn L McGrathad117d82001-10-05 04:40:37 +0000572 printf("using server \"%s\", remotefile \"%s\", "
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000573 "localfile \"%s\".\n",
574 inet_ntoa(*((struct in_addr *) host->h_addr)),
575 remotefile, localfile);
576#endif
577
578 result = tftp(cmd, host, remotefile, fd, port, blocksize);
Mark Whitley450736c2001-03-02 19:08:50 +0000579
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000580#ifdef CONFIG_FEATURE_CLEAN_UP
Eric Andersen744ec1d2002-04-15 07:40:27 +0000581 if (!(fd == fileno(stdout) || fd == fileno(stdin))) {
Eric Andersena66a43e2002-04-13 09:30:25 +0000582 close(fd);
583 }
Glenn L McGrathad117d82001-10-05 04:40:37 +0000584#endif
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000585 return(result);
Glenn L McGrathad117d82001-10-05 04:40:37 +0000586}