svn commit: r339250 - in stable/11: lib/libfetch usr.bin/fetch

Dag-Erling Smørgrav des at FreeBSD.org
Tue Oct 9 10:49:21 UTC 2018


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;


More information about the svn-src-stable-11 mailing list