diff options
author | Eric Andersen <andersen@codepoet.org> | 2000-10-03 00:21:45 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2000-10-03 00:21:45 +0000 |
commit | b520e083e0507f15e05230733a760e52dcd9f133 (patch) | |
tree | a60784dceb176b5b85286bd764ba39ebb985a59a /networking/wget.c | |
parent | 25b669c144949816d3c9726c79dbd6e93d53ee8b (diff) | |
download | busybox-w32-b520e083e0507f15e05230733a760e52dcd9f133.tar.gz busybox-w32-b520e083e0507f15e05230733a760e52dcd9f133.tar.bz2 busybox-w32-b520e083e0507f15e05230733a760e52dcd9f133.zip |
Add a spiffy progress meter.
-Erik
Diffstat (limited to 'networking/wget.c')
-rw-r--r-- | networking/wget.c | 251 |
1 files changed, 230 insertions, 21 deletions
diff --git a/networking/wget.c b/networking/wget.c index c95271b0d..02adc5520 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
@@ -5,6 +5,15 @@ | |||
5 | * Chip Rosenthal | 5 | * Chip Rosenthal |
6 | * Covad Communications | 6 | * Covad Communications |
7 | * <chip@laserlink.net> | 7 | * <chip@laserlink.net> |
8 | * | ||
9 | * Note: According to RFC2616 section 3.6.1, "All HTTP/1.1 applications | ||
10 | * MUST be able to receive and decode the "chunked" transfer-coding, | ||
11 | * and MUST ignore chunk-extension extensions they do not understand." | ||
12 | * This prevents this particular wget app from completely RFC compliant, | ||
13 | * and as such, prevents it from being used as a general purpose web browser... | ||
14 | * | ||
15 | * This is a design decision, since it makes the code smaller. | ||
16 | * | ||
8 | */ | 17 | */ |
9 | 18 | ||
10 | #include "busybox.h" | 19 | #include "busybox.h" |
@@ -13,7 +22,11 @@ | |||
13 | #include <unistd.h> | 22 | #include <unistd.h> |
14 | #include <ctype.h> | 23 | #include <ctype.h> |
15 | #include <string.h> | 24 | #include <string.h> |
25 | #include <unistd.h> | ||
26 | #include <signal.h> | ||
27 | #include <sys/ioctl.h> | ||
16 | 28 | ||
29 | #include <sys/time.h> | ||
17 | #include <sys/types.h> | 30 | #include <sys/types.h> |
18 | #include <sys/stat.h> | 31 | #include <sys/stat.h> |
19 | #include <sys/socket.h> | 32 | #include <sys/socket.h> |
@@ -25,7 +38,17 @@ | |||
25 | void parse_url(char *url, char **uri_host, int *uri_port, char **uri_path); | 38 | void parse_url(char *url, char **uri_host, int *uri_port, char **uri_path); |
26 | FILE *open_socket(char *host, int port); | 39 | FILE *open_socket(char *host, int port); |
27 | char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc); | 40 | char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc); |
28 | 41 | void progressmeter(int flag); | |
42 | |||
43 | /* Globals (can be accessed from signal handlers */ | ||
44 | static off_t filesize = 0; /* content-length of the file */ | ||
45 | #ifdef BB_FEATURE_STATUSBAR | ||
46 | static char *curfile; /* Name of current file being transferred. */ | ||
47 | static struct timeval start; /* Time a transfer started. */ | ||
48 | volatile unsigned long statbytes; /* Number of bytes transferred so far. */ | ||
49 | /* For progressmeter() -- number of seconds before xfer considered "stalled" */ | ||
50 | #define STALLTIME 5 | ||
51 | #endif | ||
29 | 52 | ||
30 | int wget_main(int argc, char **argv) | 53 | int wget_main(int argc, char **argv) |
31 | { | 54 | { |
@@ -39,7 +62,7 @@ int wget_main(int argc, char **argv) | |||
39 | int do_continue = 0; /* continue a prev transfer (-c) */ | 62 | int do_continue = 0; /* continue a prev transfer (-c) */ |
40 | long beg_range = 0L; /* range at which continue begins */ | 63 | long beg_range = 0L; /* range at which continue begins */ |
41 | int got_clen = 0; /* got content-length: from server */ | 64 | int got_clen = 0; /* got content-length: from server */ |
42 | long clen = 1L; /* the content length */ | 65 | FILE *output; /* socket to web server */ |
43 | 66 | ||
44 | /* | 67 | /* |
45 | * Crack command line. | 68 | * Crack command line. |
@@ -62,12 +85,20 @@ int wget_main(int argc, char **argv) | |||
62 | 85 | ||
63 | /* Guess an output filename */ | 86 | /* Guess an output filename */ |
64 | if (!fname_out) { | 87 | if (!fname_out) { |
65 | fname_out = get_last_path_component(argv[optind]); | 88 | fname_out = |
89 | #ifdef BB_FEATURE_STATUSBAR | ||
90 | curfile = | ||
91 | #endif | ||
92 | get_last_path_component(argv[optind]); | ||
93 | #ifdef BB_FEATURE_STATUSBAR | ||
94 | } else { | ||
95 | curfile=argv[optind]; | ||
96 | #endif | ||
66 | } | 97 | } |
67 | 98 | ||
99 | |||
68 | if (do_continue && !fname_out) | 100 | if (do_continue && !fname_out) |
69 | fatalError("wget: cannot specify continue (-c) without a filename (-O)\n"); | 101 | fatalError("wget: cannot specify continue (-c) without a filename (-O)\n"); |
70 | |||
71 | /* | 102 | /* |
72 | * Parse url into components. | 103 | * Parse url into components. |
73 | */ | 104 | */ |
@@ -82,8 +113,11 @@ int wget_main(int argc, char **argv) | |||
82 | * Open the output stream. | 113 | * Open the output stream. |
83 | */ | 114 | */ |
84 | if (fname_out != NULL) { | 115 | if (fname_out != NULL) { |
85 | if (freopen(fname_out, (do_continue ? "a" : "w"), stdout) == NULL) | 116 | if ( (output=fopen(fname_out, (do_continue ? "a" : "w"))) |
117 | == NULL) | ||
86 | fatalError("wget: freopen(%s): %s\n", fname_out, strerror(errno)); | 118 | fatalError("wget: freopen(%s): %s\n", fname_out, strerror(errno)); |
119 | } else { | ||
120 | output=stdout; | ||
87 | } | 121 | } |
88 | 122 | ||
89 | /* | 123 | /* |
@@ -91,7 +125,7 @@ int wget_main(int argc, char **argv) | |||
91 | */ | 125 | */ |
92 | if (do_continue) { | 126 | if (do_continue) { |
93 | struct stat sbuf; | 127 | struct stat sbuf; |
94 | if (fstat(fileno(stdout), &sbuf) < 0) | 128 | if (fstat(fileno(output), &sbuf) < 0) |
95 | fatalError("wget: fstat(): %s\n", strerror(errno)); | 129 | fatalError("wget: fstat(): %s\n", strerror(errno)); |
96 | if (sbuf.st_size > 0) | 130 | if (sbuf.st_size > 0) |
97 | beg_range = sbuf.st_size; | 131 | beg_range = sbuf.st_size; |
@@ -117,16 +151,16 @@ int wget_main(int argc, char **argv) | |||
117 | for ( ; isspace(*s) ; ++s) | 151 | for ( ; isspace(*s) ; ++s) |
118 | ; | 152 | ; |
119 | switch (atoi(s)) { | 153 | switch (atoi(s)) { |
120 | case 200: | 154 | case 200: |
121 | if (!do_continue) | 155 | if (!do_continue) |
122 | break; | 156 | break; |
123 | fatalError("wget: cannot continue - server does not properly support ranges\n"); | 157 | fatalError("wget: server does not support ranges\n"); |
124 | case 206: | 158 | case 206: |
125 | if (do_continue) | 159 | if (do_continue) |
126 | break; | 160 | break; |
127 | /*FALLTHRU*/ | 161 | /*FALLTHRU*/ |
128 | default: | 162 | default: |
129 | fatalError("wget: server returned error: %s", buf); | 163 | fatalError("wget: server returned error: %s", buf); |
130 | } | 164 | } |
131 | 165 | ||
132 | /* | 166 | /* |
@@ -134,12 +168,12 @@ int wget_main(int argc, char **argv) | |||
134 | */ | 168 | */ |
135 | while ((s = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) { | 169 | while ((s = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) { |
136 | if (strcmp(buf, "content-length") == 0) { | 170 | if (strcmp(buf, "content-length") == 0) { |
137 | clen = atol(s); | 171 | filesize = atol(s); |
138 | got_clen = 1; | 172 | got_clen = 1; |
139 | continue; | 173 | continue; |
140 | } | 174 | } |
141 | if (strcmp(buf, "transfer-encoding") == 0) { | 175 | if (strcmp(buf, "transfer-encoding") == 0) { |
142 | fatalError("wget: i do not do transfer encodings, server wants to do: %s\n", s); | 176 | fatalError("wget: server wants to do %s transfer encoding\n", s); |
143 | continue; | 177 | continue; |
144 | } | 178 | } |
145 | } | 179 | } |
@@ -147,10 +181,18 @@ int wget_main(int argc, char **argv) | |||
147 | /* | 181 | /* |
148 | * Retrieve HTTP body. | 182 | * Retrieve HTTP body. |
149 | */ | 183 | */ |
150 | while (clen > 0 && (n = fread(buf, 1, sizeof(buf), sfp)) > 0) { | 184 | #ifdef BB_FEATURE_STATUSBAR |
151 | fwrite(buf, 1, n, stdout); | 185 | statbytes=0; |
186 | progressmeter(-1); | ||
187 | #endif | ||
188 | while (filesize > 0 && (n = fread(buf, 1, sizeof(buf), sfp)) > 0) { | ||
189 | fwrite(buf, 1, n, output); | ||
190 | #ifdef BB_FEATURE_STATUSBAR | ||
191 | statbytes+=n; | ||
192 | progressmeter(1); | ||
193 | #endif | ||
152 | if (got_clen) | 194 | if (got_clen) |
153 | clen -= n; | 195 | filesize -= n; |
154 | } | 196 | } |
155 | if (n == 0 && ferror(sfp)) | 197 | if (n == 0 && ferror(sfp)) |
156 | fatalError("wget: network read error: %s", strerror(errno)); | 198 | fatalError("wget: network read error: %s", strerror(errno)); |
@@ -259,6 +301,172 @@ char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc) | |||
259 | return hdrval; | 301 | return hdrval; |
260 | } | 302 | } |
261 | 303 | ||
304 | #ifdef BB_FEATURE_STATUSBAR | ||
305 | /* Stuff below is from BSD rcp util.c, as added to openshh. */ | ||
306 | |||
307 | /*- | ||
308 | * Copyright (c) 1992, 1993 | ||
309 | * The Regents of the University of California. All rights reserved. | ||
310 | * | ||
311 | * Redistribution and use in source and binary forms, with or without | ||
312 | * modification, are permitted provided that the following conditions | ||
313 | * are met: | ||
314 | * 1. Redistributions of source code must retain the above copyright | ||
315 | * notice, this list of conditions and the following disclaimer. | ||
316 | * 2. Redistributions in binary form must reproduce the above copyright | ||
317 | * notice, this list of conditions and the following disclaimer in the | ||
318 | * documentation and/or other materials provided with the distribution. | ||
319 | * 3. All advertising materials mentioning features or use of this software | ||
320 | * must display the following acknowledgement: | ||
321 | * This product includes software developed by the University of | ||
322 | * California, Berkeley and its contributors. | ||
323 | * 4. Neither the name of the University nor the names of its contributors | ||
324 | * may be used to endorse or promote products derived from this software | ||
325 | * without specific prior written permission. | ||
326 | * | ||
327 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
328 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
329 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
330 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
331 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
332 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
333 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
334 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
335 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
336 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
337 | * SUCH DAMAGE. | ||
338 | * | ||
339 | * $Id: wget.c,v 1.5 2000/10/03 00:21:45 andersen Exp $ | ||
340 | */ | ||
341 | |||
342 | |||
343 | int | ||
344 | getttywidth(void) | ||
345 | { | ||
346 | struct winsize winsize; | ||
347 | |||
348 | if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1) | ||
349 | return (winsize.ws_col ? winsize.ws_col : 80); | ||
350 | else | ||
351 | return (80); | ||
352 | } | ||
353 | |||
354 | void | ||
355 | updateprogressmeter(int ignore) | ||
356 | { | ||
357 | int save_errno = errno; | ||
358 | |||
359 | progressmeter(0); | ||
360 | errno = save_errno; | ||
361 | } | ||
362 | |||
363 | void | ||
364 | alarmtimer(int wait) | ||
365 | { | ||
366 | struct itimerval itv; | ||
367 | |||
368 | itv.it_value.tv_sec = wait; | ||
369 | itv.it_value.tv_usec = 0; | ||
370 | itv.it_interval = itv.it_value; | ||
371 | setitimer(ITIMER_REAL, &itv, NULL); | ||
372 | } | ||
373 | |||
374 | |||
375 | void | ||
376 | progressmeter(int flag) | ||
377 | { | ||
378 | static const char prefixes[] = " KMGTP"; | ||
379 | static struct timeval lastupdate; | ||
380 | static off_t lastsize; | ||
381 | struct timeval now, td, wait; | ||
382 | off_t cursize, abbrevsize; | ||
383 | double elapsed; | ||
384 | int ratio, barlength, i, remaining; | ||
385 | char buf[256]; | ||
386 | |||
387 | if (flag == -1) { | ||
388 | (void) gettimeofday(&start, (struct timezone *) 0); | ||
389 | lastupdate = start; | ||
390 | lastsize = 0; | ||
391 | } | ||
392 | |||
393 | (void) gettimeofday(&now, (struct timezone *) 0); | ||
394 | cursize = statbytes; | ||
395 | if (filesize != 0) { | ||
396 | ratio = 100.0 * cursize / filesize; | ||
397 | ratio = MAX(ratio, 0); | ||
398 | ratio = MIN(ratio, 100); | ||
399 | } else | ||
400 | ratio = 100; | ||
401 | |||
402 | snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ", curfile, ratio); | ||
403 | |||
404 | barlength = getttywidth() - 51; | ||
405 | if (barlength > 0) { | ||
406 | i = barlength * ratio / 100; | ||
407 | snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), | ||
408 | "|%.*s%*s|", i, | ||
409 | "*****************************************************************************" | ||
410 | "*****************************************************************************", | ||
411 | barlength - i, ""); | ||
412 | } | ||
413 | i = 0; | ||
414 | abbrevsize = cursize; | ||
415 | while (abbrevsize >= 100000 && i < sizeof(prefixes)) { | ||
416 | i++; | ||
417 | abbrevsize >>= 10; | ||
418 | } | ||
419 | snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5d %c%c ", | ||
420 | (int) abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' : | ||
421 | 'B'); | ||
422 | |||
423 | timersub(&now, &lastupdate, &wait); | ||
424 | if (cursize > lastsize) { | ||
425 | lastupdate = now; | ||
426 | lastsize = cursize; | ||
427 | if (wait.tv_sec >= STALLTIME) { | ||
428 | start.tv_sec += wait.tv_sec; | ||
429 | start.tv_usec += wait.tv_usec; | ||
430 | } | ||
431 | wait.tv_sec = 0; | ||
432 | } | ||
433 | timersub(&now, &start, &td); | ||
434 | elapsed = td.tv_sec + (td.tv_usec / 1000000.0); | ||
435 | |||
436 | if (statbytes <= 0 || elapsed <= 0.0 || cursize > filesize) { | ||
437 | snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), | ||
438 | " --:-- ETA"); | ||
439 | } else if (wait.tv_sec >= STALLTIME) { | ||
440 | snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), | ||
441 | " - stalled -"); | ||
442 | } else { | ||
443 | remaining = (int) (filesize / (statbytes / elapsed) - elapsed); | ||
444 | i = remaining / 3600; | ||
445 | if (i) | ||
446 | snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), | ||
447 | "%2d:", i); | ||
448 | else | ||
449 | snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), | ||
450 | " "); | ||
451 | i = remaining % 3600; | ||
452 | snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), | ||
453 | "%02d:%02d ETA", i / 60, i % 60); | ||
454 | } | ||
455 | write(fileno(stdout), buf, strlen(buf)); | ||
456 | |||
457 | if (flag == -1) { | ||
458 | struct sigaction sa; | ||
459 | sa.sa_handler = updateprogressmeter; | ||
460 | sigemptyset(&sa.sa_mask); | ||
461 | sa.sa_flags = SA_RESTART; | ||
462 | sigaction(SIGALRM, &sa, NULL); | ||
463 | alarmtimer(1); | ||
464 | } else if (flag == 1) { | ||
465 | alarmtimer(0); | ||
466 | statbytes = 0; | ||
467 | } | ||
468 | } | ||
469 | #endif | ||
262 | /* | 470 | /* |
263 | Local Variables: | 471 | Local Variables: |
264 | c-file-style: "linux" | 472 | c-file-style: "linux" |
@@ -266,3 +474,4 @@ c-basic-offset: 4 | |||
266 | tab-width: 4 | 474 | tab-width: 4 |
267 | End: | 475 | End: |
268 | */ | 476 | */ |
477 | |||