blob: 378ba2feff0d4daaf141db2a53048f0053b7b866 [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;
Mark Whitley450736c2001-03-02 19:08:50 +0000282 }
283 }
284
285
286 /* send packet */
287
288
289 do {
290
291 len = cp - buf;
292
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000293#ifdef CONFIG_FEATURE_TFTP_DEBUG
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000294 printf("sending %u bytes\n", len);
295 for (cp = buf; cp < &buf[len]; cp++)
296 printf("%02x ", *cp);
297 printf("\n");
298#endif
Mark Whitley450736c2001-03-02 19:08:50 +0000299 if (sendto(socketfd, buf, len, 0,
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000300 (struct sockaddr *) &sa, sizeof(sa)) < 0) {
Mark Whitley8bb7df42001-03-06 20:58:48 +0000301 perror_msg("send");
Mark Whitley450736c2001-03-02 19:08:50 +0000302 len = -1;
303 break;
304 }
305
306
Glenn L McGrath0f182712002-12-19 20:16:22 +0000307 if (finished) {
308 break;
309 }
Mark Whitley450736c2001-03-02 19:08:50 +0000310
Glenn L McGrath0f182712002-12-19 20:16:22 +0000311 /* receive packet */
Mark Whitley450736c2001-03-02 19:08:50 +0000312
313 memset(&from, 0, sizeof(from));
314 fromlen = sizeof(from);
315
Glenn L McGrathad117d82001-10-05 04:40:37 +0000316 tv.tv_sec = TFTP_TIMEOUT;
Mark Whitley450736c2001-03-02 19:08:50 +0000317 tv.tv_usec = 0;
318
319 FD_ZERO(&rfds);
320 FD_SET(socketfd, &rfds);
321
322 switch (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) {
323 case 1:
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000324 len = recvfrom(socketfd, buf, tftp_bufsize, 0,
325 (struct sockaddr *) &from, &fromlen);
Mark Whitley450736c2001-03-02 19:08:50 +0000326
327 if (len < 0) {
328 perror_msg("recvfrom");
329 break;
330 }
331
332 timeout = 0;
333
334 if (sa.sin_port == htons(port)) {
335 sa.sin_port = from.sin_port;
Mark Whitley450736c2001-03-02 19:08:50 +0000336 }
Mark Whitley450736c2001-03-02 19:08:50 +0000337 if (sa.sin_port == from.sin_port) {
338 break;
339 }
340
341 /* fall-through for bad packets! */
342 /* discard the packet - treat as timeout */
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000343 timeout = bb_tftp_num_retries;
Mark Whitley450736c2001-03-02 19:08:50 +0000344
345 case 0:
Mark Whitley8bb7df42001-03-06 20:58:48 +0000346 error_msg("timeout");
Mark Whitley450736c2001-03-02 19:08:50 +0000347
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000348 if (timeout == 0) {
Mark Whitley450736c2001-03-02 19:08:50 +0000349 len = -1;
Mark Whitley8bb7df42001-03-06 20:58:48 +0000350 error_msg("last timeout");
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000351 } else {
352 timeout--;
Mark Whitley450736c2001-03-02 19:08:50 +0000353 }
354 break;
355
356 default:
357 perror_msg("select");
358 len = -1;
359 }
360
361 } while (timeout && (len >= 0));
362
Glenn L McGrath0f182712002-12-19 20:16:22 +0000363 if ((finished) || (len < 0)) {
Mark Whitley450736c2001-03-02 19:08:50 +0000364 break;
365 }
366
367 /* process received packet */
368
369
370 opcode = ntohs(*((unsigned short *) buf));
371 tmp = ntohs(*((unsigned short *) &buf[2]));
372
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000373#ifdef CONFIG_FEATURE_TFTP_DEBUG
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000374 printf("received %d bytes: %04x %04x\n", len, opcode, tmp);
375#endif
Mark Whitley450736c2001-03-02 19:08:50 +0000376
Glenn L McGrathad117d82001-10-05 04:40:37 +0000377 if (opcode == TFTP_ERROR) {
378 char *msg = NULL;
379
380 if (buf[4] != '\0') {
381 msg = &buf[4];
382 buf[tftp_bufsize - 1] = '\0';
383 } else if (tmp < (sizeof(tftp_error_msg)
384 / sizeof(char *))) {
385
386 msg = (char *) tftp_error_msg[tmp];
387 }
388
389 if (msg) {
390 error_msg("server says: %s", msg);
391 }
392
393 break;
394 }
395
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000396#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
Glenn L McGrathad117d82001-10-05 04:40:37 +0000397 if (want_option_ack) {
398
399 want_option_ack = 0;
400
401 if (opcode == TFTP_OACK) {
402
403 /* server seems to support options */
404
405 char *res;
406
407 res = tftp_option_get(&buf[2], len-2,
408 "blksize");
409
410 if (res) {
Glenn L McGrathfad90db2002-12-09 21:05:40 +0000411 int blksize = atoi(res);
Glenn L McGrathad117d82001-10-05 04:40:37 +0000412
Glenn L McGrathfad90db2002-12-09 21:05:40 +0000413 if (tftp_blocksize_check(blksize,
Glenn L McGrathad117d82001-10-05 04:40:37 +0000414 tftp_bufsize - 4)) {
415
416 if (cmd_put) {
417 opcode = TFTP_DATA;
418 }
419 else {
420 opcode = TFTP_ACK;
421 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000422#ifdef CONFIG_FEATURE_TFTP_DEBUG
Glenn L McGrathfad90db2002-12-09 21:05:40 +0000423 printf("using blksize %u\n", blksize);
Glenn L McGrathad117d82001-10-05 04:40:37 +0000424#endif
Glenn L McGrath9bf9f1e2002-12-09 21:52:29 +0000425 tftp_bufsize = blksize + 4;
Glenn L McGrathad117d82001-10-05 04:40:37 +0000426 block_nr = 0;
427 continue;
428 }
429 }
430 /* FIXME:
431 * we should send ERROR 8 */
432 error_msg("bad server option");
433 break;
434 }
435
436 error_msg("warning: blksize not supported by server"
437 " - reverting to 512");
438
439 tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4;
440 }
441#endif
442
443 if (cmd_get && (opcode == TFTP_DATA)) {
Mark Whitley450736c2001-03-02 19:08:50 +0000444
445 if (tmp == block_nr) {
Glenn L McGrathad117d82001-10-05 04:40:37 +0000446
Mark Whitley450736c2001-03-02 19:08:50 +0000447 len = write(localfd, &buf[4], len - 4);
448
449 if (len < 0) {
450 perror_msg("write");
451 break;
452 }
453
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000454 if (len != (tftp_bufsize - 4)) {
Mark Whitley450736c2001-03-02 19:08:50 +0000455 finished++;
456 }
457
Glenn L McGrathad117d82001-10-05 04:40:37 +0000458 opcode = TFTP_ACK;
Mark Whitley450736c2001-03-02 19:08:50 +0000459 continue;
460 }
461 }
462
Glenn L McGrathad117d82001-10-05 04:40:37 +0000463 if (cmd_put && (opcode == TFTP_ACK)) {
Mark Whitley450736c2001-03-02 19:08:50 +0000464
465 if (tmp == (block_nr - 1)) {
466 if (finished) {
467 break;
468 }
469
Glenn L McGrathad117d82001-10-05 04:40:37 +0000470 opcode = TFTP_DATA;
Mark Whitley450736c2001-03-02 19:08:50 +0000471 continue;
472 }
473 }
Mark Whitley450736c2001-03-02 19:08:50 +0000474 }
475
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000476#ifdef CONFIG_FEATURE_CLEAN_UP
Mark Whitley450736c2001-03-02 19:08:50 +0000477 close(socketfd);
478
Eric Andersen5ad22c92002-10-25 12:14:02 +0000479 free(buf);
Glenn L McGrathad117d82001-10-05 04:40:37 +0000480#endif
481
Mark Whitley8bb7df42001-03-06 20:58:48 +0000482 return finished ? EXIT_SUCCESS : EXIT_FAILURE;
Mark Whitley450736c2001-03-02 19:08:50 +0000483}
484
485int tftp_main(int argc, char **argv)
486{
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000487 struct hostent *host = NULL;
488 char *localfile = NULL;
489 char *remotefile = NULL;
490 int port = 69;
491 int cmd = 0;
492 int fd = -1;
493 int flags = 0;
494 int opt;
495 int result;
Glenn L McGrathad117d82001-10-05 04:40:37 +0000496 int blocksize = TFTP_BLOCKSIZE_DEFAULT;
Mark Whitley450736c2001-03-02 19:08:50 +0000497
Glenn L McGrathad117d82001-10-05 04:40:37 +0000498 /* figure out what to pass to getopt */
499
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000500#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
Glenn L McGrathad117d82001-10-05 04:40:37 +0000501#define BS "b:"
502#else
503#define BS
504#endif
505
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000506#ifdef CONFIG_FEATURE_TFTP_GET
Glenn L McGrathad117d82001-10-05 04:40:37 +0000507#define GET "g"
508#else
509#define GET
510#endif
511
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000512#ifdef CONFIG_FEATURE_TFTP_PUT
Glenn L McGrathad117d82001-10-05 04:40:37 +0000513#define PUT "p"
514#else
515#define PUT
516#endif
517
518 while ((opt = getopt(argc, argv, BS GET PUT "l:r:")) != -1) {
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000519 switch (opt) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000520#ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000521 case 'b':
522 blocksize = atoi(optarg);
Glenn L McGrathad117d82001-10-05 04:40:37 +0000523 if (!tftp_blocksize_check(blocksize, 0)) {
524 return EXIT_FAILURE;
525 }
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000526 break;
Glenn L McGrathad117d82001-10-05 04:40:37 +0000527#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000528#ifdef CONFIG_FEATURE_TFTP_GET
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000529 case 'g':
530 cmd = tftp_cmd_get;
Mark Whitley450736c2001-03-02 19:08:50 +0000531 flags = O_WRONLY | O_CREAT;
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000532 break;
533#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000534#ifdef CONFIG_FEATURE_TFTP_PUT
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000535 case 'p':
536 cmd = tftp_cmd_put;
Mark Whitley450736c2001-03-02 19:08:50 +0000537 flags = O_RDONLY;
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000538 break;
539#endif
540 case 'l':
541 localfile = xstrdup(optarg);
542 break;
543 case 'r':
544 remotefile = xstrdup(optarg);
545 break;
Mark Whitley450736c2001-03-02 19:08:50 +0000546 }
Mark Whitley450736c2001-03-02 19:08:50 +0000547 }
548
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000549 if ((cmd == 0) || (optind == argc)) {
Mark Whitley450736c2001-03-02 19:08:50 +0000550 show_usage();
551 }
Eric Andersen744ec1d2002-04-15 07:40:27 +0000552 if(localfile && strcmp(localfile, "-") == 0) {
Eric Andersen7829b8d2002-09-10 06:03:31 +0000553 fd = fileno((cmd==tftp_cmd_get)? stdout : stdin);
Eric Andersena66a43e2002-04-13 09:30:25 +0000554 }
Eric Andersen744ec1d2002-04-15 07:40:27 +0000555 if(localfile == NULL)
556 localfile = remotefile;
557 if(remotefile == NULL)
558 remotefile = localfile;
Eric Andersena66a43e2002-04-13 09:30:25 +0000559 if (fd==-1) {
560 fd = open(localfile, flags, 0644);
561 }
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000562 if (fd < 0) {
Mark Whitley450736c2001-03-02 19:08:50 +0000563 perror_msg_and_die("local file");
564 }
565
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000566 host = xgethostbyname(argv[optind]);
Mark Whitley450736c2001-03-02 19:08:50 +0000567
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000568 if (optind + 2 == argc) {
569 port = atoi(argv[optind + 1]);
570 }
571
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000572#ifdef CONFIG_FEATURE_TFTP_DEBUG
Glenn L McGrathad117d82001-10-05 04:40:37 +0000573 printf("using server \"%s\", remotefile \"%s\", "
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000574 "localfile \"%s\".\n",
575 inet_ntoa(*((struct in_addr *) host->h_addr)),
576 remotefile, localfile);
577#endif
578
579 result = tftp(cmd, host, remotefile, fd, port, blocksize);
Mark Whitley450736c2001-03-02 19:08:50 +0000580
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000581#ifdef CONFIG_FEATURE_CLEAN_UP
Eric Andersen744ec1d2002-04-15 07:40:27 +0000582 if (!(fd == fileno(stdout) || fd == fileno(stdin))) {
Eric Andersena66a43e2002-04-13 09:30:25 +0000583 close(fd);
584 }
Glenn L McGrathad117d82001-10-05 04:40:37 +0000585#endif
Eric Andersen76fa8ea2001-08-20 17:47:49 +0000586 return(result);
Glenn L McGrathad117d82001-10-05 04:40:37 +0000587}