Author: des
Date: Tue Oct  9 10:49:19 2018
New Revision: 339250
URL: https://svnweb.freebsd.org/changeset/base/339250

Log:
  MFH (r314778): use reallocarray(3) for extra bounds checks
  MFH (r333306): fix typo in man page
  MFH (r333571, r333572): preserve if-modified-since across redirects
  MFH (r334317): simplify the DEBUG macro
  MFH (r334319): style bug roundup
  MFH (r334326): fix netrc file location logic, improve netrcfd handling
  MFH (r338572): fix end-of-transfer statistics, improve no-tty display
  
  PR:           202424, 224426, 228017

Modified:
  stable/11/lib/libfetch/common.c
  stable/11/lib/libfetch/common.h
  stable/11/lib/libfetch/fetch.c
  stable/11/lib/libfetch/ftp.c
  stable/11/lib/libfetch/http.c
  stable/11/usr.bin/fetch/fetch.1
  stable/11/usr.bin/fetch/fetch.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/lib/libfetch/common.c
==============================================================================
--- stable/11/lib/libfetch/common.c     Tue Oct  9 07:22:14 2018        
(r339249)
+++ stable/11/lib/libfetch/common.c     Tue Oct  9 10:49:19 2018        
(r339250)
@@ -345,7 +345,7 @@ fetch_connect(const char *host, int port, int af, int 
        conn_t *conn = NULL;
        int err = 0, sd = -1;
 
-       DEBUG(fprintf(stderr, "---> %s:%d\n", host, port));
+       DEBUGF("---> %s:%d\n", host, port);
 
        /* resolve server address */
        if (verbose)
@@ -1156,7 +1156,7 @@ fetch_getln(conn_t *conn)
        } while (c != '\n');
 
        conn->buf[conn->buflen] = '\0';
-       DEBUG(fprintf(stderr, "<<< %s", conn->buf));
+       DEBUGF("<<< %s", conn->buf);
        return (0);
 }
 
@@ -1261,7 +1261,7 @@ fetch_putln(conn_t *conn, const char *str, size_t len)
        struct iovec iov[2];
        int ret;
 
-       DEBUG(fprintf(stderr, ">>> %s\n", str));
+       DEBUGF(">>> %s\n", str);
        iov[0].iov_base = __DECONST(char *, str);
        iov[0].iov_len = len;
        iov[1].iov_base = __DECONST(char *, ENDL);
@@ -1323,7 +1323,7 @@ fetch_add_entry(struct url_ent **p, int *size, int *le
        }
 
        if (*len >= *size - 1) {
-               tmp = realloc(*p, (*size * 2 + 1) * sizeof(**p));
+               tmp = reallocarray(*p, *size * 2 + 1, sizeof(**p));
                if (tmp == NULL) {
                        errno = ENOMEM;
                        fetch_syserr();
@@ -1359,19 +1359,20 @@ fetch_read_word(FILE *f)
 static int
 fetch_netrc_open(void)
 {
-       const char *p;
+       struct passwd *pwd;
        char fn[PATH_MAX];
+       const char *p;
+       int fd, serrno;
 
        if ((p = getenv("NETRC")) != NULL) {
+               DEBUGF("NETRC=%s\n", p);
                if (snprintf(fn, sizeof(fn), "%s", p) >= (int)sizeof(fn)) {
                        fetch_info("$NETRC specifies a file name "
                            "longer than PATH_MAX");
                        return (-1);
                }
        } else {
-               if ((p = getenv("HOME")) != NULL) {
-                       struct passwd *pwd;
-
+               if ((p = getenv("HOME")) == NULL) {
                        if ((pwd = getpwuid(getuid())) == NULL ||
                            (p = pwd->pw_dir) == NULL)
                                return (-1);
@@ -1380,7 +1381,12 @@ fetch_netrc_open(void)
                        return (-1);
        }
 
-       return (open(fn, O_RDONLY));
+       if ((fd = open(fn, O_RDONLY)) < 0) {
+               serrno = errno;
+               DEBUGF("%s: %s\n", fn, strerror(serrno));
+               errno = serrno;
+       }
+       return (fd);
 }
 
 /*
@@ -1390,24 +1396,32 @@ int
 fetch_netrc_auth(struct url *url)
 {
        const char *word;
+       int serrno;
        FILE *f;
 
-       if (url->netrcfd == -2)
+       if (url->netrcfd < 0)
                url->netrcfd = fetch_netrc_open();
        if (url->netrcfd < 0)
                return (-1);
-       if ((f = fdopen(url->netrcfd, "r")) == NULL)
+       if ((f = fdopen(url->netrcfd, "r")) == NULL) {
+               serrno = errno;
+               DEBUGF("fdopen(netrcfd): %s", strerror(errno));
+               close(url->netrcfd);
+               url->netrcfd = -1;
+               errno = serrno;
                return (-1);
+       }
        rewind(f);
+       DEBUGF("searching netrc for %s\n", url->host);
        while ((word = fetch_read_word(f)) != NULL) {
                if (strcmp(word, "default") == 0) {
-                       DEBUG(fetch_info("Using default .netrc settings"));
+                       DEBUGF("using default netrc settings\n");
                        break;
                }
                if (strcmp(word, "machine") == 0 &&
                    (word = fetch_read_word(f)) != NULL &&
                    strcasecmp(word, url->host) == 0) {
-                       DEBUG(fetch_info("Using .netrc settings for %s", word));
+                       DEBUGF("using netrc settings for %s\n", word);
                        break;
                }
        }
@@ -1439,9 +1453,13 @@ fetch_netrc_auth(struct url *url)
                }
        }
        fclose(f);
+       url->netrcfd = -1;
        return (0);
- ferr:
+ferr:
+       serrno = errno;
        fclose(f);
+       url->netrcfd = -1;
+       errno = serrno;
        return (-1);
 }
 

Modified: stable/11/lib/libfetch/common.h
==============================================================================
--- stable/11/lib/libfetch/common.h     Tue Oct  9 07:22:14 2018        
(r339249)
+++ stable/11/lib/libfetch/common.h     Tue Oct  9 10:49:19 2018        
(r339250)
@@ -102,9 +102,16 @@ int                 fetch_no_proxy_match(const char *);
 #define url_seterr(n)   fetch_seterr(url_errlist, n)
 
 #ifndef NDEBUG
-#define DEBUG(x) do { if (fetchDebug) { x; } } while (0)
+#define DEBUGF(...)                                                    \
+       do {                                                            \
+               if (fetchDebug)                                         \
+                       fprintf(stderr, __VA_ARGS__);                   \
+       } while (0)
 #else
-#define DEBUG(x) do { } while (0)
+#define DEBUGF(...)                                                    \
+       do {                                                            \
+               /* nothing */                                           \
+       } while (0)
 #endif
 
 /*

Modified: stable/11/lib/libfetch/fetch.c
==============================================================================
--- stable/11/lib/libfetch/fetch.c      Tue Oct  9 07:22:14 2018        
(r339249)
+++ stable/11/lib/libfetch/fetch.c      Tue Oct  9 10:49:19 2018        
(r339250)
@@ -270,6 +270,7 @@ fetchMakeURL(const char *scheme, const char *host, int
                fetch_syserr();
                return (NULL);
        }
+       u->netrcfd = -1;
 
        if ((u->doc = strdup(doc ? doc : "/")) == NULL) {
                fetch_syserr();
@@ -284,7 +285,6 @@ fetchMakeURL(const char *scheme, const char *host, int
        seturl(pwd);
 #undef seturl
        u->port = port;
-       u->netrcfd = -2;
 
        return (u);
 }
@@ -350,7 +350,7 @@ fetchParseURL(const char *URL)
                fetch_syserr();
                return (NULL);
        }
-       u->netrcfd = -2;
+       u->netrcfd = -1;
 
        /* scheme name */
        if ((p = strstr(URL, ":/"))) {
@@ -442,15 +442,14 @@ nohost:
                goto ouch;
        }
 
-       DEBUG(fprintf(stderr,
-                 "scheme:   \"%s\"\n"
-                 "user:     \"%s\"\n"
-                 "password: \"%s\"\n"
-                 "host:     \"%s\"\n"
-                 "port:     \"%d\"\n"
-                 "document: \"%s\"\n",
-                 u->scheme, u->user, u->pwd,
-                 u->host, u->port, u->doc));
+       DEBUGF("scheme:   \"%s\"\n"
+           "user:     \"%s\"\n"
+           "password: \"%s\"\n"
+           "host:     \"%s\"\n"
+           "port:     \"%d\"\n"
+           "document: \"%s\"\n",
+           u->scheme, u->user, u->pwd,
+           u->host, u->port, u->doc);
 
        return (u);
 

Modified: stable/11/lib/libfetch/ftp.c
==============================================================================
--- stable/11/lib/libfetch/ftp.c        Tue Oct  9 07:22:14 2018        
(r339249)
+++ stable/11/lib/libfetch/ftp.c        Tue Oct  9 10:49:19 2018        
(r339250)
@@ -257,7 +257,7 @@ ftp_pwd(conn_t *conn, char *pwd, size_t pwdlen)
                return (FTP_PROTOCOL_ERROR);
        *dst = '\0';
 #if 0
-       DEBUG(fprintf(stderr, "pwd: [%s]\n", pwd));
+       DEBUGF("pwd: [%s]\n", pwd);
 #endif
        return (FTP_OK);
 }
@@ -289,8 +289,8 @@ ftp_cwd(conn_t *conn, const char *file)
                        if (pwd[i] != file[i])
                                break;
 #if 0
-               DEBUG(fprintf(stderr, "have: [%.*s|%s]\n", i, pwd, pwd + i));
-               DEBUG(fprintf(stderr, "want: [%.*s|%s]\n", i, file, file + i));
+               DEBUGF("have: [%.*s|%s]\n", i, pwd, pwd + i);
+               DEBUGF("want: [%.*s|%s]\n", i, file, file + i);
 #endif
                /* Keep going up a dir until we have a matching prefix. */
                if (pwd[i] == '\0' && (file[i - 1] == '/' || file[i] == '/'))
@@ -431,7 +431,7 @@ ftp_stat(conn_t *conn, const char *file, struct url_st
        }
        if (us->size == 0)
                us->size = -1;
-       DEBUG(fprintf(stderr, "size: [%lld]\n", (long long)us->size));
+       DEBUGF("size: [%lld]\n", (long long)us->size);
 
        e = ftp_cmd(conn, "MDTM %.*s", filenamelen, filename);
        if (e != FTP_FILE_STATUS) {
@@ -466,10 +466,9 @@ ftp_stat(conn_t *conn, const char *file, struct url_st
                t = time(NULL);
        us->mtime = t;
        us->atime = t;
-       DEBUG(fprintf(stderr,
-           "last modified: [%04d-%02d-%02d %02d:%02d:%02d]\n",
+       DEBUGF("last modified: [%04d-%02d-%02d %02d:%02d:%02d]\n",
            tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
-           tm.tm_hour, tm.tm_min, tm.tm_sec));
+           tm.tm_hour, tm.tm_min, tm.tm_sec);
        return (0);
 }
 
@@ -583,7 +582,7 @@ ftp_closefn(void *v)
        fetch_close(io->dconn);
        io->dir = -1;
        io->dconn = NULL;
-       DEBUG(fprintf(stderr, "Waiting for final status\n"));
+       DEBUGF("Waiting for final status\n");
        r = ftp_chkerr(io->cconn);
        if (io->cconn == cached_connection && io->cconn->ref == 1)
                cached_connection = NULL;
@@ -913,7 +912,8 @@ ftp_authenticate(conn_t *conn, struct url *url, struct
                fetch_netrc_auth(url);
        user = url->user;
        if (*user == '\0')
-               user = getenv("FTP_LOGIN");
+               if ((user = getenv("FTP_LOGIN")) != NULL)
+                       DEBUGF("FTP_LOGIN=%s\n", user);
        if (user == NULL || *user == '\0')
                user = FTP_ANONYMOUS_USER;
        if (purl && url->port == fetch_default_port(url->scheme))
@@ -927,7 +927,8 @@ ftp_authenticate(conn_t *conn, struct url *url, struct
        if (e == FTP_NEED_PASSWORD) {
                pwd = url->pwd;
                if (*pwd == '\0')
-                       pwd = getenv("FTP_PASSWORD");
+                       if ((pwd = getenv("FTP_PASSWORD")) != NULL)
+                               DEBUGF("FTP_PASSWORD=%s\n", pwd);
                if (pwd == NULL || *pwd == '\0') {
                        if ((logname = getlogin()) == NULL)
                                logname = FTP_ANONYMOUS_USER;

Modified: stable/11/lib/libfetch/http.c
==============================================================================
--- stable/11/lib/libfetch/http.c       Tue Oct  9 07:22:14 2018        
(r339249)
+++ stable/11/lib/libfetch/http.c       Tue Oct  9 10:49:19 2018        
(r339250)
@@ -778,9 +778,9 @@ http_parse_authenticate(const char *cp, http_auth_chal
                        goto out;
                }
                init_http_auth_challenge(cs->challenges[cs->count]);
-               if (!strcasecmp(key, "basic")) {
+               if (strcasecmp(key, "basic") == 0) {
                        cs->challenges[cs->count]->scheme = HTTPAS_BASIC;
-               } else if (!strcasecmp(key, "digest")) {
+               } else if (strcasecmp(key, "digest") == 0) {
                        cs->challenges[cs->count]->scheme = HTTPAS_DIGEST;
                } else {
                        cs->challenges[cs->count]->scheme = HTTPAS_UNKNOWN;
@@ -809,25 +809,27 @@ http_parse_authenticate(const char *cp, http_auth_chal
                        if (lex != HTTPHL_WORD && lex != HTTPHL_STRING)
                                goto out;
 
-                       if (!strcasecmp(key, "realm"))
+                       if (strcasecmp(key, "realm") == 0) {
                                cs->challenges[cs->count]->realm =
-                                       strdup(value);
-                       else if (!strcasecmp(key, "qop"))
+                                   strdup(value);
+                       } else if (strcasecmp(key, "qop") == 0) {
                                cs->challenges[cs->count]->qop =
-                                       strdup(value);
-                       else if (!strcasecmp(key, "nonce"))
+                                   strdup(value);
+                       } else if (strcasecmp(key, "nonce") == 0) {
                                cs->challenges[cs->count]->nonce =
-                                       strdup(value);
-                       else if (!strcasecmp(key, "opaque"))
+                                   strdup(value);
+                       } else if (strcasecmp(key, "opaque") == 0) {
                                cs->challenges[cs->count]->opaque =
-                                       strdup(value);
-                       else if (!strcasecmp(key, "algorithm"))
+                                   strdup(value);
+                       } else if (strcasecmp(key, "algorithm") == 0) {
                                cs->challenges[cs->count]->algo =
-                                       strdup(value);
-                       else if (!strcasecmp(key, "stale"))
+                                   strdup(value);
+                       } else if (strcasecmp(key, "stale") == 0) {
                                cs->challenges[cs->count]->stale =
-                                       strcasecmp(value, "no");
-                       /* Else ignore unknown attributes */
+                                   strcasecmp(value, "no");
+                       } else {
+                               /* ignore unknown attributes */
+                       }
 
                        /* Comma or Next challenge or End */
                        lex = http_header_lex(&cp, key);
@@ -889,10 +891,9 @@ http_parse_mtime(const char *p, time_t *mtime)
        setlocale(LC_TIME, locale);
        if (r == NULL)
                return (-1);
-       DEBUG(fprintf(stderr, "last modified: [%04d-%02d-%02d "
-                 "%02d:%02d:%02d]\n",
-                 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
-                 tm.tm_hour, tm.tm_min, tm.tm_sec));
+       DEBUGF("last modified: [%04d-%02d-%02d %02d:%02d:%02d]\n",
+           tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+           tm.tm_hour, tm.tm_min, tm.tm_sec);
        *mtime = timegm(&tm);
        return (0);
 }
@@ -909,8 +910,7 @@ http_parse_length(const char *p, off_t *length)
                len = len * 10 + (*p - '0');
        if (*p)
                return (-1);
-       DEBUG(fprintf(stderr, "content length: [%lld]\n",
-           (long long)len));
+       DEBUGF("content length: [%lld]\n", (long long)len);
        *length = len;
        return (0);
 }
@@ -944,12 +944,11 @@ http_parse_range(const char *p, off_t *offset, off_t *
        if (*p || len < last - first + 1)
                return (-1);
        if (first == -1) {
-               DEBUG(fprintf(stderr, "content range: [*/%lld]\n",
-                   (long long)len));
+               DEBUGF("content range: [*/%lld]\n", (long long)len);
                *length = 0;
        } else {
-               DEBUG(fprintf(stderr, "content range: [%lld-%lld/%lld]\n",
-                   (long long)first, (long long)last, (long long)len));
+               DEBUGF("content range: [%lld-%lld/%lld]\n",
+                   (long long)first, (long long)last, (long long)len);
                *length = last - first + 1;
        }
        *offset = first;
@@ -1185,9 +1184,10 @@ DigestCalcResponse(
        OUT HASHHEX Response      /* request-digest or response-digest */
        )
 {
-/*     DEBUG(fprintf(stderr,
-                     "Calc: HA1[%s] Nonce[%s] qop[%s] method[%s] URI[%s]\n",
-                     HA1, pszNonce, pszQop, pszMethod, pszDigestUri));*/
+#if 0
+       DEBUGF("Calc: HA1[%s] Nonce[%s] qop[%s] method[%s] URI[%s]\n",
+           HA1, pszNonce, pszQop, pszMethod, pszDigestUri);
+#endif
        MD5_CTX Md5Ctx;
        HASH HA2;
        HASH RespHash;
@@ -1255,15 +1255,15 @@ http_digest_auth(conn_t *conn, const char *hdr, http_a
        char *options = NULL;
 
        if (!c->realm || !c->nonce) {
-               DEBUG(fprintf(stderr, "realm/nonce not set in challenge\n"));
+               DEBUGF("realm/nonce not set in challenge\n");
                return(-1);
        }
        if (!c->algo)
                c->algo = strdup("");
 
        if (asprintf(&options, "%s%s%s%s",
-                    *c->algo? ",algorithm=" : "", c->algo,
-                    c->opaque? ",opaque=" : "", c->opaque?c->opaque:"")== -1)
+           *c->algo? ",algorithm=" : "", c->algo,
+           c->opaque? ",opaque=" : "", c->opaque?c->opaque:"") < 0)
                return (-1);
 
        if (!c->qop) {
@@ -1280,7 +1280,7 @@ http_digest_auth(conn_t *conn, const char *hdr, http_a
        HASHHEX HA1;
        DigestCalcHA1(c->algo, parms->user, c->realm,
                      parms->password, c->nonce, cnonce, HA1);
-       DEBUG(fprintf(stderr, "HA1: [%s]\n", HA1));
+       DEBUGF("HA1: [%s]\n", HA1);
        HASHHEX digest;
        DigestCalcResponse(HA1, c->nonce, noncecount, cnonce, c->qop,
                           "GET", url->doc, "", digest);
@@ -1312,8 +1312,8 @@ http_basic_auth(conn_t *conn, const char *hdr, const c
        char *upw, *auth;
        int r;
 
-       DEBUG(fprintf(stderr, "basic: usr: [%s]\n", usr));
-       DEBUG(fprintf(stderr, "basic: pwd: [%s]\n", pwd));
+       DEBUGF("basic: usr: [%s]\n", usr);
+       DEBUGF("basic: pwd: [%s]\n", pwd);
        if (asprintf(&upw, "%s:%s", usr, pwd) == -1)
                return (-1);
        auth = http_base64(upw);
@@ -1338,7 +1338,7 @@ http_authorize(conn_t *conn, const char *hdr, http_aut
 
        /* If user or pass are null we're not happy */
        if (!parms->user || !parms->password) {
-               DEBUG(fprintf(stderr, "NULL usr or pass\n"));
+               DEBUGF("NULL usr or pass\n");
                return (-1);
        }
 
@@ -1349,10 +1349,9 @@ http_authorize(conn_t *conn, const char *hdr, http_aut
        }
 
        /* Error if "Digest" was specified and there is no Digest challenge */
-       if (!digest && (parms->scheme &&
-                       !strcasecmp(parms->scheme, "digest"))) {
-               DEBUG(fprintf(stderr,
-                             "Digest auth in env, not supported by peer\n"));
+       if (!digest &&
+           (parms->scheme && strcasecmp(parms->scheme, "digest") == 0)) {
+               DEBUGF("Digest auth in env, not supported by peer\n");
                return (-1);
        }
        /*
@@ -1360,7 +1359,8 @@ http_authorize(conn_t *conn, const char *hdr, http_aut
         * challenge, do the basic thing. Don't need a challenge for this,
         * so no need to check basic!=NULL
         */
-       if (!digest || (parms->scheme && !strcasecmp(parms->scheme,"basic")))
+       if (!digest ||
+           (parms->scheme && strcasecmp(parms->scheme, "basic") == 0))
                return (http_basic_auth(conn,hdr,parms->user,parms->password));
 
        /* Else, prefer digest. We just checked that it's not NULL */
@@ -1852,26 +1852,29 @@ http_request_body(struct url *URL, const char *op, str
                                if (new)
                                        free(new);
                                if (verbose)
-                                       fetch_info("%d redirect to %s", 
conn->err, p);
+                                       fetch_info("%d redirect to %s",
+                                           conn->err, p);
                                if (*p == '/')
                                        /* absolute path */
-                                       new = fetchMakeURL(url->scheme, 
url->host, url->port, p,
-                                           url->user, url->pwd);
+                                       new = fetchMakeURL(url->scheme, 
url->host,
+                                           url->port, p, url->user, url->pwd);
                                else
                                        new = fetchParseURL(p);
                                if (new == NULL) {
                                        /* XXX should set an error code */
-                                       DEBUG(fprintf(stderr, "failed to parse 
new URL\n"));
+                                       DEBUGF("failed to parse new URL\n");
                                        goto ouch;
                                }
 
                                /* Only copy credentials if the host matches */
-                               if (!strcmp(new->host, url->host) && 
!*new->user && !*new->pwd) {
+                               if (strcmp(new->host, url->host) == 0 &&
+                                   !*new->user && !*new->pwd) {
                                        strcpy(new->user, url->user);
                                        strcpy(new->pwd, url->pwd);
                                }
                                new->offset = url->offset;
                                new->length = url->length;
+                               new->ims_time = url->ims_time;
                                break;
                        case hdr_transfer_encoding:
                                /* XXX weak test*/
@@ -1906,7 +1909,7 @@ http_request_body(struct url *URL, const char *op, str
                            (conn->err == HTTP_NEED_PROXY_AUTH &&
                             !proxy_challenges.valid)) {
                                /* 401/7 but no www/proxy-authenticate ?? */
-                               DEBUG(fprintf(stderr, "401/7 and no auth 
header\n"));
+                               DEBUGF("%03d without auth header\n", conn->err);
                                goto ouch;
                        }
                        fetch_close(conn);
@@ -1941,7 +1944,7 @@ http_request_body(struct url *URL, const char *op, str
                fetch_close(conn);
                conn = NULL;
                if (!new) {
-                       DEBUG(fprintf(stderr, "redirect with no new 
location\n"));
+                       DEBUGF("redirect with no new location\n");
                        break;
                }
                if (url != URL)
@@ -1955,10 +1958,9 @@ http_request_body(struct url *URL, const char *op, str
                goto ouch;
        }
 
-       DEBUG(fprintf(stderr, "offset %lld, length %lld,"
-                 " size %lld, clength %lld\n",
-                 (long long)offset, (long long)length,
-                 (long long)size, (long long)clength));
+       DEBUGF("offset %lld, length %lld, size %lld, clength %lld\n",
+           (long long)offset, (long long)length,
+           (long long)size, (long long)clength);
 
        if (conn->err == HTTP_NOT_MODIFIED) {
                http_seterr(HTTP_NOT_MODIFIED);

Modified: stable/11/usr.bin/fetch/fetch.1
==============================================================================
--- stable/11/usr.bin/fetch/fetch.1     Tue Oct  9 07:22:14 2018        
(r339249)
+++ stable/11/usr.bin/fetch/fetch.1     Tue Oct  9 10:49:19 2018        
(r339250)
@@ -30,7 +30,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 18, 2016
+.Dd May 6, 2018
 .Dt FETCH 1
 .Os
 .Sh NAME
@@ -241,7 +241,7 @@ certificate presented by the server.
 .It Fl -no-verify-peer
 [SSL]
 Do not verify the peer certificate against trusted CAs.
-.It Fl o Ar file , Fl output= Ns Ar file
+.It Fl o Ar file , Fl -output= Ns Ar file
 Set the output file name to
 .Ar file .
 By default, a ``pathname'' is extracted from the specified URI, and

Modified: stable/11/usr.bin/fetch/fetch.c
==============================================================================
--- stable/11/usr.bin/fetch/fetch.c     Tue Oct  9 07:22:14 2018        
(r339249)
+++ stable/11/usr.bin/fetch/fetch.c     Tue Oct  9 10:49:19 2018        
(r339250)
@@ -85,6 +85,7 @@ static int     t_flag;        /*!   -t: workaround TCP bug */
 static int      U_flag;        /*    -U: do not use high ports */
 static int      v_level = 1;   /*    -v: verbosity level */
 static int      v_tty;         /*        stdout is a tty */
+static int      v_progress;    /*        whether to display progress */
 static pid_t    pgrp;          /*        our process group */
 static long     w_secs;        /*    -w: retry delay */
 static int      family = PF_UNSPEC;    /* -[46]: address family to use */
@@ -199,12 +200,33 @@ struct xferstat {
 };
 
 /*
+ * Format a number of seconds as either XXdYYh, XXhYYm, XXmYYs, or XXs
+ * depending on its magnitude
+ */
+static void
+stat_seconds(char *str, size_t strsz, long seconds)
+{
+
+       if (seconds > 86400)
+               snprintf(str, strsz, "%02ldd%02ldh",
+                   seconds / 86400, (seconds % 86400) / 3600);
+       else if (seconds > 3600)
+               snprintf(str, strsz, "%02ldh%02ldm",
+                   seconds / 3600, (seconds % 3600) / 60);
+       else if (seconds > 60)
+               snprintf(str, strsz, "%02ldm%02lds",
+                   seconds / 60, seconds % 60);
+       else
+               snprintf(str, strsz, "   %02lds",
+                   seconds);
+}
+
+/*
  * Compute and display ETA
  */
-static const char *
-stat_eta(struct xferstat *xs)
+static void
+stat_eta(char *str, size_t strsz, const struct xferstat *xs)
 {
-       static char str[16];
        long elapsed, eta;
        off_t received, expected;
 
@@ -212,55 +234,47 @@ stat_eta(struct xferstat *xs)
        received = xs->rcvd - xs->offset;
        expected = xs->size - xs->rcvd;
        eta = (long)((double)elapsed * expected / received);
-       if (eta > 3600)
-               snprintf(str, sizeof str, "%02ldh%02ldm",
-                   eta / 3600, (eta % 3600) / 60);
-       else if (eta > 0)
-               snprintf(str, sizeof str, "%02ldm%02lds",
-                   eta / 60, eta % 60);
+       if (eta > 0)
+               stat_seconds(str, strsz, eta);
        else
-               snprintf(str, sizeof str, "%02ldm%02lds",
-                   elapsed / 60, elapsed % 60);
-       return (str);
+               stat_seconds(str, strsz, elapsed);
 }
 
 /*
  * Format a number as "xxxx YB" where Y is ' ', 'k', 'M'...
  */
 static const char *prefixes = " kMGTP";
-static const char *
-stat_bytes(off_t bytes)
+static void
+stat_bytes(char *str, size_t strsz, off_t bytes)
 {
-       static char str[16];
        const char *prefix = prefixes;
 
        while (bytes > 9999 && prefix[1] != '\0') {
                bytes /= 1024;
                prefix++;
        }
-       snprintf(str, sizeof str, "%4jd %cB", (intmax_t)bytes, *prefix);
-       return (str);
+       snprintf(str, strsz, "%4ju %cB", (uintmax_t)bytes, *prefix);
 }
 
 /*
  * Compute and display transfer rate
  */
-static const char *
-stat_bps(struct xferstat *xs)
+static void
+stat_bps(char *str, size_t strsz, struct xferstat *xs)
 {
-       static char str[16];
+       char bytes[16];
        double delta, bps;
 
-       delta = (xs->last.tv_sec + (xs->last.tv_usec / 1.e6))
-           - (xs->last2.tv_sec + (xs->last2.tv_usec / 1.e6));
+       delta = ((double)xs->last.tv_sec + (xs->last.tv_usec / 1.e6))
+           - ((double)xs->last2.tv_sec + (xs->last2.tv_usec / 1.e6));
 
        if (delta == 0.0) {
-               snprintf(str, sizeof str, "?? Bps");
+               snprintf(str, strsz, "?? Bps");
        } else {
                bps = (xs->rcvd - xs->lastrcvd) / delta;
-               snprintf(str, sizeof str, "%sps", stat_bytes((off_t)bps));
+               stat_bytes(bytes, sizeof bytes, (off_t)bps);
+               snprintf(str, strsz, "%sps", bytes);
        }
-       return (str);
 }
 
 /*
@@ -269,11 +283,12 @@ stat_bps(struct xferstat *xs)
 static void
 stat_display(struct xferstat *xs, int force)
 {
+       char bytes[16], bps[16], eta[16];
        struct timeval now;
        int ctty_pgrp;
 
        /* check if we're the foreground process */
-       if (ioctl(STDERR_FILENO, TIOCGPGRP, &ctty_pgrp) == -1 ||
+       if (ioctl(STDERR_FILENO, TIOCGPGRP, &ctty_pgrp) != 0 ||
            (pid_t)ctty_pgrp != pgrp)
                return;
 
@@ -284,26 +299,31 @@ stat_display(struct xferstat *xs, int force)
        xs->last = now;
 
        fprintf(stderr, "\r%-46.46s", xs->name);
-       if (xs->size <= 0) {
-               setproctitle("%s [%s]", xs->name, stat_bytes(xs->rcvd));
-               fprintf(stderr, "        %s", stat_bytes(xs->rcvd));
+       if (xs->rcvd >= xs->size) {
+               stat_bytes(bytes, sizeof bytes, xs->rcvd);
+               setproctitle("%s [%s]", xs->name, bytes);
+               fprintf(stderr, "        %s", bytes);
        } else {
+               stat_bytes(bytes, sizeof bytes, xs->size);
                setproctitle("%s [%d%% of %s]", xs->name,
                    (int)((100.0 * xs->rcvd) / xs->size),
-                   stat_bytes(xs->size));
+                   bytes);
                fprintf(stderr, "%3d%% of %s",
                    (int)((100.0 * xs->rcvd) / xs->size),
-                   stat_bytes(xs->size));
+                   bytes);
        }
        if (force == 2) {
                xs->lastrcvd = xs->offset;
                xs->last2 = xs->start;
        }
-       fprintf(stderr, " %s", stat_bps(xs));
+       stat_bps(bps, sizeof bps, xs);
+       fprintf(stderr, " %s", bps);
        if ((xs->size > 0 && xs->rcvd > 0 &&
             xs->last.tv_sec >= xs->start.tv_sec + 3) ||
-           force == 2)
-               fprintf(stderr, " %s", stat_eta(xs));
+           force == 2) {
+               stat_eta(eta, sizeof eta, xs);
+               fprintf(stderr, " %s", eta);
+       }
        xs->lastrcvd = xs->rcvd;
 }
 
@@ -313,14 +333,16 @@ stat_display(struct xferstat *xs, int force)
 static void
 stat_start(struct xferstat *xs, const char *name, off_t size, off_t offset)
 {
+
+       memset(xs, 0, sizeof *xs);
        snprintf(xs->name, sizeof xs->name, "%s", name);
        gettimeofday(&xs->start, NULL);
-       xs->last.tv_sec = xs->last.tv_usec = 0;
+       xs->last2 = xs->last = xs->start;
        xs->size = size;
        xs->offset = offset;
        xs->rcvd = offset;
        xs->lastrcvd = offset;
-       if (v_tty && v_level > 0)
+       if (v_progress)
                stat_display(xs, 1);
        else if (v_level > 0)
                fprintf(stderr, "%-46s", xs->name);
@@ -332,8 +354,9 @@ stat_start(struct xferstat *xs, const char *name, off_
 static void
 stat_update(struct xferstat *xs, off_t rcvd)
 {
+
        xs->rcvd = rcvd;
-       if (v_tty && v_level > 0)
+       if (v_progress)
                stat_display(xs, 0);
 }
 
@@ -343,13 +366,17 @@ stat_update(struct xferstat *xs, off_t rcvd)
 static void
 stat_end(struct xferstat *xs)
 {
+       char bytes[16], bps[16], eta[16];
+
        gettimeofday(&xs->last, NULL);
-       if (v_tty && v_level > 0) {
+       if (v_progress) {
                stat_display(xs, 2);
                putc('\n', stderr);
        } else if (v_level > 0) {
-               fprintf(stderr, "        %s %s\n",
-                   stat_bytes(xs->size), stat_bps(xs));
+               stat_bytes(bytes, sizeof bytes, xs->rcvd);
+               stat_bps(bps, sizeof bps, xs);
+               stat_eta(eta, sizeof eta, xs);
+               fprintf(stderr, "        %s %s %s\n", bytes, bps, eta);
        }
 }
 
@@ -552,9 +579,10 @@ fetch(char *URL, const char *path)
                goto signal;
        if (f == NULL) {
                warnx("%s: %s", URL, fetchLastErrString);
-               if (i_flag && strcmp(url->scheme, SCHEME_HTTP) == 0
-                   && fetchLastErrCode == FETCH_OK
-                   && strcmp(fetchLastErrString, "Not Modified") == 0) {
+               if (i_flag && (strcmp(url->scheme, SCHEME_HTTP) == 0 ||
+                   strcmp(url->scheme, SCHEME_HTTPS) == 0) &&
+                   fetchLastErrCode == FETCH_OK &&
+                   strcmp(fetchLastErrString, "Not Modified") == 0) {
                        /* HTTP Not Modified Response, return OK. */
                        r = 0;
                        goto done;
@@ -1109,7 +1137,8 @@ main(int argc, char *argv[])
 
        /* check if output is to a tty (for progress report) */
        v_tty = isatty(STDERR_FILENO);
-       if (v_tty)
+       v_progress = v_tty && v_level > 0;
+       if (v_progress)
                pgrp = getpgrp();
 
        r = 0;
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to