diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-09-24 18:24:17 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-09-24 18:24:17 +0000 |
commit | 47ddd01b3cc8d262f6c97b41b4bb480281eeb591 (patch) | |
tree | 4794e2f04874d002378776282bb43c164083d9ba | |
parent | 7710563858a1e1d1a0af81d18222eee0259c00f2 (diff) | |
download | busybox-w32-47ddd01b3cc8d262f6c97b41b4bb480281eeb591.tar.gz busybox-w32-47ddd01b3cc8d262f6c97b41b4bb480281eeb591.tar.bz2 busybox-w32-47ddd01b3cc8d262f6c97b41b4bb480281eeb591.zip |
wget: reorder functions, no code changes
-rw-r--r-- | networking/wget.c | 621 |
1 files changed, 305 insertions, 316 deletions
diff --git a/networking/wget.c b/networking/wget.c index 2cc426f19..23a2fa855 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
@@ -50,20 +50,166 @@ struct BUG_G_too_big { | |||
50 | #define INIT_G() do { } while (0) | 50 | #define INIT_G() do { } while (0) |
51 | 51 | ||
52 | 52 | ||
53 | static void parse_url(char *url, struct host_info *h); | ||
54 | static FILE *open_socket(len_and_sockaddr *lsa); | ||
55 | static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*,int *istrunc*/ ); | ||
56 | static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf); | ||
57 | |||
58 | #if ENABLE_FEATURE_WGET_STATUSBAR | 53 | #if ENABLE_FEATURE_WGET_STATUSBAR |
59 | static void progressmeter(int flag); | ||
60 | enum { | 54 | enum { |
61 | STALLTIME = 5 /* Seconds when xfer considered "stalled" */ | 55 | STALLTIME = 5 /* Seconds when xfer considered "stalled" */ |
62 | }; | 56 | }; |
63 | #else | 57 | |
64 | static ALWAYS_INLINE void progressmeter(int flag) {} | 58 | static int getttywidth(void) |
59 | { | ||
60 | int width; | ||
61 | get_terminal_width_height(0, &width, NULL); | ||
62 | return width; | ||
63 | } | ||
64 | |||
65 | static void updateprogressmeter(int ignore) | ||
66 | { | ||
67 | int save_errno = errno; | ||
68 | |||
69 | progressmeter(0); | ||
70 | errno = save_errno; | ||
71 | } | ||
72 | |||
73 | static void alarmtimer(int iwait) | ||
74 | { | ||
75 | struct itimerval itv; | ||
76 | |||
77 | itv.it_value.tv_sec = iwait; | ||
78 | itv.it_value.tv_usec = 0; | ||
79 | itv.it_interval = itv.it_value; | ||
80 | setitimer(ITIMER_REAL, &itv, NULL); | ||
81 | } | ||
82 | |||
83 | static void progressmeter(int flag) | ||
84 | { | ||
85 | off_t abbrevsize; | ||
86 | unsigned since_last_update, elapsed; | ||
87 | unsigned ratio; | ||
88 | int barlength, i; | ||
89 | |||
90 | if (flag == -1) { /* first call to progressmeter */ | ||
91 | start_sec = monotonic_sec(); | ||
92 | lastupdate_sec = start_sec; | ||
93 | lastsize = 0; | ||
94 | totalsize = content_len + beg_range; /* as content_len changes.. */ | ||
95 | } | ||
96 | |||
97 | ratio = 100; | ||
98 | if (totalsize != 0 && !chunked) { | ||
99 | /* long long helps to have it working even if !LFS */ | ||
100 | ratio = (unsigned) (100ULL * (transferred+beg_range) / totalsize); | ||
101 | if (ratio > 100) ratio = 100; | ||
102 | } | ||
103 | |||
104 | fprintf(stderr, "\r%-20.20s%4d%% ", curfile, ratio); | ||
105 | |||
106 | barlength = getttywidth() - 49; | ||
107 | if (barlength > 0) { | ||
108 | /* god bless gcc for variable arrays :) */ | ||
109 | i = barlength * ratio / 100; | ||
110 | { | ||
111 | char buf[i+1]; | ||
112 | memset(buf, '*', i); | ||
113 | buf[i] = '\0'; | ||
114 | fprintf(stderr, "|%s%*s|", buf, barlength - i, ""); | ||
115 | } | ||
116 | } | ||
117 | i = 0; | ||
118 | abbrevsize = transferred + beg_range; | ||
119 | while (abbrevsize >= 100000) { | ||
120 | i++; | ||
121 | abbrevsize >>= 10; | ||
122 | } | ||
123 | /* see http://en.wikipedia.org/wiki/Tera */ | ||
124 | fprintf(stderr, "%6d%c ", (int)abbrevsize, " kMGTPEZY"[i]); | ||
125 | |||
126 | // Nuts! Ain't it easier to update progress meter ONLY when we transferred++? | ||
127 | // FIXME: get rid of alarmtimer + updateprogressmeter mess | ||
128 | |||
129 | elapsed = monotonic_sec(); | ||
130 | since_last_update = elapsed - lastupdate_sec; | ||
131 | if (transferred > lastsize) { | ||
132 | lastupdate_sec = elapsed; | ||
133 | lastsize = transferred; | ||
134 | if (since_last_update >= STALLTIME) { | ||
135 | /* We "cut off" these seconds from elapsed time | ||
136 | * by adjusting start time */ | ||
137 | start_sec += since_last_update; | ||
138 | } | ||
139 | since_last_update = 0; /* we are un-stalled now */ | ||
140 | } | ||
141 | elapsed -= start_sec; /* now it's "elapsed since start" */ | ||
142 | |||
143 | if (since_last_update >= STALLTIME) { | ||
144 | fprintf(stderr, " - stalled -"); | ||
145 | } else { | ||
146 | off_t to_download = totalsize - beg_range; | ||
147 | if (transferred <= 0 || (int)elapsed <= 0 || transferred > to_download || chunked) { | ||
148 | fprintf(stderr, "--:--:-- ETA"); | ||
149 | } else { | ||
150 | /* to_download / (transferred/elapsed) - elapsed: */ | ||
151 | int eta = (int) ((unsigned long long)to_download*elapsed/transferred - elapsed); | ||
152 | /* (long long helps to have working ETA even if !LFS) */ | ||
153 | i = eta % 3600; | ||
154 | fprintf(stderr, "%02d:%02d:%02d ETA", eta / 3600, i / 60, i % 60); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | if (flag == -1) { /* first call to progressmeter */ | ||
159 | struct sigaction sa; | ||
160 | sa.sa_handler = updateprogressmeter; | ||
161 | sigemptyset(&sa.sa_mask); | ||
162 | sa.sa_flags = SA_RESTART; | ||
163 | sigaction(SIGALRM, &sa, NULL); | ||
164 | alarmtimer(1); | ||
165 | } else if (flag == 1) { /* last call to progressmeter */ | ||
166 | alarmtimer(0); | ||
167 | transferred = 0; | ||
168 | putc('\n', stderr); | ||
169 | } | ||
170 | } | ||
171 | /* Original copyright notice which applies to the CONFIG_FEATURE_WGET_STATUSBAR stuff, | ||
172 | * much of which was blatantly stolen from openssh. */ | ||
173 | /*- | ||
174 | * Copyright (c) 1992, 1993 | ||
175 | * The Regents of the University of California. All rights reserved. | ||
176 | * | ||
177 | * Redistribution and use in source and binary forms, with or without | ||
178 | * modification, are permitted provided that the following conditions | ||
179 | * are met: | ||
180 | * 1. Redistributions of source code must retain the above copyright | ||
181 | * notice, this list of conditions and the following disclaimer. | ||
182 | * 2. Redistributions in binary form must reproduce the above copyright | ||
183 | * notice, this list of conditions and the following disclaimer in the | ||
184 | * documentation and/or other materials provided with the distribution. | ||
185 | * | ||
186 | * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change | ||
187 | * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> | ||
188 | * | ||
189 | * 4. Neither the name of the University nor the names of its contributors | ||
190 | * may be used to endorse or promote products derived from this software | ||
191 | * without specific prior written permission. | ||
192 | * | ||
193 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
194 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
195 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
196 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
197 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
198 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
199 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
200 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
201 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
202 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
203 | * SUCH DAMAGE. | ||
204 | * | ||
205 | */ | ||
206 | #else /* FEATURE_WGET_STATUSBAR */ | ||
207 | |||
208 | static ALWAYS_INLINE void progressmeter(int flag) { } | ||
209 | |||
65 | #endif | 210 | #endif |
66 | 211 | ||
212 | |||
67 | /* Read NMEMB bytes into PTR from STREAM. Returns the number of bytes read, | 213 | /* Read NMEMB bytes into PTR from STREAM. Returns the number of bytes read, |
68 | * and a short count if an eof or non-interrupt error is encountered. */ | 214 | * and a short count if an eof or non-interrupt error is encountered. */ |
69 | static size_t safe_fread(void *ptr, size_t nmemb, FILE *stream) | 215 | static size_t safe_fread(void *ptr, size_t nmemb, FILE *stream) |
@@ -107,6 +253,157 @@ static char *base64enc_512(char buf[512], const char *str) | |||
107 | } | 253 | } |
108 | #endif | 254 | #endif |
109 | 255 | ||
256 | |||
257 | static FILE *open_socket(len_and_sockaddr *lsa) | ||
258 | { | ||
259 | FILE *fp; | ||
260 | |||
261 | /* glibc 2.4 seems to try seeking on it - ??! */ | ||
262 | /* hopefully it understands what ESPIPE means... */ | ||
263 | fp = fdopen(xconnect_stream(lsa), "r+"); | ||
264 | if (fp == NULL) | ||
265 | bb_perror_msg_and_die("fdopen"); | ||
266 | |||
267 | return fp; | ||
268 | } | ||
269 | |||
270 | |||
271 | static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf) | ||
272 | { | ||
273 | int result; | ||
274 | if (s1) { | ||
275 | if (!s2) s2 = ""; | ||
276 | fprintf(fp, "%s%s\r\n", s1, s2); | ||
277 | fflush(fp); | ||
278 | } | ||
279 | |||
280 | do { | ||
281 | char *buf_ptr; | ||
282 | |||
283 | if (fgets(buf, 510, fp) == NULL) { | ||
284 | bb_perror_msg_and_die("error getting response"); | ||
285 | } | ||
286 | buf_ptr = strstr(buf, "\r\n"); | ||
287 | if (buf_ptr) { | ||
288 | *buf_ptr = '\0'; | ||
289 | } | ||
290 | } while (!isdigit(buf[0]) || buf[3] != ' '); | ||
291 | |||
292 | buf[3] = '\0'; | ||
293 | result = xatoi_u(buf); | ||
294 | buf[3] = ' '; | ||
295 | return result; | ||
296 | } | ||
297 | |||
298 | |||
299 | static void parse_url(char *src_url, struct host_info *h) | ||
300 | { | ||
301 | char *url, *p, *sp; | ||
302 | |||
303 | /* h->allocated = */ url = xstrdup(src_url); | ||
304 | |||
305 | if (strncmp(url, "http://", 7) == 0) { | ||
306 | h->port = bb_lookup_port("http", "tcp", 80); | ||
307 | h->host = url + 7; | ||
308 | h->is_ftp = 0; | ||
309 | } else if (strncmp(url, "ftp://", 6) == 0) { | ||
310 | h->port = bb_lookup_port("ftp", "tcp", 21); | ||
311 | h->host = url + 6; | ||
312 | h->is_ftp = 1; | ||
313 | } else | ||
314 | bb_error_msg_and_die("not an http or ftp url: %s", url); | ||
315 | |||
316 | // FYI: | ||
317 | // "Real" wget 'http://busybox.net?var=a/b' sends this request: | ||
318 | // 'GET /?var=a/b HTTP 1.0' | ||
319 | // and saves 'index.html?var=a%2Fb' (we save 'b') | ||
320 | // wget 'http://busybox.net?login=john@doe': | ||
321 | // request: 'GET /?login=john@doe HTTP/1.0' | ||
322 | // saves: 'index.html?login=john@doe' (we save '?login=john@doe') | ||
323 | // wget 'http://busybox.net#test/test': | ||
324 | // request: 'GET / HTTP/1.0' | ||
325 | // saves: 'index.html' (we save 'test') | ||
326 | // | ||
327 | // We also don't add unique .N suffix if file exists... | ||
328 | sp = strchr(h->host, '/'); | ||
329 | p = strchr(h->host, '?'); if (!sp || (p && sp > p)) sp = p; | ||
330 | p = strchr(h->host, '#'); if (!sp || (p && sp > p)) sp = p; | ||
331 | if (!sp) { | ||
332 | /* must be writable because of bb_get_last_path_component() */ | ||
333 | static char nullstr[] ALIGN1 = ""; | ||
334 | h->path = nullstr; | ||
335 | } else if (*sp == '/') { | ||
336 | *sp = '\0'; | ||
337 | h->path = sp + 1; | ||
338 | } else { // '#' or '?' | ||
339 | // http://busybox.net?login=john@doe is a valid URL | ||
340 | // memmove converts to: | ||
341 | // http:/busybox.nett?login=john@doe... | ||
342 | memmove(h->host-1, h->host, sp - h->host); | ||
343 | h->host--; | ||
344 | sp[-1] = '\0'; | ||
345 | h->path = sp; | ||
346 | } | ||
347 | |||
348 | sp = strrchr(h->host, '@'); | ||
349 | h->user = NULL; | ||
350 | if (sp != NULL) { | ||
351 | h->user = h->host; | ||
352 | *sp = '\0'; | ||
353 | h->host = sp + 1; | ||
354 | } | ||
355 | |||
356 | sp = h->host; | ||
357 | } | ||
358 | |||
359 | |||
360 | static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/) | ||
361 | { | ||
362 | char *s, *hdrval; | ||
363 | int c; | ||
364 | |||
365 | /* *istrunc = 0; */ | ||
366 | |||
367 | /* retrieve header line */ | ||
368 | if (fgets(buf, bufsiz, fp) == NULL) | ||
369 | return NULL; | ||
370 | |||
371 | /* see if we are at the end of the headers */ | ||
372 | for (s = buf; *s == '\r'; ++s) | ||
373 | continue; | ||
374 | if (*s == '\n') | ||
375 | return NULL; | ||
376 | |||
377 | /* convert the header name to lower case */ | ||
378 | for (s = buf; isalnum(*s) || *s == '-' || *s == '.'; ++s) | ||
379 | *s = tolower(*s); | ||
380 | |||
381 | /* verify we are at the end of the header name */ | ||
382 | if (*s != ':') | ||
383 | bb_error_msg_and_die("bad header line: %s", buf); | ||
384 | |||
385 | /* locate the start of the header value */ | ||
386 | *s++ = '\0'; | ||
387 | hdrval = skip_whitespace(s); | ||
388 | |||
389 | /* locate the end of header */ | ||
390 | while (*s && *s != '\r' && *s != '\n') | ||
391 | ++s; | ||
392 | |||
393 | /* end of header found */ | ||
394 | if (*s) { | ||
395 | *s = '\0'; | ||
396 | return hdrval; | ||
397 | } | ||
398 | |||
399 | /* Rats! The buffer isn't big enough to hold the entire header value. */ | ||
400 | while (c = getc(fp), c != EOF && c != '\n') | ||
401 | continue; | ||
402 | /* *istrunc = 1; */ | ||
403 | return hdrval; | ||
404 | } | ||
405 | |||
406 | |||
110 | int wget_main(int argc, char **argv); | 407 | int wget_main(int argc, char **argv); |
111 | int wget_main(int argc, char **argv) | 408 | int wget_main(int argc, char **argv) |
112 | { | 409 | { |
@@ -527,312 +824,4 @@ int wget_main(int argc, char **argv) | |||
527 | } | 824 | } |
528 | 825 | ||
529 | return EXIT_SUCCESS; | 826 | return EXIT_SUCCESS; |
530 | } /* wget_main() */ | ||
531 | |||
532 | |||
533 | static void parse_url(char *src_url, struct host_info *h) | ||
534 | { | ||
535 | char *url, *p, *sp; | ||
536 | |||
537 | /* h->allocated = */ url = xstrdup(src_url); | ||
538 | |||
539 | if (strncmp(url, "http://", 7) == 0) { | ||
540 | h->port = bb_lookup_port("http", "tcp", 80); | ||
541 | h->host = url + 7; | ||
542 | h->is_ftp = 0; | ||
543 | } else if (strncmp(url, "ftp://", 6) == 0) { | ||
544 | h->port = bb_lookup_port("ftp", "tcp", 21); | ||
545 | h->host = url + 6; | ||
546 | h->is_ftp = 1; | ||
547 | } else | ||
548 | bb_error_msg_and_die("not an http or ftp url: %s", url); | ||
549 | |||
550 | // FYI: | ||
551 | // "Real" wget 'http://busybox.net?var=a/b' sends this request: | ||
552 | // 'GET /?var=a/b HTTP 1.0' | ||
553 | // and saves 'index.html?var=a%2Fb' (we save 'b') | ||
554 | // wget 'http://busybox.net?login=john@doe': | ||
555 | // request: 'GET /?login=john@doe HTTP/1.0' | ||
556 | // saves: 'index.html?login=john@doe' (we save '?login=john@doe') | ||
557 | // wget 'http://busybox.net#test/test': | ||
558 | // request: 'GET / HTTP/1.0' | ||
559 | // saves: 'index.html' (we save 'test') | ||
560 | // | ||
561 | // We also don't add unique .N suffix if file exists... | ||
562 | sp = strchr(h->host, '/'); | ||
563 | p = strchr(h->host, '?'); if (!sp || (p && sp > p)) sp = p; | ||
564 | p = strchr(h->host, '#'); if (!sp || (p && sp > p)) sp = p; | ||
565 | if (!sp) { | ||
566 | /* must be writable because of bb_get_last_path_component() */ | ||
567 | static char nullstr[] ALIGN1 = ""; | ||
568 | h->path = nullstr; | ||
569 | } else if (*sp == '/') { | ||
570 | *sp = '\0'; | ||
571 | h->path = sp + 1; | ||
572 | } else { // '#' or '?' | ||
573 | // http://busybox.net?login=john@doe is a valid URL | ||
574 | // memmove converts to: | ||
575 | // http:/busybox.nett?login=john@doe... | ||
576 | memmove(h->host-1, h->host, sp - h->host); | ||
577 | h->host--; | ||
578 | sp[-1] = '\0'; | ||
579 | h->path = sp; | ||
580 | } | ||
581 | |||
582 | sp = strrchr(h->host, '@'); | ||
583 | h->user = NULL; | ||
584 | if (sp != NULL) { | ||
585 | h->user = h->host; | ||
586 | *sp = '\0'; | ||
587 | h->host = sp + 1; | ||
588 | } | ||
589 | |||
590 | sp = h->host; | ||
591 | } | ||
592 | |||
593 | |||
594 | static FILE *open_socket(len_and_sockaddr *lsa) | ||
595 | { | ||
596 | FILE *fp; | ||
597 | |||
598 | /* glibc 2.4 seems to try seeking on it - ??! */ | ||
599 | /* hopefully it understands what ESPIPE means... */ | ||
600 | fp = fdopen(xconnect_stream(lsa), "r+"); | ||
601 | if (fp == NULL) | ||
602 | bb_perror_msg_and_die("fdopen"); | ||
603 | |||
604 | return fp; | ||
605 | } | 827 | } |
606 | |||
607 | |||
608 | static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/) | ||
609 | { | ||
610 | char *s, *hdrval; | ||
611 | int c; | ||
612 | |||
613 | /* *istrunc = 0; */ | ||
614 | |||
615 | /* retrieve header line */ | ||
616 | if (fgets(buf, bufsiz, fp) == NULL) | ||
617 | return NULL; | ||
618 | |||
619 | /* see if we are at the end of the headers */ | ||
620 | for (s = buf; *s == '\r'; ++s) | ||
621 | continue; | ||
622 | if (*s == '\n') | ||
623 | return NULL; | ||
624 | |||
625 | /* convert the header name to lower case */ | ||
626 | for (s = buf; isalnum(*s) || *s == '-' || *s == '.'; ++s) | ||
627 | *s = tolower(*s); | ||
628 | |||
629 | /* verify we are at the end of the header name */ | ||
630 | if (*s != ':') | ||
631 | bb_error_msg_and_die("bad header line: %s", buf); | ||
632 | |||
633 | /* locate the start of the header value */ | ||
634 | *s++ = '\0'; | ||
635 | hdrval = skip_whitespace(s); | ||
636 | |||
637 | /* locate the end of header */ | ||
638 | while (*s && *s != '\r' && *s != '\n') | ||
639 | ++s; | ||
640 | |||
641 | /* end of header found */ | ||
642 | if (*s) { | ||
643 | *s = '\0'; | ||
644 | return hdrval; | ||
645 | } | ||
646 | |||
647 | /* Rats! The buffer isn't big enough to hold the entire header value. */ | ||
648 | while (c = getc(fp), c != EOF && c != '\n') | ||
649 | continue; | ||
650 | /* *istrunc = 1; */ | ||
651 | return hdrval; | ||
652 | } | ||
653 | |||
654 | static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf) | ||
655 | { | ||
656 | int result; | ||
657 | if (s1) { | ||
658 | if (!s2) s2 = ""; | ||
659 | fprintf(fp, "%s%s\r\n", s1, s2); | ||
660 | fflush(fp); | ||
661 | } | ||
662 | |||
663 | do { | ||
664 | char *buf_ptr; | ||
665 | |||
666 | if (fgets(buf, 510, fp) == NULL) { | ||
667 | bb_perror_msg_and_die("error getting response"); | ||
668 | } | ||
669 | buf_ptr = strstr(buf, "\r\n"); | ||
670 | if (buf_ptr) { | ||
671 | *buf_ptr = '\0'; | ||
672 | } | ||
673 | } while (!isdigit(buf[0]) || buf[3] != ' '); | ||
674 | |||
675 | buf[3] = '\0'; | ||
676 | result = xatoi_u(buf); | ||
677 | buf[3] = ' '; | ||
678 | return result; | ||
679 | } | ||
680 | |||
681 | #if ENABLE_FEATURE_WGET_STATUSBAR | ||
682 | /* Stuff below is from BSD rcp util.c, as added to openshh. | ||
683 | * Original copyright notice is retained at the end of this file. | ||
684 | */ | ||
685 | static int | ||
686 | getttywidth(void) | ||
687 | { | ||
688 | int width; | ||
689 | get_terminal_width_height(0, &width, NULL); | ||
690 | return width; | ||
691 | } | ||
692 | |||
693 | static void | ||
694 | updateprogressmeter(int ignore) | ||
695 | { | ||
696 | int save_errno = errno; | ||
697 | |||
698 | progressmeter(0); | ||
699 | errno = save_errno; | ||
700 | } | ||
701 | |||
702 | static void alarmtimer(int iwait) | ||
703 | { | ||
704 | struct itimerval itv; | ||
705 | |||
706 | itv.it_value.tv_sec = iwait; | ||
707 | itv.it_value.tv_usec = 0; | ||
708 | itv.it_interval = itv.it_value; | ||
709 | setitimer(ITIMER_REAL, &itv, NULL); | ||
710 | } | ||
711 | |||
712 | static void | ||
713 | progressmeter(int flag) | ||
714 | { | ||
715 | off_t abbrevsize; | ||
716 | unsigned since_last_update, elapsed; | ||
717 | unsigned ratio; | ||
718 | int barlength, i; | ||
719 | |||
720 | if (flag == -1) { /* first call to progressmeter */ | ||
721 | start_sec = monotonic_sec(); | ||
722 | lastupdate_sec = start_sec; | ||
723 | lastsize = 0; | ||
724 | totalsize = content_len + beg_range; /* as content_len changes.. */ | ||
725 | } | ||
726 | |||
727 | ratio = 100; | ||
728 | if (totalsize != 0 && !chunked) { | ||
729 | /* long long helps to have it working even if !LFS */ | ||
730 | ratio = (unsigned) (100ULL * (transferred+beg_range) / totalsize); | ||
731 | if (ratio > 100) ratio = 100; | ||
732 | } | ||
733 | |||
734 | fprintf(stderr, "\r%-20.20s%4d%% ", curfile, ratio); | ||
735 | |||
736 | barlength = getttywidth() - 49; | ||
737 | if (barlength > 0) { | ||
738 | /* god bless gcc for variable arrays :) */ | ||
739 | i = barlength * ratio / 100; | ||
740 | { | ||
741 | char buf[i+1]; | ||
742 | memset(buf, '*', i); | ||
743 | buf[i] = '\0'; | ||
744 | fprintf(stderr, "|%s%*s|", buf, barlength - i, ""); | ||
745 | } | ||
746 | } | ||
747 | i = 0; | ||
748 | abbrevsize = transferred + beg_range; | ||
749 | while (abbrevsize >= 100000) { | ||
750 | i++; | ||
751 | abbrevsize >>= 10; | ||
752 | } | ||
753 | /* see http://en.wikipedia.org/wiki/Tera */ | ||
754 | fprintf(stderr, "%6d%c ", (int)abbrevsize, " kMGTPEZY"[i]); | ||
755 | |||
756 | // Nuts! Ain't it easier to update progress meter ONLY when we transferred++? | ||
757 | // FIXME: get rid of alarmtimer + updateprogressmeter mess | ||
758 | |||
759 | elapsed = monotonic_sec(); | ||
760 | since_last_update = elapsed - lastupdate_sec; | ||
761 | if (transferred > lastsize) { | ||
762 | lastupdate_sec = elapsed; | ||
763 | lastsize = transferred; | ||
764 | if (since_last_update >= STALLTIME) { | ||
765 | /* We "cut off" these seconds from elapsed time | ||
766 | * by adjusting start time */ | ||
767 | start_sec += since_last_update; | ||
768 | } | ||
769 | since_last_update = 0; /* we are un-stalled now */ | ||
770 | } | ||
771 | elapsed -= start_sec; /* now it's "elapsed since start" */ | ||
772 | |||
773 | if (since_last_update >= STALLTIME) { | ||
774 | fprintf(stderr, " - stalled -"); | ||
775 | } else { | ||
776 | off_t to_download = totalsize - beg_range; | ||
777 | if (transferred <= 0 || (int)elapsed <= 0 || transferred > to_download || chunked) { | ||
778 | fprintf(stderr, "--:--:-- ETA"); | ||
779 | } else { | ||
780 | /* to_download / (transferred/elapsed) - elapsed: */ | ||
781 | int eta = (int) ((unsigned long long)to_download*elapsed/transferred - elapsed); | ||
782 | /* (long long helps to have working ETA even if !LFS) */ | ||
783 | i = eta % 3600; | ||
784 | fprintf(stderr, "%02d:%02d:%02d ETA", eta / 3600, i / 60, i % 60); | ||
785 | } | ||
786 | } | ||
787 | |||
788 | if (flag == -1) { /* first call to progressmeter */ | ||
789 | struct sigaction sa; | ||
790 | sa.sa_handler = updateprogressmeter; | ||
791 | sigemptyset(&sa.sa_mask); | ||
792 | sa.sa_flags = SA_RESTART; | ||
793 | sigaction(SIGALRM, &sa, NULL); | ||
794 | alarmtimer(1); | ||
795 | } else if (flag == 1) { /* last call to progressmeter */ | ||
796 | alarmtimer(0); | ||
797 | transferred = 0; | ||
798 | putc('\n', stderr); | ||
799 | } | ||
800 | } | ||
801 | #endif /* FEATURE_WGET_STATUSBAR */ | ||
802 | |||
803 | /* Original copyright notice which applies to the CONFIG_FEATURE_WGET_STATUSBAR stuff, | ||
804 | * much of which was blatantly stolen from openssh. */ | ||
805 | |||
806 | /*- | ||
807 | * Copyright (c) 1992, 1993 | ||
808 | * The Regents of the University of California. All rights reserved. | ||
809 | * | ||
810 | * Redistribution and use in source and binary forms, with or without | ||
811 | * modification, are permitted provided that the following conditions | ||
812 | * are met: | ||
813 | * 1. Redistributions of source code must retain the above copyright | ||
814 | * notice, this list of conditions and the following disclaimer. | ||
815 | * 2. Redistributions in binary form must reproduce the above copyright | ||
816 | * notice, this list of conditions and the following disclaimer in the | ||
817 | * documentation and/or other materials provided with the distribution. | ||
818 | * | ||
819 | * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change | ||
820 | * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> | ||
821 | * | ||
822 | * 4. Neither the name of the University nor the names of its contributors | ||
823 | * may be used to endorse or promote products derived from this software | ||
824 | * without specific prior written permission. | ||
825 | * | ||
826 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
827 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
828 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
829 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
830 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
831 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
832 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
833 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
834 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
835 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
836 | * SUCH DAMAGE. | ||
837 | * | ||
838 | */ | ||