diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-19 13:07:00 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-19 13:07:00 +0000 |
commit | 403a5a298eaa5d1d827ad6ebbf38a7b765ba5b44 (patch) | |
tree | 6a31deaf0444b2e375a03db0a66c0d14d61e97c9 | |
parent | 71c9f015e9d83910ea3ae127944ef5d900c5a582 (diff) | |
download | busybox-w32-403a5a298eaa5d1d827ad6ebbf38a7b765ba5b44.tar.gz busybox-w32-403a5a298eaa5d1d827ad6ebbf38a7b765ba5b44.tar.bz2 busybox-w32-403a5a298eaa5d1d827ad6ebbf38a7b765ba5b44.zip |
tftpd: options -c (allow _new_ files to be uploaded) and -u USER
function old new delta
tftp_protocol 1316 1466 +150
packed_usage 23774 23798 +24
tftpd_main 509 502 -7
tftp_main 311 252 -59
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/2 up/down: 174/-66) Total: 108 bytes
text data bss dec hex filename
797700 641 7380 805721 c4b59 busybox_old
797833 641 7380 805854 c4bde busybox_unstripped
-rw-r--r-- | include/usage.h | 6 | ||||
-rw-r--r-- | networking/tftp.c | 147 |
2 files changed, 88 insertions, 65 deletions
diff --git a/include/usage.h b/include/usage.h index 7fe9ad063..ad9009763 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -3977,11 +3977,13 @@ | |||
3977 | ) | 3977 | ) |
3978 | 3978 | ||
3979 | #define tftpd_trivial_usage \ | 3979 | #define tftpd_trivial_usage \ |
3980 | "[-r] [DIR]" | 3980 | "[-cr] [-u USER] [DIR]" |
3981 | #define tftpd_full_usage \ | 3981 | #define tftpd_full_usage \ |
3982 | "Transfer a file on request from a tftp client.\n" \ | 3982 | "Transfer a file on tftp client's request.\n" \ |
3983 | "\nOptions:" \ | 3983 | "\nOptions:" \ |
3984 | "\n -r Prohibit upload" \ | 3984 | "\n -r Prohibit upload" \ |
3985 | "\n -c Allow file creation via upload" \ | ||
3986 | "\n -u Access files as USER" \ | ||
3985 | 3987 | ||
3986 | #define time_trivial_usage \ | 3988 | #define time_trivial_usage \ |
3987 | "[OPTION]... COMMAND [ARGS...]" | 3989 | "[OPTION]... COMMAND [ARGS...]" |
diff --git a/networking/tftp.c b/networking/tftp.c index e0f2b91cf..5fac48769 100644 --- a/networking/tftp.c +++ b/networking/tftp.c | |||
@@ -51,6 +51,17 @@ | |||
51 | #define ERR_BAD_USER 7 | 51 | #define ERR_BAD_USER 7 |
52 | #define ERR_BAD_OPT 8 | 52 | #define ERR_BAD_OPT 8 |
53 | 53 | ||
54 | /* masks coming from getopt32 */ | ||
55 | enum { | ||
56 | TFTP_OPT_GET = (1 << 0), | ||
57 | TFTP_OPT_PUT = (1 << 1), | ||
58 | /* pseudo option: if set, it's tftpd */ | ||
59 | TFTPD_OPT = (1 << 7) * ENABLE_TFTPD, | ||
60 | TFTPD_OPT_r = (1 << 8) * ENABLE_TFTPD, | ||
61 | TFTPD_OPT_c = (1 << 9) * ENABLE_TFTPD, | ||
62 | TFTPD_OPT_u = (1 << 10) * ENABLE_TFTPD, | ||
63 | }; | ||
64 | |||
54 | #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT | 65 | #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT |
55 | #define USE_GETPUT(...) | 66 | #define USE_GETPUT(...) |
56 | #define CMD_GET(cmd) 1 | 67 | #define CMD_GET(cmd) 1 |
@@ -61,9 +72,8 @@ | |||
61 | #define CMD_PUT(cmd) 1 | 72 | #define CMD_PUT(cmd) 1 |
62 | #else | 73 | #else |
63 | #define USE_GETPUT(...) __VA_ARGS__ | 74 | #define USE_GETPUT(...) __VA_ARGS__ |
64 | /* masks coming from getopt32 */ | 75 | #define CMD_GET(cmd) ((cmd) & TFTP_OPT_GET) |
65 | #define CMD_GET(cmd) ((cmd) & 1) | 76 | #define CMD_PUT(cmd) ((cmd) & TFTP_OPT_PUT) |
66 | #define CMD_PUT(cmd) ((cmd) & 2) | ||
67 | #endif | 77 | #endif |
68 | /* NB: in the code below | 78 | /* NB: in the code below |
69 | * CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive | 79 | * CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive |
@@ -73,11 +83,15 @@ | |||
73 | struct globals { | 83 | struct globals { |
74 | /* u16 TFTP_ERROR; u16 reason; both network-endian, then error text: */ | 84 | /* u16 TFTP_ERROR; u16 reason; both network-endian, then error text: */ |
75 | uint8_t error_pkt[4 + 32]; | 85 | uint8_t error_pkt[4 + 32]; |
86 | #if ENABLE_TFTPD | ||
87 | char *user_opt; | ||
88 | #endif | ||
76 | /* used in tftpd_main(), a bit big for stack: */ | 89 | /* used in tftpd_main(), a bit big for stack: */ |
77 | char block_buf[TFTP_BLKSIZE_DEFAULT]; | 90 | char block_buf[TFTP_BLKSIZE_DEFAULT]; |
78 | }; | 91 | }; |
79 | #define G (*(struct globals*)&bb_common_bufsiz1) | 92 | #define G (*(struct globals*)&bb_common_bufsiz1) |
80 | #define block_buf (G.block_buf ) | 93 | #define block_buf (G.block_buf ) |
94 | #define user_opt (G.user_opt ) | ||
81 | #define error_pkt (G.error_pkt ) | 95 | #define error_pkt (G.error_pkt ) |
82 | #define INIT_G() \ | 96 | #define INIT_G() \ |
83 | do { \ | 97 | do { \ |
@@ -148,11 +162,10 @@ static char *tftp_get_blksize(char *buf, int len) | |||
148 | #endif | 162 | #endif |
149 | 163 | ||
150 | static int tftp_protocol( | 164 | static int tftp_protocol( |
151 | USE_GETPUT(int cmd,) | ||
152 | len_and_sockaddr *our_lsa, | 165 | len_and_sockaddr *our_lsa, |
153 | len_and_sockaddr *peer_lsa, | 166 | len_and_sockaddr *peer_lsa, |
167 | const char *local_file, | ||
154 | USE_TFTP(const char *remote_file,) | 168 | USE_TFTP(const char *remote_file,) |
155 | int local_fd, | ||
156 | int blksize) | 169 | int blksize) |
157 | { | 170 | { |
158 | #if !ENABLE_TFTP | 171 | #if !ENABLE_TFTP |
@@ -167,6 +180,7 @@ static int tftp_protocol( | |||
167 | uint16_t opcode; | 180 | uint16_t opcode; |
168 | uint16_t block_nr; | 181 | uint16_t block_nr; |
169 | uint16_t recv_blk; | 182 | uint16_t recv_blk; |
183 | int open_mode, local_fd; | ||
170 | int retries, waittime_ms; | 184 | int retries, waittime_ms; |
171 | int io_bufsize = blksize + 4; | 185 | int io_bufsize = blksize + 4; |
172 | char *cp; | 186 | char *cp; |
@@ -180,6 +194,39 @@ static int tftp_protocol( | |||
180 | socket_fd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0); | 194 | socket_fd = xsocket(peer_lsa->u.sa.sa_family, SOCK_DGRAM, 0); |
181 | setsockopt_reuseaddr(socket_fd); | 195 | setsockopt_reuseaddr(socket_fd); |
182 | 196 | ||
197 | #if ENABLE_TFTPD | ||
198 | if (user_opt) { | ||
199 | struct passwd *pw = getpwnam(user_opt); /* initgroups, setgid, setuid */ | ||
200 | if (!pw) | ||
201 | bb_error_msg_and_die("unknown user '%s'", user_opt); | ||
202 | change_identity(pw); | ||
203 | } | ||
204 | #endif | ||
205 | |||
206 | if (CMD_PUT(option_mask32)) { | ||
207 | open_mode = O_RDONLY; | ||
208 | } else { | ||
209 | open_mode = O_WRONLY | O_TRUNC | O_CREAT; | ||
210 | #if ENABLE_TFTPD | ||
211 | if ((option_mask32 & (TFTPD_OPT+TFTPD_OPT_c)) == TFTPD_OPT) { | ||
212 | /* tftpd without -c */ | ||
213 | open_mode = O_WRONLY | O_TRUNC; | ||
214 | } | ||
215 | #endif | ||
216 | } | ||
217 | if (!(option_mask32 & TFTPD_OPT)) { | ||
218 | local_fd = CMD_GET(option_mask32) ? STDOUT_FILENO : STDIN_FILENO; | ||
219 | if (NOT_LONE_DASH(local_file)) | ||
220 | local_fd = xopen(local_file, open_mode); | ||
221 | } else { | ||
222 | local_fd = open_or_warn(local_file, open_mode); | ||
223 | if (local_fd < 0) { | ||
224 | /*error_pkt_reason = ERR_NOFILE/ERR_ACCESS?*/ | ||
225 | strcpy(error_pkt_str, "can't open file"); | ||
226 | goto send_err_pkt; | ||
227 | } | ||
228 | } | ||
229 | |||
183 | block_nr = 1; | 230 | block_nr = 1; |
184 | if (!ENABLE_TFTP || our_lsa) { | 231 | if (!ENABLE_TFTP || our_lsa) { |
185 | /* tftpd */ | 232 | /* tftpd */ |
@@ -197,7 +244,7 @@ static int tftp_protocol( | |||
197 | if (error_pkt_reason || error_pkt_str[0]) | 244 | if (error_pkt_reason || error_pkt_str[0]) |
198 | goto send_err_pkt; | 245 | goto send_err_pkt; |
199 | 246 | ||
200 | if (CMD_GET(cmd)) { | 247 | if (CMD_GET(option_mask32)) { |
201 | /* it's upload - we must ACK 1st packet (with filename) | 248 | /* it's upload - we must ACK 1st packet (with filename) |
202 | * as if it's "block 0" */ | 249 | * as if it's "block 0" */ |
203 | block_nr = 0; | 250 | block_nr = 0; |
@@ -231,7 +278,7 @@ static int tftp_protocol( | |||
231 | 278 | ||
232 | /* build opcode */ | 279 | /* build opcode */ |
233 | opcode = TFTP_WRQ; | 280 | opcode = TFTP_WRQ; |
234 | if (CMD_GET(cmd)) { | 281 | if (CMD_GET(option_mask32)) { |
235 | opcode = TFTP_RRQ; | 282 | opcode = TFTP_RRQ; |
236 | } | 283 | } |
237 | cp = xbuf + 2; | 284 | cp = xbuf + 2; |
@@ -276,7 +323,7 @@ static int tftp_protocol( | |||
276 | cp += 2; | 323 | cp += 2; |
277 | block_nr++; | 324 | block_nr++; |
278 | opcode = TFTP_ACK; | 325 | opcode = TFTP_ACK; |
279 | if (CMD_PUT(cmd)) { | 326 | if (CMD_PUT(option_mask32)) { |
280 | opcode = TFTP_DATA; | 327 | opcode = TFTP_DATA; |
281 | len = full_read(local_fd, cp, blksize); | 328 | len = full_read(local_fd, cp, blksize); |
282 | if (len < 0) { | 329 | if (len < 0) { |
@@ -420,7 +467,7 @@ static int tftp_protocol( | |||
420 | /* block_nr is already advanced to next block# we expect | 467 | /* block_nr is already advanced to next block# we expect |
421 | * to get / block# we are about to send next time */ | 468 | * to get / block# we are about to send next time */ |
422 | 469 | ||
423 | if (CMD_GET(cmd) && (opcode == TFTP_DATA)) { | 470 | if (CMD_GET(option_mask32) && (opcode == TFTP_DATA)) { |
424 | if (recv_blk == block_nr) { | 471 | if (recv_blk == block_nr) { |
425 | int sz = full_write(local_fd, &rbuf[4], len - 4); | 472 | int sz = full_write(local_fd, &rbuf[4], len - 4); |
426 | if (sz != len - 4) { | 473 | if (sz != len - 4) { |
@@ -440,7 +487,7 @@ static int tftp_protocol( | |||
440 | } | 487 | } |
441 | } | 488 | } |
442 | 489 | ||
443 | if (CMD_PUT(cmd) && (opcode == TFTP_ACK)) { | 490 | if (CMD_PUT(option_mask32) && (opcode == TFTP_ACK)) { |
444 | /* did peer ACK our last DATA pkt? */ | 491 | /* did peer ACK our last DATA pkt? */ |
445 | if (recv_blk == (uint16_t) (block_nr - 1)) { | 492 | if (recv_blk == (uint16_t) (block_nr - 1)) { |
446 | if (finished) | 493 | if (finished) |
@@ -462,6 +509,7 @@ static int tftp_protocol( | |||
462 | } /* end of "while (1)" */ | 509 | } /* end of "while (1)" */ |
463 | ret: | 510 | ret: |
464 | if (ENABLE_FEATURE_CLEAN_UP) { | 511 | if (ENABLE_FEATURE_CLEAN_UP) { |
512 | close(local_fd); | ||
465 | close(socket_fd); | 513 | close(socket_fd); |
466 | free(xbuf); | 514 | free(xbuf); |
467 | free(rbuf); | 515 | free(rbuf); |
@@ -487,13 +535,11 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv) | |||
487 | len_and_sockaddr *peer_lsa; | 535 | len_and_sockaddr *peer_lsa; |
488 | const char *local_file = NULL; | 536 | const char *local_file = NULL; |
489 | const char *remote_file = NULL; | 537 | const char *remote_file = NULL; |
490 | int port; | ||
491 | USE_GETPUT(int cmd;) | ||
492 | int local_fd; | ||
493 | int flags = 0; | ||
494 | int result; | ||
495 | int blksize; | ||
496 | const char *blksize_str = "512"; | 538 | const char *blksize_str = "512"; |
539 | int blksize; | ||
540 | int result; | ||
541 | int port; | ||
542 | USE_GETPUT(int opt;) | ||
497 | 543 | ||
498 | INIT_G(); | 544 | INIT_G(); |
499 | 545 | ||
@@ -501,17 +547,13 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv) | |||
501 | opt_complementary = "" USE_FEATURE_TFTP_GET("g:") USE_FEATURE_TFTP_PUT("p:") | 547 | opt_complementary = "" USE_FEATURE_TFTP_GET("g:") USE_FEATURE_TFTP_PUT("p:") |
502 | USE_GETPUT("g--p:p--g:"); | 548 | USE_GETPUT("g--p:p--g:"); |
503 | 549 | ||
504 | USE_GETPUT(cmd =) getopt32(argv, | 550 | USE_GETPUT(opt =) getopt32(argv, |
505 | USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p") | 551 | USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p") |
506 | "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"), | 552 | "l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"), |
507 | &local_file, &remote_file | 553 | &local_file, &remote_file |
508 | USE_FEATURE_TFTP_BLOCKSIZE(, &blksize_str)); | 554 | USE_FEATURE_TFTP_BLOCKSIZE(, &blksize_str)); |
509 | argv += optind; | 555 | argv += optind; |
510 | 556 | ||
511 | flags = O_RDONLY; | ||
512 | if (CMD_GET(cmd)) | ||
513 | flags = O_WRONLY | O_CREAT | O_TRUNC; | ||
514 | |||
515 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE | 557 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE |
516 | /* Check if the blksize is valid: | 558 | /* Check if the blksize is valid: |
517 | * RFC2348 says between 8 and 65464 */ | 559 | * RFC2348 says between 8 and 65464 */ |
@@ -530,11 +572,6 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv) | |||
530 | if (!remote_file || !argv[0]) | 572 | if (!remote_file || !argv[0]) |
531 | bb_show_usage(); | 573 | bb_show_usage(); |
532 | 574 | ||
533 | local_fd = CMD_GET(cmd) ? STDOUT_FILENO : STDIN_FILENO; | ||
534 | if (!LONE_DASH(local_file)) { | ||
535 | local_fd = xopen(local_file, flags); | ||
536 | } | ||
537 | |||
538 | port = bb_lookup_port(argv[1], "udp", 69); | 575 | port = bb_lookup_port(argv[1], "udp", 69); |
539 | peer_lsa = xhost2sockaddr(argv[0], port); | 576 | peer_lsa = xhost2sockaddr(argv[0], port); |
540 | 577 | ||
@@ -545,14 +582,11 @@ int tftp_main(int argc ATTRIBUTE_UNUSED, char **argv) | |||
545 | #endif | 582 | #endif |
546 | 583 | ||
547 | result = tftp_protocol( | 584 | result = tftp_protocol( |
548 | USE_GETPUT(cmd,) | 585 | NULL /* our_lsa*/, peer_lsa, |
549 | NULL /* our_lsa*/, | 586 | local_file, remote_file, |
550 | peer_lsa, | 587 | blksize); |
551 | remote_file, local_fd, blksize); | ||
552 | 588 | ||
553 | if (ENABLE_FEATURE_CLEAN_UP) | 589 | if (result != EXIT_SUCCESS && NOT_LONE_DASH(local_file) && CMD_GET(opt)) { |
554 | close(local_fd); | ||
555 | if (result != EXIT_SUCCESS && !LONE_DASH(local_file) && CMD_GET(cmd)) { | ||
556 | unlink(local_file); | 590 | unlink(local_file); |
557 | } | 591 | } |
558 | return result; | 592 | return result; |
@@ -581,9 +615,9 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv) | |||
581 | { | 615 | { |
582 | len_and_sockaddr *our_lsa; | 616 | len_and_sockaddr *our_lsa; |
583 | len_and_sockaddr *peer_lsa; | 617 | len_and_sockaddr *peer_lsa; |
584 | char *filename, *mode; | 618 | char *local_file, *mode; |
585 | const char *error_msg; | 619 | const char *error_msg; |
586 | int opt_r, result, opcode, open_mode; | 620 | int opt, result, opcode; |
587 | int local_fd = local_fd; /* for compiler */ | 621 | int local_fd = local_fd; /* for compiler */ |
588 | int blksize = blksize; | 622 | int blksize = blksize; |
589 | USE_GETPUT(int cmd = cmd;) | 623 | USE_GETPUT(int cmd = cmd;) |
@@ -596,7 +630,8 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv) | |||
596 | peer_lsa = xzalloc(LSA_LEN_SIZE + our_lsa->len); | 630 | peer_lsa = xzalloc(LSA_LEN_SIZE + our_lsa->len); |
597 | peer_lsa->len = our_lsa->len; | 631 | peer_lsa->len = our_lsa->len; |
598 | 632 | ||
599 | opt_r = getopt32(argv, "r"); | 633 | /* Shifting to not collide with TFTP_OPTs */ |
634 | opt = option_mask32 = TFTPD_OPT | (getopt32(argv, "rcu:", &user_opt) << 8); | ||
600 | argv += optind; | 635 | argv += optind; |
601 | if (argv[0]) | 636 | if (argv[0]) |
602 | xchdir(argv[0]); | 637 | xchdir(argv[0]); |
@@ -616,15 +651,13 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv) | |||
616 | ) { | 651 | ) { |
617 | goto err; | 652 | goto err; |
618 | } | 653 | } |
619 | filename = block_buf + 2; | 654 | local_file = block_buf + 2; |
620 | if (filename[0] == '.' || strstr(filename, "/.")) { | 655 | if (local_file[0] == '.' || strstr(local_file, "/.")) { |
621 | error_msg = "dot in filename"; | 656 | error_msg = "dot in local_file"; |
622 | goto err; | 657 | goto err; |
623 | } | 658 | } |
624 | mode = filename + strlen(filename) + 1; | 659 | mode = local_file + strlen(local_file) + 1; |
625 | if (mode >= block_buf + result | 660 | if (mode >= block_buf + result || strcmp(mode, "octet") != 0) { |
626 | || strcmp(mode, "octet") != 0 | ||
627 | ) { | ||
628 | goto err; | 661 | goto err; |
629 | } | 662 | } |
630 | blksize = TFTP_BLKSIZE_DEFAULT; | 663 | blksize = TFTP_BLKSIZE_DEFAULT; |
@@ -647,29 +680,16 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv) | |||
647 | } | 680 | } |
648 | #endif | 681 | #endif |
649 | 682 | ||
650 | #if ENABLE_FEATURE_TFTP_PUT | ||
651 | /* in case opcode is TFTP_RRQ: */ | ||
652 | USE_GETPUT(cmd = 2;) /* CMD_PUT: we will send file's data */ | ||
653 | open_mode = O_RDONLY; | ||
654 | #endif | ||
655 | #if ENABLE_FEATURE_TFTP_GET | ||
656 | if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) { | 683 | if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) { |
657 | if (opt_r) { | 684 | if (opt & TFTPD_OPT_r) { |
658 | /* This would mean "disk full" - not true */ | 685 | /* This would mean "disk full" - not true */ |
659 | /*error_pkt_reason = ERR_WRITE;*/ | 686 | /*error_pkt_reason = ERR_WRITE;*/ |
660 | error_msg = bb_msg_write_error; | 687 | error_msg = bb_msg_write_error; |
661 | goto err; | 688 | goto err; |
662 | } | 689 | } |
663 | USE_GETPUT(cmd = 1;) /* CMD_GET: we will receive file's data */ | 690 | USE_GETPUT(option_mask32 |= TFTP_OPT_GET;) /* will receive file's data */ |
664 | open_mode = O_WRONLY | O_TRUNC; | 691 | } else { |
665 | } | 692 | USE_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */ |
666 | #endif | ||
667 | local_fd = open(filename, open_mode); | ||
668 | if (local_fd < 0) { | ||
669 | /*error_pkt_reason = ERR_NOFILE/ERR_ACCESS?*/ | ||
670 | error_msg = "can't open file"; | ||
671 | err: | ||
672 | strcpy(error_pkt_str, error_msg); | ||
673 | } | 693 | } |
674 | 694 | ||
675 | close(STDIN_FILENO); /* close old, possibly wildcard socket */ | 695 | close(STDIN_FILENO); /* close old, possibly wildcard socket */ |
@@ -679,14 +699,15 @@ int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv) | |||
679 | * tftp_protocol() just sends one error pkt and returns */ | 699 | * tftp_protocol() just sends one error pkt and returns */ |
680 | do_proto: | 700 | do_proto: |
681 | result = tftp_protocol( | 701 | result = tftp_protocol( |
682 | USE_GETPUT(cmd,) | ||
683 | our_lsa, peer_lsa, | 702 | our_lsa, peer_lsa, |
684 | USE_TFTP(NULL /*remote_file*/,) | 703 | local_file, USE_TFTP(NULL /*remote_file*/,) |
685 | local_fd, | ||
686 | blksize | 704 | blksize |
687 | ); | 705 | ); |
688 | 706 | ||
689 | return result; | 707 | return result; |
708 | err: | ||
709 | strcpy(error_pkt_str, error_msg); | ||
710 | goto do_proto; | ||
690 | } | 711 | } |
691 | 712 | ||
692 | #endif /* ENABLE_TFTPD */ | 713 | #endif /* ENABLE_TFTPD */ |