Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (16 years ago)
Author:
Bruno Cornec
Message:
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/stable/mindi-busybox/networking/wget.c

    r821 r1770  
    77 */
    88
    9 #include "busybox.h"
    10 #include <errno.h>
    11 #include <signal.h>
    12 #include <sys/ioctl.h>
    13 #include <getopt.h>
    14 
     9/* We want libc to give us xxx64 functions also */
     10/* http://www.unix.org/version2/whatsnew/lfs20mar.html */
     11//#define _LARGEFILE64_SOURCE 1
     12
     13#include <getopt.h> /* for struct option */
     14#include "libbb.h"
    1515
    1616struct host_info {
     17    // May be used if we ever will want to free() all xstrdup()s...
     18    /* char *allocated; */
    1719    char *host;
    1820    int port;
     
    2325
    2426static void parse_url(char *url, struct host_info *h);
    25 static FILE *open_socket(struct sockaddr_in *s_in);
     27static FILE *open_socket(len_and_sockaddr *lsa);
    2628static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc);
    27 static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf);
     29static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf);
    2830
    2931/* Globals (can be accessed from signal handlers */
    30 static off_t filesize;      /* content-length of the file */
    31 static int chunked;     /* chunked transfer encoding */
    32 #ifdef CONFIG_FEATURE_WGET_STATUSBAR
     32static off_t content_len;        /* Content-length of the file */
     33static off_t beg_range;          /* Range at which continue begins */
     34#if ENABLE_FEATURE_WGET_STATUSBAR
     35static off_t transferred;        /* Number of bytes transferred so far */
     36#endif
     37static bool chunked;                     /* chunked transfer encoding */
     38#if ENABLE_FEATURE_WGET_STATUSBAR
    3339static void progressmeter(int flag);
    34 static char *curfile;       /* Name of current file being transferred. */
    35 static struct timeval start;    /* Time a transfer started. */
    36 static off_t transferred;   /* Number of bytes transferred so far. */
    37 /* For progressmeter() -- number of seconds before xfer considered "stalled" */
     40static const char *curfile;             /* Name of current file being transferred */
    3841enum {
    39     STALLTIME = 5
     42    STALLTIME = 5                   /* Seconds when xfer considered "stalled" */
    4043};
    4144#else
    42 static inline void progressmeter(int flag) {}
    43 #endif
    44 
    45 static void close_and_delete_outfile(FILE* output, char *fname_out, int do_continue)
    46 {
    47     if (output != stdout && do_continue==0) {
    48         fclose(output);
    49         unlink(fname_out);
    50     }
    51 }
    52 
    53 /* Read NMEMB elements of SIZE bytes into PTR from STREAM.  Returns the
    54  * number of elements read, and a short count if an eof or non-interrupt
    55  * error is encountered.  */
    56 static size_t safe_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
    57 {
    58     size_t ret = 0;
     45static ALWAYS_INLINE void progressmeter(int flag) {}
     46#endif
     47
     48/* Read NMEMB bytes into PTR from STREAM.  Returns the number of bytes read,
     49 * and a short count if an eof or non-interrupt error is encountered.  */
     50static size_t safe_fread(void *ptr, size_t nmemb, FILE *stream)
     51{
     52    size_t ret;
     53    char *p = (char*)ptr;
    5954
    6055    do {
    6156        clearerr(stream);
    62         ret += fread((char *)ptr + (ret * size), size, nmemb - ret, stream);
    63     } while (ret < nmemb && ferror(stream) && errno == EINTR);
    64 
    65     return ret;
    66 }
    67 
    68 /* Write NMEMB elements of SIZE bytes from PTR to STREAM.  Returns the
    69  * number of elements written, and a short count if an eof or non-interrupt
    70  * error is encountered.  */
    71 static size_t safe_fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream)
    72 {
    73     size_t ret = 0;
    74 
    75     do {
    76         clearerr(stream);
    77         ret += fwrite((char *)ptr + (ret * size), size, nmemb - ret, stream);
    78     } while (ret < nmemb && ferror(stream) && errno == EINTR);
    79 
    80     return ret;
    81 }
    82 
    83 /* Read a line or SIZE - 1 bytes into S, whichever is less, from STREAM.
     57        ret = fread(p, 1, nmemb, stream);
     58        p += ret;
     59        nmemb -= ret;
     60    } while (nmemb && ferror(stream) && errno == EINTR);
     61
     62    return p - (char*)ptr;
     63}
     64
     65/* Read a line or SIZE-1 bytes into S, whichever is less, from STREAM.
    8466 * Returns S, or NULL if an eof or non-interrupt error is encountered.  */
    8567static char *safe_fgets(char *s, int size, FILE *stream)
     
    9577}
    9678
    97 #define close_delete_and_die(s...) { \
    98     close_and_delete_outfile(output, fname_out, do_continue); \
    99     bb_error_msg_and_die(s); }
    100 
    101 
    102 #ifdef CONFIG_FEATURE_WGET_AUTHENTICATION
    103 /*
    104  *  Base64-encode character string
    105  *  oops... isn't something similar in uuencode.c?
    106  *  XXX: It would be better to use already existing code
    107  */
    108 static char *base64enc(unsigned char *p, char *buf, int len) {
    109 
    110     char al[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    111             "0123456789+/";
    112     char *s = buf;
    113 
    114     while(*p) {
    115         if (s >= buf+len-4)
    116             bb_error_msg_and_die("buffer overflow");
    117         *(s++) = al[(*p >> 2) & 0x3F];
    118         *(s++) = al[((*p << 4) & 0x30) | ((*(p+1) >> 4) & 0x0F)];
    119         *s = *(s+1) = '=';
    120         *(s+2) = 0;
    121         if (! *(++p)) break;
    122         *(s++) = al[((*p << 2) & 0x3C) | ((*(p+1) >> 6) & 0x03)];
    123         if (! *(++p)) break;
    124         *(s++) = al[*(p++) & 0x3F];
    125     }
    126 
     79#if ENABLE_FEATURE_WGET_AUTHENTICATION
     80/* Base64-encode character string. buf is assumed to be char buf[512]. */
     81static char *base64enc_512(char buf[512], const char *str)
     82{
     83    unsigned len = strlen(str);
     84    if (len > 512/4*3 - 10) /* paranoia */
     85        len = 512/4*3 - 10;
     86    bb_uuencode(buf, str, len, bb_uuenc_tbl_base64);
    12787    return buf;
    12888}
    12989#endif
    13090
    131 #define WGET_OPT_CONTINUE   1
    132 #define WGET_OPT_QUIET  2
    133 #define WGET_OPT_PASSIVE    4
    134 #define WGET_OPT_OUTNAME    8
    135 #define WGET_OPT_HEADER 16
    136 #define WGET_OPT_PREFIX 32
    137 #define WGET_OPT_PROXY  64
    138 
    139 #if ENABLE_WGET_LONG_OPTIONS
    140 static const struct option wget_long_options[] = {
    141     { "continue",        0, NULL, 'c' },
    142     { "quiet",           0, NULL, 'q' },
    143     { "passive-ftp",     0, NULL, 139 },
    144     { "output-document", 1, NULL, 'O' },
    145     { "header",          1, NULL, 131 },
    146     { "directory-prefix",1, NULL, 'P' },
    147     { "proxy",           1, NULL, 'Y' },
    148     { 0,                 0, 0, 0 }
    149 };
    150 #endif
    151 
     91int wget_main(int argc, char **argv);
    15292int wget_main(int argc, char **argv)
    15393{
    154     int n, try=5, status;
    155     unsigned long opt;
     94    char buf[512];
     95    struct host_info server, target;
     96    len_and_sockaddr *lsa;
     97    int n, status;
    15698    int port;
     99    int try = 5;
     100    unsigned opt;
     101    char *str;
    157102    char *proxy = 0;
    158     char *dir_prefix=NULL;
    159     char *s, buf[512];
    160     struct stat sbuf;
    161     char extra_headers[1024];
    162     char *extra_headers_ptr = extra_headers;
    163     int extra_headers_left = sizeof(extra_headers);
    164     struct host_info server, target;
    165     struct sockaddr_in s_in;
     103    char *dir_prefix = NULL;
     104#if ENABLE_FEATURE_WGET_LONG_OPTIONS
     105    char *extra_headers = NULL;
    166106    llist_t *headers_llist = NULL;
    167 
    168     FILE *sfp = NULL;       /* socket to web/ftp server     */
    169     FILE *dfp = NULL;       /* socket to ftp server (data)      */
    170     char *fname_out = NULL;     /* where to direct output (-O)      */
    171     int do_continue = 0;        /* continue a prev transfer (-c)    */
    172     long beg_range = 0L;        /*   range at which continue begins */
    173     int got_clen = 0;       /* got content-length: from server  */
    174     FILE *output;           /* socket to web server         */
    175     int quiet_flag = FALSE;     /* Be verry, verry quiet...     */
    176     int use_proxy = 1;      /* Use proxies if env vars are set  */
    177     char *proxy_flag = "on";    /* Use proxies if env vars are set  */
    178 
    179     /*
    180      * Crack command line.
    181      */
    182     bb_opt_complementally = "-1:\203::";
    183 #if ENABLE_WGET_LONG_OPTIONS
    184     bb_applet_long_options = wget_long_options;
    185 #endif
    186     opt = bb_getopt_ulflags(argc, argv, "cq\213O:\203:P:Y:",
    187                     &fname_out, &headers_llist,
    188                     &dir_prefix, &proxy_flag);
    189     if (opt & WGET_OPT_CONTINUE) {
    190         ++do_continue;
    191     }
    192     if (opt & WGET_OPT_QUIET) {
    193         quiet_flag = TRUE;
    194     }
     107#endif
     108
     109    FILE *sfp = NULL;               /* socket to web/ftp server         */
     110    FILE *dfp = NULL;               /* socket to ftp server (data)      */
     111    char *fname_out = NULL;         /* where to direct output (-O)      */
     112    bool got_clen = 0;              /* got content-length: from server  */
     113    int output_fd = -1;
     114    bool use_proxy = 1;             /* Use proxies if env vars are set  */
     115    const char *proxy_flag = "on";  /* Use proxies if env vars are set  */
     116    const char *user_agent = "Wget";/* "User-Agent" header field        */
     117    static const char keywords[] ALIGN1 =
     118        "content-length\0""transfer-encoding\0""chunked\0""location\0";
     119    enum {
     120        KEY_content_length = 1, KEY_transfer_encoding, KEY_chunked, KEY_location
     121    };
     122    enum {
     123        WGET_OPT_CONTINUE   = 0x1,
     124        WGET_OPT_SPIDER     = 0x2,
     125        WGET_OPT_QUIET      = 0x4,
     126        WGET_OPT_OUTNAME    = 0x8,
     127        WGET_OPT_PREFIX     = 0x10,
     128        WGET_OPT_PROXY      = 0x20,
     129        WGET_OPT_USER_AGENT = 0x40,
     130        WGET_OPT_PASSIVE    = 0x80,
     131        WGET_OPT_HEADER     = 0x100,
     132    };
     133#if ENABLE_FEATURE_WGET_LONG_OPTIONS
     134    static const char wget_longopts[] ALIGN1 =
     135        /* name, has_arg, val */
     136        "continue\0"         No_argument       "c"
     137        "spider\0"           No_argument       "s"
     138        "quiet\0"            No_argument       "q"
     139        "output-document\0"  Required_argument "O"
     140        "directory-prefix\0" Required_argument "P"
     141        "proxy\0"            Required_argument "Y"
     142        "user-agent\0"       Required_argument "U"
     143        "passive-ftp\0"      No_argument       "\xff"
     144        "header\0"           Required_argument "\xfe"
     145        ;
     146    applet_long_options = wget_longopts;
     147#endif
     148    /* server.allocated = target.allocated = NULL; */
     149    opt_complementary = "-1" USE_FEATURE_WGET_LONG_OPTIONS(":\xfe::");
     150    opt = getopt32(argv, "csqO:P:Y:U:",
     151                &fname_out, &dir_prefix,
     152                &proxy_flag, &user_agent
     153                USE_FEATURE_WGET_LONG_OPTIONS(, &headers_llist)
     154                );
    195155    if (strcmp(proxy_flag, "off") == 0) {
    196         /* Use the proxy if necessary. */
     156        /* Use the proxy if necessary */
    197157        use_proxy = 0;
    198158    }
    199     if (opt & WGET_OPT_HEADER) {
     159#if ENABLE_FEATURE_WGET_LONG_OPTIONS
     160    if (headers_llist) {
     161        int size = 1;
     162        char *cp;
     163        llist_t *ll = headers_llist;
     164        while (ll) {
     165            size += strlen(ll->data) + 2;
     166            ll = ll->link;
     167        }
     168        extra_headers = cp = xmalloc(size);
    200169        while (headers_llist) {
    201             int arglen = strlen(headers_llist->data);
    202             if (extra_headers_left - arglen - 2 <= 0)
    203                 bb_error_msg_and_die("extra_headers buffer too small(need %i)", extra_headers_left - arglen);
    204             strcpy(extra_headers_ptr, headers_llist->data);
    205             extra_headers_ptr += arglen;
    206             extra_headers_left -= ( arglen + 2 );
    207             *extra_headers_ptr++ = '\r';
    208             *extra_headers_ptr++ = '\n';
    209             *(extra_headers_ptr + 1) = 0;
     170            cp += sprintf(cp, "%s\r\n", headers_llist->data);
    210171            headers_llist = headers_llist->link;
    211172        }
    212173    }
     174#endif
    213175
    214176    parse_url(argv[optind], &target);
     
    216178    server.port = target.port;
    217179
    218     /*
    219      * Use the proxy if necessary.
    220      */
     180    /* Use the proxy if necessary */
    221181    if (use_proxy) {
    222182        proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy");
    223183        if (proxy && *proxy) {
    224             parse_url(bb_xstrdup(proxy), &server);
     184            parse_url(proxy, &server);
    225185        } else {
    226186            use_proxy = 0;
     
    232192        // Dirty hack. Needed because bb_get_last_path_component
    233193        // will destroy trailing / by storing '\0' in last byte!
    234         if(*target.path && target.path[strlen(target.path)-1]!='/') {
    235             fname_out =
    236 #ifdef CONFIG_FEATURE_WGET_STATUSBAR
    237                 curfile =
    238 #endif
    239                 bb_get_last_path_component(target.path);
    240         }
    241         if (fname_out==NULL || strlen(fname_out)<1) {
    242             fname_out =
    243 #ifdef CONFIG_FEATURE_WGET_STATUSBAR
    244                 curfile =
    245 #endif
    246                 "index.html";
     194        if (!last_char_is(target.path, '/')) {
     195            fname_out = bb_get_last_path_component(target.path);
     196#if ENABLE_FEATURE_WGET_STATUSBAR
     197            curfile = fname_out;
     198#endif
     199        }
     200        if (!fname_out || !fname_out[0]) {
     201            /* bb_get_last_path_component writes
     202             * to last '/' only. We don't have one here... */
     203            fname_out = (char*)"index.html";
     204#if ENABLE_FEATURE_WGET_STATUSBAR
     205            curfile = fname_out;
     206#endif
    247207        }
    248208        if (dir_prefix != NULL)
    249209            fname_out = concat_path_file(dir_prefix, fname_out);
    250 #ifdef CONFIG_FEATURE_WGET_STATUSBAR
     210#if ENABLE_FEATURE_WGET_STATUSBAR
    251211    } else {
    252212        curfile = bb_get_last_path_component(fname_out);
    253213#endif
    254214    }
    255     if (do_continue && !fname_out)
    256         bb_error_msg_and_die("cannot specify continue (-c) without a filename (-O)");
    257 
    258 
    259     /*
    260      * Open the output file stream.
    261      */
    262     if (strcmp(fname_out, "-") == 0) {
    263         output = stdout;
    264         quiet_flag = TRUE;
    265     } else {
    266         output = bb_xfopen(fname_out, (do_continue ? "a" : "w"));
    267     }
    268 
    269     /*
    270      * Determine where to start transfer.
    271      */
    272     if (do_continue) {
    273         if (fstat(fileno(output), &sbuf) < 0)
    274             bb_perror_msg_and_die("fstat()");
    275         if (sbuf.st_size > 0)
    276             beg_range = sbuf.st_size;
    277         else
    278             do_continue = 0;
     215    /* Impossible?
     216    if ((opt & WGET_OPT_CONTINUE) && !fname_out)
     217        bb_error_msg_and_die("cannot specify continue (-c) without a filename (-O)"); */
     218
     219    /* Determine where to start transfer */
     220    if (LONE_DASH(fname_out)) {
     221        output_fd = 1;
     222        opt &= ~WGET_OPT_CONTINUE;
     223    }
     224    if (opt & WGET_OPT_CONTINUE) {
     225        output_fd = open(fname_out, O_WRONLY);
     226        if (output_fd >= 0) {
     227            beg_range = xlseek(output_fd, 0, SEEK_END);
     228        }
     229        /* File doesn't exist. We do not create file here yet.
     230           We are not sure it exists on remove side */
    279231    }
    280232
     
    282234     * sites (i.e. ftp.us.debian.org) use round-robin DNS
    283235     * and we want to connect to only one IP... */
    284     bb_lookup_host(&s_in, server.host);
    285     s_in.sin_port = server.port;
    286     if (quiet_flag==FALSE) {
    287         fprintf(stdout, "Connecting to %s[%s]:%d\n",
    288                 server.host, inet_ntoa(s_in.sin_addr), ntohs(server.port));
     236    lsa = xhost2sockaddr(server.host, server.port);
     237    if (!(opt & WGET_OPT_QUIET)) {
     238        fprintf(stderr, "Connecting to %s (%s)\n", server.host,
     239                xmalloc_sockaddr2dotted(&lsa->sa));
     240        /* We leak result of xmalloc_sockaddr2dotted */
    289241    }
    290242
     
    296248            got_clen = chunked = 0;
    297249
    298             if (! --try)
    299                 close_delete_and_die("too many redirections");
    300 
    301             /*
    302              * Open socket to http server
    303              */
     250            if (!--try)
     251                bb_error_msg_and_die("too many redirections");
     252
     253            /* Open socket to http server */
    304254            if (sfp) fclose(sfp);
    305             sfp = open_socket(&s_in);
    306 
    307             /*
    308              * Send HTTP request.
    309              */
     255            sfp = open_socket(lsa);
     256
     257            /* Send HTTP request.  */
    310258            if (use_proxy) {
    311                 const char *format = "GET %stp://%s:%d/%s HTTP/1.1\r\n";
    312 #ifdef CONFIG_FEATURE_WGET_IP6_LITERAL
    313                 if (strchr(target.host, ':'))
    314                     format = "GET %stp://[%s]:%d/%s HTTP/1.1\r\n";
    315 #endif
    316                 fprintf(sfp, format,
     259                fprintf(sfp, "GET %stp://%s/%s HTTP/1.1\r\n",
    317260                    target.is_ftp ? "f" : "ht", target.host,
    318                     ntohs(target.port), target.path);
     261                    target.path);
    319262            } else {
    320263                fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path);
    321264            }
    322265
    323             fprintf(sfp, "Host: %s\r\nUser-Agent: Wget\r\n", target.host);
    324 
    325 #ifdef CONFIG_FEATURE_WGET_AUTHENTICATION
     266            fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n",
     267                target.host, user_agent);
     268
     269#if ENABLE_FEATURE_WGET_AUTHENTICATION
    326270            if (target.user) {
    327                 fprintf(sfp, "Authorization: Basic %s\r\n",
    328                     base64enc((unsigned char*)target.user, buf, sizeof(buf)));
     271                fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6,
     272                    base64enc_512(buf, target.user));
    329273            }
    330274            if (use_proxy && server.user) {
    331275                fprintf(sfp, "Proxy-Authorization: Basic %s\r\n",
    332                     base64enc((unsigned char*)server.user, buf, sizeof(buf)));
     276                    base64enc_512(buf, server.user));
    333277            }
    334278#endif
    335279
    336             if (do_continue)
    337                 fprintf(sfp, "Range: bytes=%ld-\r\n", beg_range);
    338             if(extra_headers_left < sizeof(extra_headers))
    339                 fputs(extra_headers,sfp);
    340             fprintf(sfp,"Connection: close\r\n\r\n");
     280            if (beg_range)
     281                fprintf(sfp, "Range: bytes=%"OFF_FMT"d-\r\n", beg_range);
     282#if ENABLE_FEATURE_WGET_LONG_OPTIONS
     283            if (extra_headers)
     284                fputs(extra_headers, sfp);
     285#endif
     286            fprintf(sfp, "Connection: close\r\n\r\n");
    341287
    342288            /*
    343289            * Retrieve HTTP response line and check for "200" status code.
    344290            */
    345 read_response:
     291 read_response:
    346292            if (fgets(buf, sizeof(buf), sfp) == NULL)
    347                 close_delete_and_die("no response from server");
    348 
    349             for (s = buf ; *s != '\0' && !isspace(*s) ; ++s)
    350                 ;
    351             for ( ; isspace(*s) ; ++s)
    352                 ;
    353             switch (status = atoi(s)) {
    354                 case 0:
    355                 case 100:
    356                     while (gethdr(buf, sizeof(buf), sfp, &n) != NULL);
    357                     goto read_response;
    358                 case 200:
    359                     if (do_continue && output != stdout)
    360                         output = freopen(fname_out, "w", output);
    361                     do_continue = 0;
     293                bb_error_msg_and_die("no response from server");
     294
     295            str = buf;
     296            str = skip_non_whitespace(str);
     297            str = skip_whitespace(str);
     298            // FIXME: no error check
     299            // xatou wouldn't work: "200 OK"
     300            status = atoi(str);
     301            switch (status) {
     302            case 0:
     303            case 100:
     304                while (gethdr(buf, sizeof(buf), sfp, &n) != NULL)
     305                    /* eat all remaining headers */;
     306                goto read_response;
     307            case 200:
     308                break;
     309            case 300:   /* redirection */
     310            case 301:
     311            case 302:
     312            case 303:
     313                break;
     314            case 206:
     315                if (beg_range)
    362316                    break;
    363                 case 300:   /* redirection */
    364                 case 301:
    365                 case 302:
    366                 case 303:
    367                     break;
    368                 case 206:
    369                     if (do_continue)
    370                         break;
    371                     /*FALLTHRU*/
    372                 default:
    373                     chomp(buf);
    374                     close_delete_and_die("server returned error %d: %s", atoi(s), buf);
     317                /*FALLTHRU*/
     318            default:
     319                /* Show first line only and kill any ESC tricks */
     320                buf[strcspn(buf, "\n\r\x1b")] = '\0';
     321                bb_error_msg_and_die("server returned error: %s", buf);
    375322            }
    376323
     
    378325             * Retrieve HTTP headers.
    379326             */
    380             while ((s = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) {
    381                 if (strcasecmp(buf, "content-length") == 0) {
    382                     unsigned long value;
    383                     if (safe_strtoul(s, &value)) {
    384                         close_delete_and_die("content-length %s is garbage", s);
     327            while ((str = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) {
     328                /* gethdr did already convert the "FOO:" string to lowercase */
     329                smalluint key = index_in_strings(keywords, *&buf) + 1;
     330                if (key == KEY_content_length) {
     331                    content_len = BB_STRTOOFF(str, NULL, 10);
     332                    if (errno || content_len < 0) {
     333                        bb_error_msg_and_die("content-length %s is garbage", str);
    385334                    }
    386                     filesize = value;
    387335                    got_clen = 1;
    388336                    continue;
    389337                }
    390                 if (strcasecmp(buf, "transfer-encoding") == 0) {
    391                     if (strcasecmp(s, "chunked") == 0) {
    392                         chunked = got_clen = 1;
    393                     } else {
    394                         close_delete_and_die("server wants to do %s transfer encoding", s);
    395                     }
     338                if (key == KEY_transfer_encoding) {
     339                    if (index_in_strings(keywords, str_tolower(str)) + 1 != KEY_chunked)
     340                        bb_error_msg_and_die("server wants to do %s transfer encoding", str);
     341                    chunked = got_clen = 1;
    396342                }
    397                 if (strcasecmp(buf, "location") == 0) {
    398                     if (s[0] == '/')
    399                         target.path = bb_xstrdup(s+1);
     343                if (key == KEY_location) {
     344                    if (str[0] == '/')
     345                        /* free(target.allocated); */
     346                        target.path = /* target.allocated = */ xstrdup(str+1);
    400347                    else {
    401                         parse_url(bb_xstrdup(s), &target);
     348                        parse_url(str, &target);
    402349                        if (use_proxy == 0) {
    403350                            server.host = target.host;
    404351                            server.port = target.port;
    405352                        }
    406                         bb_lookup_host(&s_in, server.host);
    407                         s_in.sin_port = server.port;
     353                        free(lsa);
     354                        lsa = xhost2sockaddr(server.host, server.port);
    408355                        break;
    409356                    }
    410357                }
    411358            }
    412         } while(status >= 300);
     359        } while (status >= 300);
    413360
    414361        dfp = sfp;
    415     }
    416     else
    417     {
     362
     363    } else {
     364
    418365        /*
    419366         *  FTP session
    420367         */
    421         if (! target.user)
    422             target.user = bb_xstrdup("anonymous:busybox@");
    423 
    424         sfp = open_socket(&s_in);
     368        if (!target.user)
     369            target.user = xstrdup("anonymous:busybox@");
     370
     371        sfp = open_socket(lsa);
    425372        if (ftpcmd(NULL, NULL, sfp, buf) != 220)
    426             close_delete_and_die("%s", buf+4);
     373            bb_error_msg_and_die("%s", buf+4);
    427374
    428375        /*
     
    430377         * trying to log in
    431378         */
    432         s = strchr(target.user, ':');
    433         if (s)
    434             *(s++) = '\0';
    435         switch(ftpcmd("USER ", target.user, sfp, buf)) {
    436             case 230:
     379        str = strchr(target.user, ':');
     380        if (str)
     381            *(str++) = '\0';
     382        switch (ftpcmd("USER ", target.user, sfp, buf)) {
     383        case 230:
     384            break;
     385        case 331:
     386            if (ftpcmd("PASS ", str, sfp, buf) == 230)
    437387                break;
    438             case 331:
    439                 if (ftpcmd("PASS ", s, sfp, buf) == 230)
    440                     break;
    441                 /* FALLTHRU (failed login) */
    442             default:
    443                 close_delete_and_die("ftp login: %s", buf+4);
     388            /* FALLTHRU (failed login) */
     389        default:
     390            bb_error_msg_and_die("ftp login: %s", buf+4);
    444391        }
    445392
     
    450397         */
    451398        if (ftpcmd("SIZE ", target.path, sfp, buf) == 213) {
    452             unsigned long value;
    453             if (safe_strtoul(buf+4, &value)) {
    454                 close_delete_and_die("SIZE value is garbage");
     399            content_len = BB_STRTOOFF(buf+4, NULL, 10);
     400            if (errno || content_len < 0) {
     401                bb_error_msg_and_die("SIZE value is garbage");
    455402            }
    456             filesize = value;
    457403            got_clen = 1;
    458404        }
     
    461407         * Entering passive mode
    462408         */
    463         if (ftpcmd("PASV", NULL, sfp, buf) !=  227)
    464             close_delete_and_die("PASV: %s", buf+4);
    465         s = strrchr(buf, ',');
    466         *s = 0;
    467         port = atoi(s+1);
    468         s = strrchr(buf, ',');
    469         port += atoi(s+1) * 256;
    470         s_in.sin_port = htons(port);
    471         dfp = open_socket(&s_in);
    472 
    473         if (do_continue) {
    474             sprintf(buf, "REST %ld", beg_range);
    475             if (ftpcmd(buf, NULL, sfp, buf) != 350) {
    476                 if (output != stdout)
    477                     output = freopen(fname_out, "w", output);
    478                 do_continue = 0;
    479             } else
    480                 filesize -= beg_range;
     409        if (ftpcmd("PASV", NULL, sfp, buf) != 227) {
     410 pasv_error:
     411            bb_error_msg_and_die("bad response to %s: %s", "PASV", buf);
     412        }
     413        // Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage]
     414        // Server's IP is N1.N2.N3.N4 (we ignore it)
     415        // Server's port for data connection is P1*256+P2
     416        str = strrchr(buf, ')');
     417        if (str) str[0] = '\0';
     418        str = strrchr(buf, ',');
     419        if (!str) goto pasv_error;
     420        port = xatou_range(str+1, 0, 255);
     421        *str = '\0';
     422        str = strrchr(buf, ',');
     423        if (!str) goto pasv_error;
     424        port += xatou_range(str+1, 0, 255) * 256;
     425        set_nport(lsa, htons(port));
     426        dfp = open_socket(lsa);
     427
     428        if (beg_range) {
     429            sprintf(buf, "REST %"OFF_FMT"d", beg_range);
     430            if (ftpcmd(buf, NULL, sfp, buf) == 350)
     431                content_len -= beg_range;
    481432        }
    482433
    483434        if (ftpcmd("RETR ", target.path, sfp, buf) > 150)
    484             close_delete_and_die("RETR: %s", buf+4);
    485     }
    486 
     435            bb_error_msg_and_die("bad response to RETR: %s", buf);
     436    }
     437    if (opt & WGET_OPT_SPIDER) {
     438        if (ENABLE_FEATURE_CLEAN_UP)
     439            fclose(sfp);
     440        goto done;
     441    }
    487442
    488443    /*
     
    491446    if (chunked) {
    492447        fgets(buf, sizeof(buf), dfp);
    493         filesize = strtol(buf, (char **) NULL, 16);
    494     }
    495 
    496     if (quiet_flag==FALSE)
     448        content_len = STRTOOFF(buf, NULL, 16);
     449        /* FIXME: error check?? */
     450    }
     451
     452    /* Do it before progressmeter (want to have nice error message) */
     453    if (output_fd < 0)
     454        output_fd = xopen(fname_out,
     455            O_WRONLY|O_CREAT|O_EXCL|O_TRUNC);
     456
     457    if (!(opt & WGET_OPT_QUIET))
    497458        progressmeter(-1);
    498459
    499460    do {
    500         while ((filesize > 0 || !got_clen) && (n = safe_fread(buf, 1, ((chunked || got_clen) && (filesize < sizeof(buf)) ? filesize : sizeof(buf)), dfp)) > 0) {
    501             if (safe_fwrite(buf, 1, n, output) != n) {
     461        while (content_len > 0 || !got_clen) {
     462            unsigned rdsz = sizeof(buf);
     463            if (content_len < sizeof(buf) && (chunked || got_clen))
     464                rdsz = (unsigned)content_len;
     465            n = safe_fread(buf, rdsz, dfp);
     466            if (n <= 0)
     467                break;
     468            if (full_write(output_fd, buf, n) != n) {
    502469                bb_perror_msg_and_die(bb_msg_write_error);
    503470            }
    504 #ifdef CONFIG_FEATURE_WGET_STATUSBAR
     471#if ENABLE_FEATURE_WGET_STATUSBAR
    505472            transferred += n;
    506473#endif
    507474            if (got_clen) {
    508                 filesize -= n;
     475                content_len -= n;
    509476            }
    510477        }
     
    513480            safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */
    514481            safe_fgets(buf, sizeof(buf), dfp);
    515             filesize = strtol(buf, (char **) NULL, 16);
    516             if (filesize==0) {
     482            content_len = STRTOOFF(buf, NULL, 16);
     483            /* FIXME: error check? */
     484            if (content_len == 0) {
    517485                chunked = 0; /* all done! */
    518486            }
     
    524492    } while (chunked);
    525493
    526     if (quiet_flag==FALSE)
     494    if (!(opt & WGET_OPT_QUIET))
    527495        progressmeter(1);
    528496
     
    533501        ftpcmd("QUIT", NULL, sfp, buf);
    534502    }
     503done:
    535504    exit(EXIT_SUCCESS);
    536505}
    537506
    538507
    539 void parse_url(char *url, struct host_info *h)
    540 {
    541     char *cp, *sp, *up, *pp;
     508static void parse_url(char *src_url, struct host_info *h)
     509{
     510    char *url, *p, *sp;
     511
     512    /* h->allocated = */ url = xstrdup(src_url);
    542513
    543514    if (strncmp(url, "http://", 7) == 0) {
     
    546517        h->is_ftp = 0;
    547518    } else if (strncmp(url, "ftp://", 6) == 0) {
    548         h->port = bb_lookup_port("ftp", "tfp", 21);
     519        h->port = bb_lookup_port("ftp", "tcp", 21);
    549520        h->host = url + 6;
    550521        h->is_ftp = 1;
     
    552523        bb_error_msg_and_die("not an http or ftp url: %s", url);
    553524
     525    // FYI:
     526    // "Real" wget 'http://busybox.net?var=a/b' sends this request:
     527    //   'GET /?var=a/b HTTP 1.0'
     528    //   and saves 'index.html?var=a%2Fb' (we save 'b')
     529    // wget 'http://busybox.net?login=john@doe':
     530    //   request: 'GET /?login=john@doe HTTP/1.0'
     531    //   saves: 'index.html?login=john@doe' (we save '?login=john@doe')
     532    // wget 'http://busybox.net#test/test':
     533    //   request: 'GET / HTTP/1.0'
     534    //   saves: 'index.html' (we save 'test')
     535    //
     536    // We also don't add unique .N suffix if file exists...
    554537    sp = strchr(h->host, '/');
    555     if (sp) {
    556         *sp++ = '\0';
     538    p = strchr(h->host, '?'); if (!sp || (p && sp > p)) sp = p;
     539    p = strchr(h->host, '#'); if (!sp || (p && sp > p)) sp = p;
     540    if (!sp) {
     541        /* must be writable because of bb_get_last_path_component() */
     542        static char nullstr[] ALIGN1 = "";
     543        h->path = nullstr;
     544    } else if (*sp == '/') {
     545        *sp = '\0';
     546        h->path = sp + 1;
     547    } else { // '#' or '?'
     548        // http://busybox.net?login=john@doe is a valid URL
     549        // memmove converts to:
     550        // http:/busybox.nett?login=john@doe...
     551        memmove(h->host-1, h->host, sp - h->host);
     552        h->host--;
     553        sp[-1] = '\0';
    557554        h->path = sp;
    558     } else
    559         h->path = bb_xstrdup("");
    560 
    561     up = strrchr(h->host, '@');
    562     if (up != NULL) {
     555    }
     556
     557    sp = strrchr(h->host, '@');
     558    h->user = NULL;
     559    if (sp != NULL) {
    563560        h->user = h->host;
    564         *up++ = '\0';
    565         h->host = up;
    566     } else
    567         h->user = NULL;
    568 
    569     pp = h->host;
    570 
    571 #ifdef CONFIG_FEATURE_WGET_IP6_LITERAL
    572     if (h->host[0] == '[') {
    573         char *ep;
    574 
    575         ep = h->host + 1;
    576         while (*ep == ':' || isxdigit (*ep))
    577             ep++;
    578         if (*ep == ']') {
    579             h->host++;
    580             *ep = '\0';
    581             pp = ep + 1;
    582         }
    583     }
    584 #endif
    585 
    586     cp = strchr(pp, ':');
    587     if (cp != NULL) {
    588         *cp++ = '\0';
    589         h->port = htons(atoi(cp));
    590     }
    591 }
    592 
    593 
    594 FILE *open_socket(struct sockaddr_in *s_in)
     561        *sp = '\0';
     562        h->host = sp + 1;
     563    }
     564
     565    sp = h->host;
     566}
     567
     568
     569static FILE *open_socket(len_and_sockaddr *lsa)
    595570{
    596571    FILE *fp;
    597572
    598     fp = fdopen(xconnect(s_in), "r+");
     573    /* glibc 2.4 seems to try seeking on it - ??! */
     574    /* hopefully it understands what ESPIPE means... */
     575    fp = fdopen(xconnect_stream(lsa), "r+");
    599576    if (fp == NULL)
    600         bb_perror_msg_and_die("fdopen()");
     577        bb_perror_msg_and_die("fdopen");
    601578
    602579    return fp;
     
    604581
    605582
    606 char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc)
     583static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc)
    607584{
    608585    char *s, *hdrval;
     
    616593
    617594    /* see if we are at the end of the headers */
    618     for (s = buf ; *s == '\r' ; ++s)
     595    for (s = buf; *s == '\r'; ++s)
    619596        ;
    620597    if (s[0] == '\n')
     
    622599
    623600    /* convert the header name to lower case */
    624     for (s = buf ; isalnum(*s) || *s == '-' ; ++s)
     601    for (s = buf; isalnum(*s) || *s == '-'; ++s)
    625602        *s = tolower(*s);
    626603
     
    630607
    631608    /* locate the start of the header value */
    632     for (*s++ = '\0' ; *s == ' ' || *s == '\t' ; ++s)
     609    for (*s++ = '\0'; *s == ' ' || *s == '\t'; ++s)
    633610        ;
    634611    hdrval = s;
     
    651628}
    652629
    653 static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf)
    654 {
     630static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf)
     631{
     632    int result;
    655633    if (s1) {
    656         if (!s2) s2="";
     634        if (!s2) s2 = "";
    657635        fprintf(fp, "%s%s\r\n", s1, s2);
    658636        fflush(fp);
     
    663641
    664642        if (fgets(buf, 510, fp) == NULL) {
    665             bb_perror_msg_and_die("fgets()");
     643            bb_perror_msg_and_die("error getting response");
    666644        }
    667645        buf_ptr = strstr(buf, "\r\n");
     
    669647            *buf_ptr = '\0';
    670648        }
    671     } while (! isdigit(buf[0]) || buf[3] != ' ');
    672 
    673     return atoi(buf);
    674 }
    675 
    676 #ifdef CONFIG_FEATURE_WGET_STATUSBAR
     649    } while (!isdigit(buf[0]) || buf[3] != ' ');
     650
     651    buf[3] = '\0';
     652    result = xatoi_u(buf);
     653    buf[3] = ' ';
     654    return result;
     655}
     656
     657#if ENABLE_FEATURE_WGET_STATUSBAR
    677658/* Stuff below is from BSD rcp util.c, as added to openshh.
    678659 * Original copyright notice is retained at the end of this file.
    679  *
    680660 */
    681 
    682 
    683661static int
    684662getttywidth(void)
    685663{
    686     int width=0;
     664    int width;
    687665    get_terminal_width_height(0, &width, NULL);
    688     return (width);
     666    return width;
    689667}
    690668
     
    698676}
    699677
    700 static void
    701 alarmtimer(int wait)
     678static void alarmtimer(int iwait)
    702679{
    703680    struct itimerval itv;
    704681
    705     itv.it_value.tv_sec = wait;
     682    itv.it_value.tv_sec = iwait;
    706683    itv.it_value.tv_usec = 0;
    707684    itv.it_interval = itv.it_value;
     
    709686}
    710687
    711 
    712688static void
    713689progressmeter(int flag)
    714690{
    715     static struct timeval lastupdate;
     691    static unsigned lastupdate_sec;
     692    static unsigned start_sec;
    716693    static off_t lastsize, totalsize;
    717694
    718     struct timeval now, td, wait;
    719695    off_t abbrevsize;
    720     int elapsed, ratio, barlength, i;
    721     char buf[256];
    722 
    723     if (flag == -1) {
    724         (void) gettimeofday(&start, (struct timezone *) 0);
    725         lastupdate = start;
     696    unsigned since_last_update, elapsed;
     697    unsigned ratio;
     698    int barlength, i;
     699
     700    if (flag == -1) { /* first call to progressmeter */
     701        start_sec = monotonic_sec();
     702        lastupdate_sec = start_sec;
    726703        lastsize = 0;
    727         totalsize = filesize; /* as filesize changes.. */
    728     }
    729 
    730     (void) gettimeofday(&now, (struct timezone *) 0);
     704        totalsize = content_len + beg_range; /* as content_len changes.. */
     705    }
     706
    731707    ratio = 100;
    732708    if (totalsize != 0 && !chunked) {
    733         ratio = (int) (100 * transferred / totalsize);
    734         ratio = MIN(ratio, 100);
     709        /* long long helps to have it working even if !LFS */
     710        ratio = (unsigned) (100ULL * (transferred+beg_range) / totalsize);
     711        if (ratio > 100) ratio = 100;
    735712    }
    736713
    737714    fprintf(stderr, "\r%-20.20s%4d%% ", curfile, ratio);
    738715
    739     barlength = getttywidth() - 51;
    740     if (barlength > 0 && barlength < sizeof(buf)) {
     716    barlength = getttywidth() - 49;
     717    if (barlength > 0) {
     718        /* god bless gcc for variable arrays :) */
    741719        i = barlength * ratio / 100;
    742         memset(buf, '*', i);
    743         memset(buf + i, ' ', barlength - i);
    744         buf[barlength] = '\0';
    745         fprintf(stderr, "|%s|", buf);
     720        {
     721            char buf[i+1];
     722            memset(buf, '*', i);
     723            buf[i] = '\0';
     724            fprintf(stderr, "|%s%*s|", buf, barlength - i, "");
     725        }
    746726    }
    747727    i = 0;
    748     abbrevsize = transferred;
     728    abbrevsize = transferred + beg_range;
    749729    while (abbrevsize >= 100000) {
    750730        i++;
    751731        abbrevsize >>= 10;
    752732    }
    753     /* See http://en.wikipedia.org/wiki/Tera */
    754     fprintf(stderr, "%6d %c%c ", (int)abbrevsize, " KMGTPEZY"[i], i?'B':' ');
    755 
    756     timersub(&now, &lastupdate, &wait);
     733    /* see http://en.wikipedia.org/wiki/Tera */
     734    fprintf(stderr, "%6d%c ", (int)abbrevsize, " kMGTPEZY"[i]);
     735
     736// Nuts! Ain't it easier to update progress meter ONLY when we transferred++?
     737// FIXME: get rid of alarmtimer + updateprogressmeter mess
     738
     739    elapsed = monotonic_sec();
     740    since_last_update = elapsed - lastupdate_sec;
    757741    if (transferred > lastsize) {
    758         lastupdate = now;
     742        lastupdate_sec = elapsed;
    759743        lastsize = transferred;
    760         if (wait.tv_sec >= STALLTIME)
    761             timeradd(&start, &wait, &start);
    762         wait.tv_sec = 0;
    763     }
    764     timersub(&now, &start, &td);
    765     elapsed = td.tv_sec;
    766 
    767     if (wait.tv_sec >= STALLTIME) {
     744        if (since_last_update >= STALLTIME) {
     745            /* We "cut off" these seconds from elapsed time
     746             * by adjusting start time */
     747            start_sec += since_last_update;
     748        }
     749        since_last_update = 0; /* we are un-stalled now */
     750    }
     751    elapsed -= start_sec; /* now it's "elapsed since start" */
     752
     753    if (since_last_update >= STALLTIME) {
    768754        fprintf(stderr, " - stalled -");
    769     } else if (transferred <= 0 || elapsed <= 0 || transferred > totalsize || chunked) {
    770         fprintf(stderr, "--:--:-- ETA");
    771755    } else {
    772         /* totalsize / (transferred/elapsed) - elapsed: */
    773         int eta = (int) (totalsize*elapsed/transferred - elapsed);
    774         i = eta % 3600;
    775         fprintf(stderr, "%02d:%02d:%02d ETA", eta / 3600, i / 60, i % 60);
    776     }
    777 
    778     if (flag == -1) {
     756        off_t to_download = totalsize - beg_range;
     757        if (transferred <= 0 || (int)elapsed <= 0 || transferred > to_download || chunked) {
     758            fprintf(stderr, "--:--:-- ETA");
     759        } else {
     760            /* to_download / (transferred/elapsed) - elapsed: */
     761            int eta = (int) ((unsigned long long)to_download*elapsed/transferred - elapsed);
     762            /* (long long helps to have working ETA even if !LFS) */
     763            i = eta % 3600;
     764            fprintf(stderr, "%02d:%02d:%02d ETA", eta / 3600, i / 60, i % 60);
     765        }
     766    }
     767
     768    if (flag == -1) { /* first call to progressmeter */
    779769        struct sigaction sa;
    780770        sa.sa_handler = updateprogressmeter;
     
    783773        sigaction(SIGALRM, &sa, NULL);
    784774        alarmtimer(1);
    785     } else if (flag == 1) {
     775    } else if (flag == 1) { /* last call to progressmeter */
    786776        alarmtimer(0);
    787777        transferred = 0;
     
    789779    }
    790780}
    791 #endif
     781#endif /* FEATURE_WGET_STATUSBAR */
    792782
    793783/* Original copyright notice which applies to the CONFIG_FEATURE_WGET_STATUSBAR stuff,
     
    826816 * SUCH DAMAGE.
    827817 *
    828  *  $Id: wget.c,v 1.75 2004/10/08 08:27:40 andersen Exp $
    829818 */
Note: See TracChangeset for help on using the changeset viewer.