diff options
author | Bradley M. Kuhn <bkuhn@ebb.org> | 2010-08-08 02:51:20 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-08-08 02:51:20 +0200 |
commit | c97131c2af832f03e769a12b2a95e4de86c5858f (patch) | |
tree | 6bb49cd582b75953c822431162a94809a9539918 /networking/wget.c | |
parent | 33bbb27e45c7c6a0fecb40b3a5aa36aef69825f9 (diff) | |
download | busybox-w32-c97131c2af832f03e769a12b2a95e4de86c5858f.tar.gz busybox-w32-c97131c2af832f03e769a12b2a95e4de86c5858f.tar.bz2 busybox-w32-c97131c2af832f03e769a12b2a95e4de86c5858f.zip |
wget: implement -T SEC; rework progress meter to not use signals (it was unsafe)
function old new delta
retrieve_file_data 364 450 +86
bb_progress_update 615 682 +67
packed_usage 27406 27422 +16
wget_main 2440 2453 +13
static.wget_longopts 145 155 +10
progress_meter 199 159 -40
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/1 up/down: 192/-40) Total: 152 bytes
Signed-off-by: Bradley M. Kuhn <bkuhn@ebb.org>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/wget.c')
-rw-r--r-- | networking/wget.c | 121 |
1 files changed, 73 insertions, 48 deletions
diff --git a/networking/wget.c b/networking/wget.c index 1f35f8b03..f62339071 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
@@ -3,8 +3,10 @@ | |||
3 | * wget - retrieve a file using HTTP or FTP | 3 | * wget - retrieve a file using HTTP or FTP |
4 | * | 4 | * |
5 | * Chip Rosenthal Covad Communications <chip@laserlink.net> | 5 | * Chip Rosenthal Covad Communications <chip@laserlink.net> |
6 | * | ||
7 | * Licensed under GPLv2, see file LICENSE in this tarball for details. | 6 | * Licensed under GPLv2, see file LICENSE in this tarball for details. |
7 | * | ||
8 | * Copyright (C) 2010 Bradley M. Kuhn <bkuhn@ebb.org> | ||
9 | * Kuhn's copyrights are licensed GPLv2-or-later. File as a whole remains GPLv2. | ||
8 | */ | 10 | */ |
9 | #include "libbb.h" | 11 | #include "libbb.h" |
10 | 12 | ||
@@ -19,7 +21,7 @@ struct host_info { | |||
19 | }; | 21 | }; |
20 | 22 | ||
21 | 23 | ||
22 | /* Globals (can be accessed from signal handlers) */ | 24 | /* Globals */ |
23 | struct globals { | 25 | struct globals { |
24 | off_t content_len; /* Content-length of the file */ | 26 | off_t content_len; /* Content-length of the file */ |
25 | off_t beg_range; /* Range at which continue begins */ | 27 | off_t beg_range; /* Range at which continue begins */ |
@@ -28,6 +30,9 @@ struct globals { | |||
28 | const char *curfile; /* Name of current file being transferred */ | 30 | const char *curfile; /* Name of current file being transferred */ |
29 | bb_progress_t pmt; | 31 | bb_progress_t pmt; |
30 | #endif | 32 | #endif |
33 | #if ENABLE_FEATURE_WGET_TIMEOUT | ||
34 | unsigned timeout_seconds; | ||
35 | #endif | ||
31 | smallint chunked; /* chunked transfer encoding */ | 36 | smallint chunked; /* chunked transfer encoding */ |
32 | smallint got_clen; /* got content-length: from server */ | 37 | smallint got_clen; /* got content-length: from server */ |
33 | } FIX_ALIASING; | 38 | } FIX_ALIASING; |
@@ -35,42 +40,51 @@ struct globals { | |||
35 | struct BUG_G_too_big { | 40 | struct BUG_G_too_big { |
36 | char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; | 41 | char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; |
37 | }; | 42 | }; |
38 | #define INIT_G() do { } while (0) | 43 | #define INIT_G() do { \ |
44 | IF_FEATURE_WGET_TIMEOUT(G.timeout_seconds = 900;) \ | ||
45 | } while (0) | ||
39 | 46 | ||
40 | 47 | ||
41 | #if ENABLE_FEATURE_WGET_STATUSBAR | 48 | /* Must match option string! */ |
49 | enum { | ||
50 | WGET_OPT_CONTINUE = (1 << 0), | ||
51 | WGET_OPT_SPIDER = (1 << 1), | ||
52 | WGET_OPT_QUIET = (1 << 2), | ||
53 | WGET_OPT_OUTNAME = (1 << 3), | ||
54 | WGET_OPT_PREFIX = (1 << 4), | ||
55 | WGET_OPT_PROXY = (1 << 5), | ||
56 | WGET_OPT_USER_AGENT = (1 << 6), | ||
57 | WGET_OPT_NETWORK_READ_TIMEOUT = (1 << 7), | ||
58 | WGET_OPT_RETRIES = (1 << 8), | ||
59 | WGET_OPT_PASSIVE = (1 << 9), | ||
60 | WGET_OPT_HEADER = (1 << 10) * ENABLE_FEATURE_WGET_LONG_OPTIONS, | ||
61 | WGET_OPT_POST_DATA = (1 << 11) * ENABLE_FEATURE_WGET_LONG_OPTIONS, | ||
62 | }; | ||
42 | 63 | ||
64 | enum { | ||
65 | PROGRESS_START = -1, | ||
66 | PROGRESS_END = 0, | ||
67 | PROGRESS_BUMP = 1, | ||
68 | }; | ||
69 | #if ENABLE_FEATURE_WGET_STATUSBAR | ||
43 | static void progress_meter(int flag) | 70 | static void progress_meter(int flag) |
44 | { | 71 | { |
45 | /* We can be called from signal handler */ | 72 | if (option_mask32 & WGET_OPT_QUIET) |
46 | int save_errno = errno; | 73 | return; |
47 | 74 | ||
48 | if (flag == -1) { /* first call to progress_meter */ | 75 | if (flag == PROGRESS_START) |
49 | bb_progress_init(&G.pmt); | 76 | bb_progress_init(&G.pmt); |
50 | } | ||
51 | 77 | ||
52 | bb_progress_update(&G.pmt, G.curfile, G.beg_range, G.transferred, | 78 | bb_progress_update(&G.pmt, G.curfile, G.beg_range, G.transferred, |
53 | G.chunked ? 0 : G.beg_range + G.transferred + G.content_len); | 79 | G.chunked ? 0 : G.beg_range + G.transferred + G.content_len); |
54 | 80 | ||
55 | if (flag == 0) { | 81 | if (flag == PROGRESS_END) { |
56 | /* last call to progress_meter */ | ||
57 | alarm(0); | ||
58 | bb_putchar_stderr('\n'); | 82 | bb_putchar_stderr('\n'); |
59 | G.transferred = 0; | 83 | G.transferred = 0; |
60 | } else { | ||
61 | if (flag == -1) { /* first call to progress_meter */ | ||
62 | signal_SA_RESTART_empty_mask(SIGALRM, progress_meter); | ||
63 | } | ||
64 | alarm(1); | ||
65 | } | 84 | } |
66 | |||
67 | errno = save_errno; | ||
68 | } | 85 | } |
69 | 86 | #else | |
70 | #else /* FEATURE_WGET_STATUSBAR */ | ||
71 | |||
72 | static ALWAYS_INLINE void progress_meter(int flag UNUSED_PARAM) { } | 87 | static ALWAYS_INLINE void progress_meter(int flag UNUSED_PARAM) { } |
73 | |||
74 | #endif | 88 | #endif |
75 | 89 | ||
76 | 90 | ||
@@ -430,28 +444,20 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ | |||
430 | return sfp; | 444 | return sfp; |
431 | } | 445 | } |
432 | 446 | ||
433 | /* Must match option string! */ | ||
434 | enum { | ||
435 | WGET_OPT_CONTINUE = (1 << 0), | ||
436 | WGET_OPT_SPIDER = (1 << 1), | ||
437 | WGET_OPT_QUIET = (1 << 2), | ||
438 | WGET_OPT_OUTNAME = (1 << 3), | ||
439 | WGET_OPT_PREFIX = (1 << 4), | ||
440 | WGET_OPT_PROXY = (1 << 5), | ||
441 | WGET_OPT_USER_AGENT = (1 << 6), | ||
442 | WGET_OPT_RETRIES = (1 << 7), | ||
443 | WGET_OPT_NETWORK_READ_TIMEOUT = (1 << 8), | ||
444 | WGET_OPT_PASSIVE = (1 << 9), | ||
445 | WGET_OPT_HEADER = (1 << 10) * ENABLE_FEATURE_WGET_LONG_OPTIONS, | ||
446 | WGET_OPT_POST_DATA = (1 << 11) * ENABLE_FEATURE_WGET_LONG_OPTIONS, | ||
447 | }; | ||
448 | |||
449 | static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) | 447 | static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) |
450 | { | 448 | { |
451 | char buf[512]; | 449 | char buf[512]; |
452 | 450 | #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT | |
453 | if (!(option_mask32 & WGET_OPT_QUIET)) | 451 | # if ENABLE_FEATURE_WGET_TIMEOUT |
454 | progress_meter(-1); | 452 | unsigned second_cnt; |
453 | # endif | ||
454 | struct pollfd polldata; | ||
455 | |||
456 | polldata.fd = fileno(dfp); | ||
457 | polldata.events = POLLIN | POLLPRI; | ||
458 | ndelay(polldata.fd); | ||
459 | #endif | ||
460 | progress_meter(PROGRESS_START); | ||
455 | 461 | ||
456 | if (G.chunked) | 462 | if (G.chunked) |
457 | goto get_clen; | 463 | goto get_clen; |
@@ -470,6 +476,23 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) | |||
470 | rdsz = (unsigned)G.content_len; | 476 | rdsz = (unsigned)G.content_len; |
471 | } | 477 | } |
472 | } | 478 | } |
479 | #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT | ||
480 | # if ENABLE_FEATURE_WGET_TIMEOUT | ||
481 | second_cnt = G.timeout_seconds; | ||
482 | # endif | ||
483 | while (1) { | ||
484 | if (safe_poll(&polldata, 1, 1000) != 0) | ||
485 | break; /* error, EOF, or data is available */ | ||
486 | # if ENABLE_FEATURE_WGET_TIMEOUT | ||
487 | if (second_cnt != 0 && --second_cnt == 0) { | ||
488 | progress_meter(PROGRESS_END); | ||
489 | bb_perror_msg_and_die("download timed out"); | ||
490 | } | ||
491 | # endif | ||
492 | /* Needed for "stalled" indicator */ | ||
493 | progress_meter(PROGRESS_BUMP); | ||
494 | } | ||
495 | #endif | ||
473 | n = safe_fread(buf, rdsz, dfp); | 496 | n = safe_fread(buf, rdsz, dfp); |
474 | if (n <= 0) { | 497 | if (n <= 0) { |
475 | if (ferror(dfp)) { | 498 | if (ferror(dfp)) { |
@@ -481,6 +504,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) | |||
481 | xwrite(output_fd, buf, n); | 504 | xwrite(output_fd, buf, n); |
482 | #if ENABLE_FEATURE_WGET_STATUSBAR | 505 | #if ENABLE_FEATURE_WGET_STATUSBAR |
483 | G.transferred += n; | 506 | G.transferred += n; |
507 | progress_meter(PROGRESS_BUMP); | ||
484 | #endif | 508 | #endif |
485 | if (G.got_clen) | 509 | if (G.got_clen) |
486 | G.content_len -= n; | 510 | G.content_len -= n; |
@@ -499,8 +523,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) | |||
499 | G.got_clen = 1; | 523 | G.got_clen = 1; |
500 | } | 524 | } |
501 | 525 | ||
502 | if (!(option_mask32 & WGET_OPT_QUIET)) | 526 | progress_meter(PROGRESS_END); |
503 | progress_meter(0); | ||
504 | } | 527 | } |
505 | 528 | ||
506 | int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 529 | int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
@@ -541,9 +564,11 @@ int wget_main(int argc UNUSED_PARAM, char **argv) | |||
541 | "directory-prefix\0" Required_argument "P" | 564 | "directory-prefix\0" Required_argument "P" |
542 | "proxy\0" Required_argument "Y" | 565 | "proxy\0" Required_argument "Y" |
543 | "user-agent\0" Required_argument "U" | 566 | "user-agent\0" Required_argument "U" |
567 | #if ENABLE_FEATURE_WGET_TIMEOUT | ||
568 | "timeout\0" Required_argument "T" | ||
569 | #endif | ||
544 | /* Ignored: */ | 570 | /* Ignored: */ |
545 | // "tries\0" Required_argument "t" | 571 | // "tries\0" Required_argument "t" |
546 | // "timeout\0" Required_argument "T" | ||
547 | /* Ignored (we always use PASV): */ | 572 | /* Ignored (we always use PASV): */ |
548 | "passive-ftp\0" No_argument "\xff" | 573 | "passive-ftp\0" No_argument "\xff" |
549 | "header\0" Required_argument "\xfe" | 574 | "header\0" Required_argument "\xfe" |
@@ -559,12 +584,12 @@ int wget_main(int argc UNUSED_PARAM, char **argv) | |||
559 | applet_long_options = wget_longopts; | 584 | applet_long_options = wget_longopts; |
560 | #endif | 585 | #endif |
561 | /* server.allocated = target.allocated = NULL; */ | 586 | /* server.allocated = target.allocated = NULL; */ |
562 | opt_complementary = "-1" IF_FEATURE_WGET_LONG_OPTIONS(":\xfe::"); | 587 | opt_complementary = "-1" IF_FEATURE_WGET_TIMEOUT(":T+") IF_FEATURE_WGET_LONG_OPTIONS(":\xfe::"); |
563 | opt = getopt32(argv, "csqO:P:Y:U:" /*ignored:*/ "t:T:", | 588 | opt = getopt32(argv, "csqO:P:Y:U:T:" /*ignored:*/ "t:", |
564 | &fname_out, &dir_prefix, | 589 | &fname_out, &dir_prefix, |
565 | &proxy_flag, &user_agent, | 590 | &proxy_flag, &user_agent, |
566 | NULL, /* -t RETRIES */ | 591 | IF_FEATURE_WGET_TIMEOUT(&G.timeout_seconds) IF_NOT_FEATURE_WGET_TIMEOUT(NULL), |
567 | NULL /* -T NETWORK_READ_TIMEOUT */ | 592 | NULL /* -t RETRIES */ |
568 | IF_FEATURE_WGET_LONG_OPTIONS(, &headers_llist) | 593 | IF_FEATURE_WGET_LONG_OPTIONS(, &headers_llist) |
569 | IF_FEATURE_WGET_LONG_OPTIONS(, &post_data) | 594 | IF_FEATURE_WGET_LONG_OPTIONS(, &post_data) |
570 | ); | 595 | ); |