Beispiel #1
0
/*
 * Attempt to parse the given URL; if successful, call fetchXGet().
 */
fetchIO *
fetchXGetURL(const char *URL, struct url_stat *us, const char *flags)
{
	struct url *u;
	fetchIO *f;

	if ((u = fetchParseURL(URL)) == NULL)
		return (NULL);

	f = fetchXGet(u, us, flags);

	fetchFreeURL(u);
	return (f);
}
Beispiel #2
0
/*
 * Open a pkg_summary and if newer than local return an open libfetch
 * connection to it.
 */
Sumfile *
sum_open(char *str_url, time_t *db_mtime)
{
	Sumfile		*sum = NULL;
	fetchIO		*f = NULL;
	struct url	*url;
	struct url_stat	st;

	url = fetchParseURL(str_url);

	if (url == NULL || (f = fetchXGet(url, &st, "")) == NULL)
		goto nofetch;

	if (st.size == -1) { /* could not obtain file size */
		*db_mtime = 0; /* not -1, don't force update */
		goto nofetch;
	}

	if (st.mtime <= *db_mtime) {
		/*
		 * -1 used to identify return type,
		 * local summary up-to-date
		 */
		*db_mtime = -1;
		goto nofetch;
	}

	*db_mtime = st.mtime;

#ifndef _MINIX /* XXX: SSIZE_MAX fails under MINIX */
	/* st.size is an off_t, it will be > SSIZE_MAX on 32 bits systems */
	if (sizeof(st.size) == sizeof(SSIZE_MAX) && st.size > SSIZE_MAX - 1)
		err(EXIT_FAILURE, "file is too large");
#endif

	XMALLOC(sum, sizeof(Sumfile));

	sum->fd = f;
	sum->url = url;
	sum->size = st.size;
	goto out;
nofetch:
	if (url)
		fetchFreeURL(url);
	if (f)
		fetchIO_close(f);
out:
	return sum;
}
Beispiel #3
0
/* if db_mtime == NULL, we're downloading a package, pkg_summary otherwise */
Dlfile *
download_file(char *str_url, time_t *db_mtime)
{
	/* from pkg_install/files/admin/audit.c */
	Dlfile			*file;
	char			*p;
	size_t			buf_len, buf_fetched;
	ssize_t			cur_fetched;
	off_t			statsize;
	time_t			begin_dl, now;
	struct url_stat	st;
	struct url		*url;
	fetchIO			*f = NULL;

	url = fetchParseURL(str_url);

	if (url == NULL || (f = fetchXGet(url, &st, "")) == NULL)
		return NULL;

	if (st.size == -1) { /* could not obtain file size */
		if (db_mtime != NULL) /* we're downloading pkg_summary */
			*db_mtime = 0; /* not -1, don't force update */

		return NULL;
	}

	if (db_mtime != NULL) {
		if (st.mtime <= *db_mtime) {
			/* -1 used to identify return type, local summary up-to-date */
			*db_mtime = -1; 

			fetchIO_close(f);

			return NULL;
		}

		*db_mtime = st.mtime;
	}


	if ((p = strrchr(str_url, '/')) != NULL)
		p++;
	else
		p = (char *)str_url; /* should not happen */

#ifndef _MINIX /* XXX: SSIZE_MAX fails under MINIX */
	/* st.size is an off_t, it will be > SSIZE_MAX on 32 bits systems */
	if (sizeof(st.size) == sizeof(SSIZE_MAX) && st.size > SSIZE_MAX - 1)
		err(EXIT_FAILURE, "file is too large");
#endif

	buf_len = st.size;
	XMALLOC(file, sizeof(Dlfile));
	XMALLOC(file->buf, buf_len + 1);

	printf(MSG_DOWNLOADING, p);
	fflush(stdout);

	buf_fetched = 0;
	begin_dl = time(NULL);

	statsize = 0;
	start_progress_meter(p, buf_len, &statsize);

	while (buf_fetched < buf_len) {
		cur_fetched = fetchIO_read(f, file->buf + buf_fetched, fetch_buffer);
		if (cur_fetched == 0)
			errx(EXIT_FAILURE, "truncated file");
		else if (cur_fetched == -1)
			errx(EXIT_FAILURE, "failure during fetch of file: %s",
				fetchLastErrString);

		buf_fetched += cur_fetched;
		statsize += cur_fetched;
		now = time(NULL);
	}

	stop_progress_meter();

	file->buf[buf_len] = '\0';
	file->size = buf_len;

	if (file->buf[0] == '\0')
		errx(EXIT_FAILURE, "empty download, exiting.\n");


	fetchIO_close(f);

	return file;
}
Beispiel #4
0
/*
 * Select the appropriate protocol for the URL scheme, and return a
 * read-only stream connected to the document referenced by the URL.
 */
fetchIO *
fetchGet(struct url *URL, const char *flags)
{
	return (fetchXGet(URL, NULL, flags));
}
Beispiel #5
0
/*
 * Download a package to the local cache.
 */
ssize_t
download_pkg(char *pkg_url, FILE *fp)
{
	struct url_stat st;
	size_t size, wrote;
	ssize_t fetched, written = 0;
	off_t statsize = 0;
	struct url *url;
	fetchIO *f = NULL;
	char buf[4096];
	char *pkg, *ptr;

	if ((url = fetchParseURL(pkg_url)) == NULL)
		errx(EXIT_FAILURE, "%s: parse failure", pkg_url);

	if ((f = fetchXGet(url, &st, "")) == NULL)
		errx(EXIT_FAILURE, "%s: %s", pkg_url, fetchLastErrString);

	/* Package not available */
	if (st.size == -1)
		return st.size;

	if ((pkg = strrchr(pkg_url, '/')) != NULL)
		pkg++;
	else
		pkg = (char *)pkg_url; /* should not happen */

	if (parsable) {
		printf(MSG_DOWNLOAD_START);
	} else {
		printf(MSG_DOWNLOADING, pkg);
		fflush(stdout);
		start_progress_meter(pkg, st.size, &statsize);
	}

	while (written < st.size) {
		if ((fetched = fetchIO_read(f, buf, sizeof(buf))) == 0)
			break;
		if (fetched == -1 && errno == EINTR)
			continue;
		if (fetched == -1)
			errx(EXIT_FAILURE, "fetch failure: %s",
			    fetchLastErrString);

		statsize += fetched;
		size = fetched;

		for (ptr = buf; size > 0; ptr += wrote, size -= wrote) {
			if ((wrote = fwrite(ptr, 1, size, fp)) < size) {
				if (ferror(fp) && errno == EINTR)
					clearerr(fp);
				else
					break;
			}
			written += wrote;
		}
	}

	if (parsable)
		printf(MSG_DOWNLOAD_END);
	else
		stop_progress_meter();

	fetchIO_close(f);
	fetchFreeURL(url);

	if (written != st.size)
		return -1;

	return written;
}
void
fetch_pkg_vulnerabilities(int argc, char **argv)
{
	struct pkg_vulnerabilities *pv_check;
	char *buf;
	size_t buf_len, buf_fetched;
	ssize_t cur_fetched;
	struct url *url;
	struct url_stat st;
	fetchIO *f;
	int fd;
	struct stat sb;
	char my_flags[20];
	const char *flags;

	parse_options(argc, argv, "su");
	if (argc != optind)
		usage();

	if (verbose >= 2)
		fprintf(stderr, "Fetching %s\n", pkg_vulnerabilities_url);

	url = fetchParseURL(pkg_vulnerabilities_url);
	if (url == NULL)
		errx(EXIT_FAILURE,
		    "Could not parse location of pkg_vulnerabilities: %s",
		    fetchLastErrString);

	flags = fetch_flags;
	if (update_pkg_vuln) {
		fd = open(pkg_vulnerabilities_file, O_RDONLY);
		if (fd != -1 && fstat(fd, &sb) != -1) {
			url->last_modified = sb.st_mtime;
			snprintf(my_flags, sizeof(my_flags), "%si",
			    fetch_flags);
			flags = my_flags;
		} else
			update_pkg_vuln = 0;
		if (fd != -1)
			close(fd);
	}

	f = fetchXGet(url, &st, flags);
	if (f == NULL && update_pkg_vuln &&
	    fetchLastErrCode == FETCH_UNCHANGED) {
		if (verbose >= 1)
			fprintf(stderr, "%s is not newer\n",
			    pkg_vulnerabilities_url);
		exit(EXIT_SUCCESS);
	}

	if (f == NULL)
		errx(EXIT_FAILURE, "Could not fetch vulnerability file: %s",
		    fetchLastErrString);

	if (st.size > SSIZE_MAX - 1)
		errx(EXIT_FAILURE, "pkg-vulnerabilities is too large");

	buf_len = st.size;
	buf = xmalloc(buf_len + 1);
	buf_fetched = 0;

	while (buf_fetched < buf_len) {
		cur_fetched = fetchIO_read(f, buf + buf_fetched,
		    buf_len - buf_fetched);
		if (cur_fetched == 0)
			errx(EXIT_FAILURE,
			    "Truncated pkg-vulnerabilities received");
		else if (cur_fetched == -1)
			errx(EXIT_FAILURE,
			    "IO error while fetching pkg-vulnerabilities: %s",
			    fetchLastErrString);
		buf_fetched += cur_fetched;
	}
	
	buf[buf_len] = '\0';

	pv_check = read_pkg_vulnerabilities_memory(buf, buf_len, check_signature);
	free_pkg_vulnerabilities(pv_check);

	fd = open(pkg_vulnerabilities_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
	if (fd == -1)
		err(EXIT_FAILURE, "Cannot create pkg-vulnerability file %s",
		    pkg_vulnerabilities_file);

	if (write(fd, buf, buf_len) != (ssize_t)buf_len)
		err(EXIT_FAILURE, "Cannot write pkg-vulnerability file");
	if (close(fd) == -1)
		err(EXIT_FAILURE, "Cannot close pkg-vulnerability file after write");

	free(buf);

	exit(EXIT_SUCCESS);
}
Beispiel #7
0
/*
 * Fetch a file
 */
static int
fetch(char *URL, const char *path)
{
	struct url *url;
	struct url_stat us;
	struct stat sb, nsb;
	struct xferstat xs;
	FILE *f, *of;
	size_t size, readcnt, wr;
	off_t count;
	char flags[8];
	const char *slash;
	char *tmppath;
	int r;
	unsigned timeout;
	char *ptr;

	f = of = NULL;
	tmppath = NULL;

	timeout = 0;
	*flags = 0;
	count = 0;

	/* set verbosity level */
	if (v_level > 1)
		strcat(flags, "v");
	if (v_level > 2)
		fetchDebug = 1;

	/* parse URL */
	if ((url = fetchParseURL(URL)) == NULL) {
		warnx("%s: parse error", URL);
		goto failure;
	}

	/* if no scheme was specified, take a guess */
	if (*url->scheme == 0) {
		if (*url->host == 0)
			strcpy(url->scheme, SCHEME_FILE);
		else if (strncasecmp(url->host, "ftp.", 4) == 0)
			strcpy(url->scheme, SCHEME_FTP);
		else if (strncasecmp(url->host, "www.", 4) == 0)
			strcpy(url->scheme, SCHEME_HTTP);
	}

	/* common flags */
	switch (family) {
	case PF_INET:
		strcat(flags, "4");
		break;
	case PF_INET6:
		strcat(flags, "6");
		break;
	}

	/* FTP specific flags */
	if (strcmp(url->scheme, SCHEME_FTP) == 0) {
		if (p_flag)
			strcat(flags, "p");
		if (d_flag)
			strcat(flags, "d");
		if (U_flag)
			strcat(flags, "l");
		timeout = T_secs ? T_secs : ftp_timeout;
	}

	/* HTTP specific flags */
	if (strcmp(url->scheme, SCHEME_HTTP) == 0 ||
	    strcmp(url->scheme, SCHEME_HTTPS) == 0) {
		if (d_flag)
			strcat(flags, "d");
		if (A_flag)
			strcat(flags, "A");
		timeout = T_secs ? T_secs : http_timeout;
		if (i_flag) {
			if (stat(i_filename, &sb)) {
				warn("%s: stat()", i_filename);
				goto failure;
			}
			url->ims_time = sb.st_mtime;
			strcat(flags, "i");
		}
	}

	/* set the protocol timeout. */
	fetchTimeout = timeout;

	/* just print size */
	if (s_flag) {
		if (timeout)
			alarm(timeout);
		r = fetchStat(url, &us, flags);
		if (timeout)
			alarm(0);
		if (sigalrm || sigint)
			goto signal;
		if (r == -1) {
			warnx("%s", fetchLastErrString);
			goto failure;
		}
		if (us.size == -1)
			printf("Unknown\n");
		else
			printf("%jd\n", (intmax_t)us.size);
		goto success;
	}

	/*
	 * If the -r flag was specified, we have to compare the local
	 * and remote files, so we should really do a fetchStat()
	 * first, but I know of at least one HTTP server that only
	 * sends the content size in response to GET requests, and
	 * leaves it out of replies to HEAD requests.  Also, in the
	 * (frequent) case that the local and remote files match but
	 * the local file is truncated, we have sufficient information
	 * before the compare to issue a correct request.  Therefore,
	 * we always issue a GET request as if we were sure the local
	 * file was a truncated copy of the remote file; we can drop
	 * the connection later if we change our minds.
	 */
	sb.st_size = -1;
	if (!o_stdout) {
		r = stat(path, &sb);
		if (r == 0 && r_flag && S_ISREG(sb.st_mode)) {
			url->offset = sb.st_size;
		} else if (r == -1 || !S_ISREG(sb.st_mode)) {
			/*
			 * Whatever value sb.st_size has now is either
			 * wrong (if stat(2) failed) or irrelevant (if the
			 * path does not refer to a regular file)
			 */
			sb.st_size = -1;
		}
		if (r == -1 && errno != ENOENT) {
			warnx("%s: stat()", path);
			goto failure;
		}
	}

	/* start the transfer */
	if (timeout)
		alarm(timeout);
	f = fetchXGet(url, &us, flags);
	if (timeout)
		alarm(0);
	if (sigalrm || sigint)
		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) {
			/* HTTP Not Modified Response, return OK. */
			r = 0;
			goto done;
		} else
			goto failure;
	}
	if (sigint)
		goto signal;

	/* check that size is as expected */
	if (S_size) {
		if (us.size == -1) {
			warnx("%s: size unknown", URL);
		} else if (us.size != S_size) {
			warnx("%s: size mismatch: expected %jd, actual %jd",
			    URL, (intmax_t)S_size, (intmax_t)us.size);
			goto failure;
		}
	}

	/* symlink instead of copy */
	if (l_flag && strcmp(url->scheme, "file") == 0 && !o_stdout) {
		if (symlink(url->doc, path) == -1) {
			warn("%s: symlink()", path);
			goto failure;
		}
		goto success;
	}

	if (us.size == -1 && !o_stdout && v_level > 0)
		warnx("%s: size of remote file is not known", URL);
	if (v_level > 1) {
		if (sb.st_size != -1)
			fprintf(stderr, "local size / mtime: %jd / %ld\n",
			    (intmax_t)sb.st_size, (long)sb.st_mtime);
		if (us.size != -1)
			fprintf(stderr, "remote size / mtime: %jd / %ld\n",
			    (intmax_t)us.size, (long)us.mtime);
	}

	/* open output file */
	if (o_stdout) {
		/* output to stdout */
		of = stdout;
	} else if (r_flag && sb.st_size != -1) {
		/* resume mode, local file exists */
		if (!F_flag && us.mtime && sb.st_mtime != us.mtime) {
			/* no match! have to refetch */
			fclose(f);
			/* if precious, warn the user and give up */
			if (R_flag) {
				warnx("%s: local modification time "
				    "does not match remote", path);
				goto failure_keep;
			}
		} else if (us.size != -1) {
			if (us.size == sb.st_size)
				/* nothing to do */
				goto success;
			if (sb.st_size > us.size) {
				/* local file too long! */
				warnx("%s: local file (%jd bytes) is longer "
				    "than remote file (%jd bytes)", path,
				    (intmax_t)sb.st_size, (intmax_t)us.size);
				goto failure;
			}
			/* we got it, open local file */
			if ((of = fopen(path, "a")) == NULL) {
				warn("%s: fopen()", path);
				goto failure;
			}
			/* check that it didn't move under our feet */
			if (fstat(fileno(of), &nsb) == -1) {
				/* can't happen! */
				warn("%s: fstat()", path);
				goto failure;
			}
			if (nsb.st_dev != sb.st_dev ||
			    nsb.st_ino != nsb.st_ino ||
			    nsb.st_size != sb.st_size) {
				warnx("%s: file has changed", URL);
				fclose(of);
				of = NULL;
				sb = nsb;
			}
		}
	} else if (m_flag && sb.st_size != -1) {
		/* mirror mode, local file exists */
		if (sb.st_size == us.size && sb.st_mtime == us.mtime)
			goto success;
	}

	if (of == NULL) {
		/*
		 * We don't yet have an output file; either this is a
		 * vanilla run with no special flags, or the local and
		 * remote files didn't match.
		 */

		if (url->offset > 0) {
			/*
			 * We tried to restart a transfer, but for
			 * some reason gave up - so we have to restart
			 * from scratch if we want the whole file
			 */
			url->offset = 0;
			if ((f = fetchXGet(url, &us, flags)) == NULL) {
				warnx("%s: %s", URL, fetchLastErrString);
				goto failure;
			}
			if (sigint)
				goto signal;
		}

		/* construct a temporary file name */
		if (sb.st_size != -1 && S_ISREG(sb.st_mode)) {
			if ((slash = strrchr(path, '/')) == NULL)
				slash = path;
			else
				++slash;
			asprintf(&tmppath, "%.*s.fetch.XXXXXX.%s",
			    (int)(slash - path), path, slash);
			if (tmppath != NULL) {
				if (mkstemps(tmppath, strlen(slash)+1) == -1) {
					warn("%s: mkstemps()", path);
					goto failure;
				}

				of = fopen(tmppath, "w");
				chown(tmppath, sb.st_uid, sb.st_gid);
				chmod(tmppath, sb.st_mode & ALLPERMS);
			}
		}

		if (of == NULL)
			if ((of = fopen(path, "w")) == NULL) {
				warn("%s: fopen()", path);
			goto failure;
		}
	}
	count = url->offset;

	/* start the counter */
	stat_start(&xs, path, us.size, count);

	sigalrm = siginfo = sigint = 0;

	/* suck in the data */
	signal(SIGINFO, sig_handler);
	while (!sigint) {
		if (us.size != -1 && us.size - count < B_size &&
		    us.size - count >= 0)
			size = us.size - count;
		else
			size = B_size;
		if (siginfo) {
			stat_end(&xs);
			siginfo = 0;
		}

		if (size == 0)
			break;

		if ((readcnt = fread(buf, 1, size, f)) < size) {
			if (ferror(f) && errno == EINTR && !sigint)
				clearerr(f);
			else if (readcnt == 0)
				break;
		}

		stat_update(&xs, count += readcnt);
		for (ptr = buf; readcnt > 0; ptr += wr, readcnt -= wr)
			if ((wr = fwrite(ptr, 1, readcnt, of)) < readcnt) {
				if (ferror(of) && errno == EINTR && !sigint)
					clearerr(of);
				else
					break;
			}
		if (readcnt != 0)
			break;
	}
	if (!sigalrm)
		sigalrm = ferror(f) && errno == ETIMEDOUT;
	signal(SIGINFO, SIG_DFL);

	stat_end(&xs);

	/*
	 * If the transfer timed out or was interrupted, we still want to
	 * set the mtime in case the file is not removed (-r or -R) and
	 * the user later restarts the transfer.
	 */
 signal:
	/* set mtime of local file */
	if (!n_flag && us.mtime && !o_stdout && of != NULL &&
	    (stat(path, &sb) != -1) && sb.st_mode & S_IFREG) {
		struct timeval tv[2];

		fflush(of);
		tv[0].tv_sec = (long)(us.atime ? us.atime : us.mtime);
		tv[1].tv_sec = (long)us.mtime;
		tv[0].tv_usec = tv[1].tv_usec = 0;
		if (utimes(tmppath ? tmppath : path, tv))
			warn("%s: utimes()", tmppath ? tmppath : path);
	}

	/* timed out or interrupted? */
	if (sigalrm)
		warnx("transfer timed out");
	if (sigint) {
		warnx("transfer interrupted");
		goto failure;
	}

	/* timeout / interrupt before connection completley established? */
	if (f == NULL)
		goto failure;

	if (!sigalrm) {
		/* check the status of our files */
		if (ferror(f))
			warn("%s", URL);
		if (ferror(of))
			warn("%s", path);
		if (ferror(f) || ferror(of))
			goto failure;
	}

	/* did the transfer complete normally? */
	if (us.size != -1 && count < us.size) {
		warnx("%s appears to be truncated: %jd/%jd bytes",
		    path, (intmax_t)count, (intmax_t)us.size);
		goto failure_keep;
	}

	/*
	 * If the transfer timed out and we didn't know how much to
	 * expect, assume the worst (i.e. we didn't get all of it)
	 */
	if (sigalrm && us.size == -1) {
		warnx("%s may be truncated", path);
		goto failure_keep;
	}

 success:
	r = 0;
	if (tmppath != NULL && rename(tmppath, path) == -1) {
		warn("%s: rename()", path);
		goto failure_keep;
	}
	goto done;
 failure:
	if (of && of != stdout && !R_flag && !r_flag)
		if (stat(path, &sb) != -1 && (sb.st_mode & S_IFREG))
			unlink(tmppath ? tmppath : path);
	if (R_flag && tmppath != NULL && sb.st_size == -1)
		rename(tmppath, path); /* ignore errors here */
 failure_keep:
	r = -1;
	goto done;
 done:
	if (f)
		fclose(f);
	if (of && of != stdout)
		fclose(of);
	if (url)
		fetchFreeURL(url);
	if (tmppath != NULL)
		free(tmppath);
	return (r);
}
Beispiel #8
0
int
pkg_fetch_file_to_fd(const char *url, int dest, time_t t)
{
	FILE *remote = NULL;
	struct url *u;
	struct url_stat st;
	off_t done = 0;
	off_t r;

	int64_t max_retry, retry;
	time_t begin_dl;
	time_t now;
	time_t last = 0;
	char buf[10240];
	char *doc;
	char docpath[MAXPATHLEN];
	int retcode = EPKG_OK;
	bool srv = false;
	bool http = false;
	char zone[MAXHOSTNAMELEN + 13];
	struct dns_srvinfo *srv_current = NULL;
	struct http_mirror *http_current = NULL;
	const char *mt;

	fetchTimeout = 30;

	if (pkg_config_int64(PKG_CONFIG_FETCH_RETRY, &max_retry) == EPKG_FATAL)
		max_retry = 3;

	retry = max_retry;

	u = fetchParseURL(url);
	doc = u->doc;
	while (remote == NULL) {
		if (retry == max_retry) {
			pkg_config_string(PKG_CONFIG_MIRRORS, &mt);
			if (mt != NULL && strncasecmp(mt, "srv", 3) == 0 && \
			    strcmp(u->scheme, "file") != 0) {
				srv = true;
				snprintf(zone, sizeof(zone),
				    "_%s._tcp.%s", u->scheme, u->host);
				pthread_mutex_lock(&mirror_mtx);
				if (srv_mirrors != NULL)
					srv_mirrors = dns_getsrvinfo(zone);
				pthread_mutex_unlock(&mirror_mtx);
				srv_current = srv_mirrors;
			} else if (mt != NULL && strncasecmp(mt, "http", 4) == 0 && \
			           strcmp(u->scheme, "file") != 0 && \
			           strcmp(u->scheme, "ftp") != 0) {
				http = true;
				snprintf(zone, sizeof(zone),
				    "%s://%s", u->scheme, u->host);
				pthread_mutex_lock(&mirror_mtx);
				if (STAILQ_EMPTY(&http_mirrors))
					gethttpmirrors(zone);
				pthread_mutex_unlock(&mirror_mtx);
				http_current = STAILQ_FIRST(&http_mirrors);
			}
		}

		if (srv && srv_mirrors != NULL)
			strlcpy(u->host, srv_current->host, sizeof(u->host));
		else if (http && !STAILQ_EMPTY(&http_mirrors)) {
			strlcpy(u->scheme, http_current->url->scheme, sizeof(u->scheme));
			strlcpy(u->host, http_current->url->host, sizeof(u->host));
			snprintf(docpath, MAXPATHLEN, "%s%s", http_current->url->doc, doc);
			u->doc = docpath;
			u->port = http_current->url->port;
		}

		remote = fetchXGet(u, &st, "");
		if (remote == NULL) {
			--retry;
			if (retry <= 0) {
				pkg_emit_error("%s: %s", url,
				    fetchLastErrString);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
			if (srv && srv_mirrors != NULL) {
				srv_current = srv_current->next;
				if (srv_current == NULL)
					srv_current = srv_mirrors;
			} else if (http && !STAILQ_EMPTY(&http_mirrors)) {
				http_current = STAILQ_NEXT(http_current, next);
				if (http_current == NULL)
					http_current = STAILQ_FIRST(&http_mirrors);
			} else {
				sleep(1);
			}
		}
	}
	if (t != 0) {
		if (st.mtime <= t) {
			retcode = EPKG_UPTODATE;
			goto cleanup;
		}
	}

	begin_dl = time(NULL);
	while (done < st.size) {
		if ((r = fread(buf, 1, sizeof(buf), remote)) < 1)
			break;

		if (write(dest, buf, r) != r) {
			pkg_emit_errno("write", "");
			retcode = EPKG_FATAL;
			goto cleanup;
		}

		done += r;
		now = time(NULL);
		/* Only call the callback every second */
		if (now > last || done == st.size) {
			pkg_emit_fetching(url, st.size, done, (now - begin_dl));
			last = now;
		}
	}

	if (ferror(remote)) {
		pkg_emit_error("%s: %s", url, fetchLastErrString);
		retcode = EPKG_FATAL;
		goto cleanup;
	}

	cleanup:

	if (remote != NULL)
		fclose(remote);

	/* restore original doc */
	u->doc = doc;

	fetchFreeURL(u);

	return (retcode);
}
Beispiel #9
0
int
pkg_fetch_file_to_fd(const char *url, int dest, time_t t)
{
	FILE *remote = NULL;
	struct url *u;
	struct url_stat st;
	off_t done = 0;
	off_t r;

	int64_t max_retry, retry;
	time_t begin_dl;
	time_t now;
	time_t last = 0;
	char buf[10240];
	int retcode = EPKG_OK;
	bool srv = false;
	char zone[MAXHOSTNAMELEN + 12];
	struct dns_srvinfo *mirrors, *current;

	current = mirrors = NULL;

	fetchTimeout = 30;

	if (pkg_config_int64(PKG_CONFIG_FETCH_RETRY, &max_retry) == EPKG_FATAL)
		max_retry = 3;

	retry = max_retry;

	u = fetchParseURL(url);
	while (remote == NULL) {
		if (retry == max_retry) {
			pkg_config_bool(PKG_CONFIG_SRV_MIRROR, &srv);
			if (srv) {
				if (strcmp(u->scheme, "file") != 0) {
					snprintf(zone, sizeof(zone),
					    "_%s._tcp.%s", u->scheme, u->host);
					mirrors = dns_getsrvinfo(zone);
					current = mirrors;
				}
			}
		}

		if (mirrors != NULL)
			strlcpy(u->host, current->host, sizeof(u->host));

		remote = fetchXGet(u, &st, "");
		if (remote == NULL) {
			--retry;
			if (retry <= 0) {
				pkg_emit_error("%s: %s", url,
				    fetchLastErrString);
				retcode = EPKG_FATAL;
				goto cleanup;
			}
			if (mirrors == NULL) {
				sleep(1);
			} else {
				current = current->next;
				if (current == NULL)
					current = mirrors;
			}
		}
	}
	if (t != 0) {
		if (st.mtime <= t) {
			retcode = EPKG_UPTODATE;
			goto cleanup;
		}
	}

	begin_dl = time(NULL);
	while (done < st.size) {
		if ((r = fread(buf, 1, sizeof(buf), remote)) < 1)
			break;

		if (write(dest, buf, r) != r) {
			pkg_emit_errno("write", "");
			retcode = EPKG_FATAL;
			goto cleanup;
		}

		done += r;
		now = time(NULL);
		/* Only call the callback every second */
		if (now > last || done == st.size) {
			pkg_emit_fetching(url, st.size, done, (now - begin_dl));
			last = now;
		}
	}

	if (ferror(remote)) {
		pkg_emit_error("%s: %s", url, fetchLastErrString);
		retcode = EPKG_FATAL;
		goto cleanup;
	}

	cleanup:

	if (remote != NULL)
		fclose(remote);

	fetchFreeURL(u);

	return (retcode);
}
Beispiel #10
0
static int
bootstrap_pkg(void)
{
	struct url *u;
	FILE *remote;
	FILE *config;
	char *site;
	struct dns_srvinfo *mirrors, *current;
	/* To store _https._tcp. + hostname + \0 */
	char zone[MAXHOSTNAMELEN + 13];
	char url[MAXPATHLEN];
	char conf[MAXPATHLEN];
	char tmppkg[MAXPATHLEN];
	const char *packagesite, *mirror_type;
	char buf[10240];
	char pkgstatic[MAXPATHLEN];
	int fd, retry, ret, max_retry;
	struct url_stat st;
	off_t done, r;
	time_t now;
	time_t last;

	done = 0;
	last = 0;
	max_retry = 3;
	ret = -1;
	remote = NULL;
	config = NULL;
	current = mirrors = NULL;

	printf("Bootstrapping pkg please wait\n");

	if (config_string(PACKAGESITE, &packagesite) != 0) {
		warnx("No PACKAGESITE defined");
		return (-1);
	}
	if (config_string(MIRROR_TYPE, &mirror_type) != 0) {
		warnx("No MIRROR_TYPE defined");
		return (-1);
	}
	snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite);

	snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX",
	    getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);

	if ((fd = mkstemp(tmppkg)) == -1) {
		warn("mkstemp()");
		return (-1);
	}

	retry = max_retry;

	u = fetchParseURL(url);
	while (remote == NULL) {
		if (retry == max_retry) {
			if (strcmp(u->scheme, "file") != 0 &&
			    strcasecmp(mirror_type, "srv") == 0) {
				snprintf(zone, sizeof(zone),
				    "_%s._tcp.%s", u->scheme, u->host);
				mirrors = dns_getsrvinfo(zone);
				current = mirrors;
			}
		}

		if (mirrors != NULL)
			strlcpy(u->host, current->host, sizeof(u->host));

		remote = fetchXGet(u, &st, "");
		if (remote == NULL) {
			--retry;
			if (retry <= 0)
				goto fetchfail;
			if (mirrors == NULL) {
				sleep(1);
			} else {
				current = current->next;
				if (current == NULL)
					current = mirrors;
			}
		}
	}

	if (remote == NULL)
		goto fetchfail;

	while (done < st.size) {
		if ((r = fread(buf, 1, sizeof(buf), remote)) < 1)
			break;

		if (write(fd, buf, r) != r) {
			warn("write()");
			goto cleanup;
		}

		done += r;
		now = time(NULL);
		if (now > last || done == st.size)
			last = now;
	}

	if (ferror(remote))
		goto fetchfail;

	if ((ret = extract_pkg_static(fd, pkgstatic, MAXPATHLEN)) == 0)
		ret = install_pkg_static(pkgstatic, tmppkg);

	snprintf(conf, MAXPATHLEN, "%s/etc/pkg.conf",
	    getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE);

	if (access(conf, R_OK) == -1) {
		site = strrchr(url, '/');
		if (site == NULL)
			goto cleanup;
		site[0] = '\0';
		site = strrchr(url, '/');
		if (site == NULL)
			goto cleanup;
		site[0] = '\0';

		config = fopen(conf, "w+");
		if (config == NULL)
			goto cleanup;
		fprintf(config, "packagesite: %s\n", url);
		fclose(config);
	}

	goto cleanup;

fetchfail:
	warnx("Error fetching %s: %s", url, fetchLastErrString);
	fprintf(stderr, "A pre-built version of pkg could not be found for your system.\n");
	fprintf(stderr, "Consider changing PACKAGESITE or installing it from ports: 'ports-mgmt/pkg'.\n");

cleanup:
	if (remote != NULL)
		fclose(remote);
	close(fd);
	unlink(tmppkg);

	return (ret);
}