xref: /freebsd/usr.sbin/pkg/pkg.c (revision 3b05c2a8a7baf903e3bd49a8072e2fd09c77e228)
13aa4b42aSBaptiste Daroussin /*-
23aa4b42aSBaptiste Daroussin  * Copyright (c) 2012 Baptiste Daroussin <bapt@FreeBSD.org>
33aa4b42aSBaptiste Daroussin  * All rights reserved.
43aa4b42aSBaptiste Daroussin  *
53aa4b42aSBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
63aa4b42aSBaptiste Daroussin  * modification, are permitted provided that the following conditions
73aa4b42aSBaptiste Daroussin  * are met:
83aa4b42aSBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
93aa4b42aSBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer.
103aa4b42aSBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
113aa4b42aSBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
123aa4b42aSBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
133aa4b42aSBaptiste Daroussin  *
143aa4b42aSBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
153aa4b42aSBaptiste Daroussin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
163aa4b42aSBaptiste Daroussin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
173aa4b42aSBaptiste Daroussin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
183aa4b42aSBaptiste Daroussin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
193aa4b42aSBaptiste Daroussin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
203aa4b42aSBaptiste Daroussin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
213aa4b42aSBaptiste Daroussin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
223aa4b42aSBaptiste Daroussin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
233aa4b42aSBaptiste Daroussin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
243aa4b42aSBaptiste Daroussin  * SUCH DAMAGE.
253aa4b42aSBaptiste Daroussin  */
263aa4b42aSBaptiste Daroussin 
273aa4b42aSBaptiste Daroussin #include <sys/cdefs.h>
283aa4b42aSBaptiste Daroussin __FBSDID("$FreeBSD$");
293aa4b42aSBaptiste Daroussin 
303aa4b42aSBaptiste Daroussin #include <sys/param.h>
313aa4b42aSBaptiste Daroussin #include <sys/elf_common.h>
323aa4b42aSBaptiste Daroussin #include <sys/endian.h>
33*3b05c2a8SBaptiste Daroussin #include <sys/wait.h>
343aa4b42aSBaptiste Daroussin 
353aa4b42aSBaptiste Daroussin #include <archive.h>
363aa4b42aSBaptiste Daroussin #include <archive_entry.h>
373aa4b42aSBaptiste Daroussin #include <ctype.h>
383aa4b42aSBaptiste Daroussin #include <err.h>
393aa4b42aSBaptiste Daroussin #include <errno.h>
403aa4b42aSBaptiste Daroussin #include <fcntl.h>
41*3b05c2a8SBaptiste Daroussin #include <fetch.h>
423aa4b42aSBaptiste Daroussin #include <gelf.h>
433aa4b42aSBaptiste Daroussin #include <stdlib.h>
443aa4b42aSBaptiste Daroussin #include <stdio.h>
453aa4b42aSBaptiste Daroussin #include <string.h>
463aa4b42aSBaptiste Daroussin #include <time.h>
473aa4b42aSBaptiste Daroussin #include <unistd.h>
483aa4b42aSBaptiste Daroussin 
493aa4b42aSBaptiste Daroussin #include "elf_tables.h"
503aa4b42aSBaptiste Daroussin 
513aa4b42aSBaptiste Daroussin #define _LOCALBASE "/usr/local"
523aa4b42aSBaptiste Daroussin #define _PKGS_URL "http://pkgbeta.FreeBSD.org"
533aa4b42aSBaptiste Daroussin #define _DEFAULT_TMP "/tmp"
543aa4b42aSBaptiste Daroussin 
553aa4b42aSBaptiste Daroussin static const char *
563aa4b42aSBaptiste Daroussin elf_corres_to_string(struct _elf_corres *m, int e)
573aa4b42aSBaptiste Daroussin {
58ce36f45dSBaptiste Daroussin 	int i;
593aa4b42aSBaptiste Daroussin 
603aa4b42aSBaptiste Daroussin 	for (i = 0; m[i].string != NULL; i++)
613aa4b42aSBaptiste Daroussin 		if (m[i].elf_nb == e)
623aa4b42aSBaptiste Daroussin 			return (m[i].string);
633aa4b42aSBaptiste Daroussin 
643aa4b42aSBaptiste Daroussin 	return ("unknown");
653aa4b42aSBaptiste Daroussin }
663aa4b42aSBaptiste Daroussin 
673aa4b42aSBaptiste Daroussin static int
683aa4b42aSBaptiste Daroussin pkg_get_myabi(char *dest, size_t sz)
693aa4b42aSBaptiste Daroussin {
703aa4b42aSBaptiste Daroussin 	Elf *elf;
713aa4b42aSBaptiste Daroussin 	GElf_Ehdr elfhdr;
723aa4b42aSBaptiste Daroussin 	GElf_Shdr shdr;
733aa4b42aSBaptiste Daroussin 	Elf_Data *data;
743aa4b42aSBaptiste Daroussin 	Elf_Note note;
753aa4b42aSBaptiste Daroussin 	Elf_Scn *scn;
763aa4b42aSBaptiste Daroussin 	char *src, *osname;
773aa4b42aSBaptiste Daroussin 	const char *abi;
783aa4b42aSBaptiste Daroussin 	int fd, i, ret;
793aa4b42aSBaptiste Daroussin 	uint32_t version;
803aa4b42aSBaptiste Daroussin 
813aa4b42aSBaptiste Daroussin 	version = 0;
823aa4b42aSBaptiste Daroussin 	ret = 0;
833aa4b42aSBaptiste Daroussin 	scn = NULL;
843aa4b42aSBaptiste Daroussin 	abi = NULL;
853aa4b42aSBaptiste Daroussin 
863aa4b42aSBaptiste Daroussin 	if (elf_version(EV_CURRENT) == EV_NONE) {
87*3b05c2a8SBaptiste Daroussin 		warnx("ELF library initialization failed: %s",
88*3b05c2a8SBaptiste Daroussin 		    elf_errmsg(-1));
89*3b05c2a8SBaptiste Daroussin 		return (-1);
903aa4b42aSBaptiste Daroussin 	}
913aa4b42aSBaptiste Daroussin 
923aa4b42aSBaptiste Daroussin 	if ((fd = open("/bin/sh", O_RDONLY)) < 0) {
933aa4b42aSBaptiste Daroussin 		warn("open()");
94*3b05c2a8SBaptiste Daroussin 		return (-1);
953aa4b42aSBaptiste Daroussin 	}
963aa4b42aSBaptiste Daroussin 
973aa4b42aSBaptiste Daroussin 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
983aa4b42aSBaptiste Daroussin 		ret = -1;
993aa4b42aSBaptiste Daroussin 		warnx("elf_begin() failed: %s.", elf_errmsg(-1));
1003aa4b42aSBaptiste Daroussin 		goto cleanup;
1013aa4b42aSBaptiste Daroussin 	}
1023aa4b42aSBaptiste Daroussin 
1033aa4b42aSBaptiste Daroussin 	if (gelf_getehdr(elf, &elfhdr) == NULL) {
1043aa4b42aSBaptiste Daroussin 		ret = -1;
1053aa4b42aSBaptiste Daroussin 		warn("getehdr() failed: %s.", elf_errmsg(-1));
1063aa4b42aSBaptiste Daroussin 		goto cleanup;
1073aa4b42aSBaptiste Daroussin 	}
1083aa4b42aSBaptiste Daroussin 
1093aa4b42aSBaptiste Daroussin 	while ((scn = elf_nextscn(elf, scn)) != NULL) {
1103aa4b42aSBaptiste Daroussin 		if (gelf_getshdr(scn, &shdr) != &shdr) {
1113aa4b42aSBaptiste Daroussin 			ret = -1;
1123aa4b42aSBaptiste Daroussin 			warn("getshdr() failed: %s.", elf_errmsg(-1));
1133aa4b42aSBaptiste Daroussin 			goto cleanup;
1143aa4b42aSBaptiste Daroussin 		}
1153aa4b42aSBaptiste Daroussin 
1163aa4b42aSBaptiste Daroussin 		if (shdr.sh_type == SHT_NOTE)
1173aa4b42aSBaptiste Daroussin 			break;
1183aa4b42aSBaptiste Daroussin 	}
1193aa4b42aSBaptiste Daroussin 
1203aa4b42aSBaptiste Daroussin 	if (scn == NULL) {
1213aa4b42aSBaptiste Daroussin 		ret = -1;
1223aa4b42aSBaptiste Daroussin 		warn("fail to get the note section");
1233aa4b42aSBaptiste Daroussin 		goto cleanup;
1243aa4b42aSBaptiste Daroussin 	}
1253aa4b42aSBaptiste Daroussin 
1263aa4b42aSBaptiste Daroussin 	data = elf_getdata(scn, NULL);
1273aa4b42aSBaptiste Daroussin 	src = data->d_buf;
128ce36f45dSBaptiste Daroussin 	for (;;) {
1293aa4b42aSBaptiste Daroussin 		memcpy(&note, src, sizeof(Elf_Note));
1303aa4b42aSBaptiste Daroussin 		src += sizeof(Elf_Note);
1313aa4b42aSBaptiste Daroussin 		if (note.n_type == NT_VERSION)
1323aa4b42aSBaptiste Daroussin 			break;
1333aa4b42aSBaptiste Daroussin 		src += note.n_namesz + note.n_descsz;
1343aa4b42aSBaptiste Daroussin 	}
1353aa4b42aSBaptiste Daroussin 	osname = src;
1363aa4b42aSBaptiste Daroussin 	src += note.n_namesz;
1373aa4b42aSBaptiste Daroussin 	if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB)
1383aa4b42aSBaptiste Daroussin 		version = be32dec(src);
1393aa4b42aSBaptiste Daroussin 	else
1403aa4b42aSBaptiste Daroussin 		version = le32dec(src);
1413aa4b42aSBaptiste Daroussin 
1423aa4b42aSBaptiste Daroussin 	for (i = 0; osname[i] != '\0'; i++)
1433aa4b42aSBaptiste Daroussin 		osname[i] = (char)tolower(osname[i]);
1443aa4b42aSBaptiste Daroussin 
1453aa4b42aSBaptiste Daroussin 	snprintf(dest, sz, "%s:%d:%s:%s",
146*3b05c2a8SBaptiste Daroussin 	    osname, version / 100000,
1473aa4b42aSBaptiste Daroussin 	    elf_corres_to_string(mach_corres, (int)elfhdr.e_machine),
1483aa4b42aSBaptiste Daroussin 	    elf_corres_to_string(wordsize_corres,
1493aa4b42aSBaptiste Daroussin 	    (int)elfhdr.e_ident[EI_CLASS]));
1503aa4b42aSBaptiste Daroussin 
1513aa4b42aSBaptiste Daroussin 	switch (elfhdr.e_machine) {
1523aa4b42aSBaptiste Daroussin 		case EM_ARM:
1533aa4b42aSBaptiste Daroussin 			snprintf(dest + strlen(dest), sz - strlen(dest),
154*3b05c2a8SBaptiste Daroussin 			    ":%s:%s:%s", elf_corres_to_string(endian_corres,
1553aa4b42aSBaptiste Daroussin 			    (int)elfhdr.e_ident[EI_DATA]),
1563aa4b42aSBaptiste Daroussin 			    (elfhdr.e_flags & EF_ARM_NEW_ABI) > 0 ?
1573aa4b42aSBaptiste Daroussin 			    "eabi" : "oabi",
1583aa4b42aSBaptiste Daroussin 			    (elfhdr.e_flags & EF_ARM_VFP_FLOAT) > 0 ?
1593aa4b42aSBaptiste Daroussin 			    "softfp" : "vfp");
1603aa4b42aSBaptiste Daroussin 			break;
1613aa4b42aSBaptiste Daroussin 		case EM_MIPS:
1623aa4b42aSBaptiste Daroussin 			/*
1633aa4b42aSBaptiste Daroussin 			 * this is taken from binutils sources:
1643aa4b42aSBaptiste Daroussin 			 * include/elf/mips.h
1653aa4b42aSBaptiste Daroussin 			 * mapping is figured out from binutils:
1663aa4b42aSBaptiste Daroussin 			 * gas/config/tc-mips.c
1673aa4b42aSBaptiste Daroussin 			 */
1683aa4b42aSBaptiste Daroussin 			switch (elfhdr.e_flags & EF_MIPS_ABI) {
1693aa4b42aSBaptiste Daroussin 				case E_MIPS_ABI_O32:
1703aa4b42aSBaptiste Daroussin 					abi = "o32";
1713aa4b42aSBaptiste Daroussin 					break;
1723aa4b42aSBaptiste Daroussin 				case E_MIPS_ABI_N32:
1733aa4b42aSBaptiste Daroussin 					abi = "n32";
1743aa4b42aSBaptiste Daroussin 					break;
1753aa4b42aSBaptiste Daroussin 				default:
1763aa4b42aSBaptiste Daroussin 					if (elfhdr.e_ident[EI_DATA] ==
1773aa4b42aSBaptiste Daroussin 					    ELFCLASS32)
1783aa4b42aSBaptiste Daroussin 						abi = "o32";
1793aa4b42aSBaptiste Daroussin 					else if (elfhdr.e_ident[EI_DATA] ==
1803aa4b42aSBaptiste Daroussin 					    ELFCLASS64)
1813aa4b42aSBaptiste Daroussin 						abi = "n64";
1823aa4b42aSBaptiste Daroussin 					break;
1833aa4b42aSBaptiste Daroussin 			}
1843aa4b42aSBaptiste Daroussin 			snprintf(dest + strlen(dest), sz - strlen(dest),
185*3b05c2a8SBaptiste Daroussin 			    ":%s:%s", elf_corres_to_string(endian_corres,
186*3b05c2a8SBaptiste Daroussin 			    (int)elfhdr.e_ident[EI_DATA]), abi);
1873aa4b42aSBaptiste Daroussin 			break;
1883aa4b42aSBaptiste Daroussin 	}
1893aa4b42aSBaptiste Daroussin 
1903aa4b42aSBaptiste Daroussin cleanup:
1913aa4b42aSBaptiste Daroussin 	if (elf != NULL)
1923aa4b42aSBaptiste Daroussin 		elf_end(elf);
1933aa4b42aSBaptiste Daroussin 
1943aa4b42aSBaptiste Daroussin 	close(fd);
1953aa4b42aSBaptiste Daroussin 	return (ret);
1963aa4b42aSBaptiste Daroussin }
1973aa4b42aSBaptiste Daroussin 
1983aa4b42aSBaptiste Daroussin static int
1993aa4b42aSBaptiste Daroussin extract_pkg_static(int fd, char *p, int sz)
2003aa4b42aSBaptiste Daroussin {
2013aa4b42aSBaptiste Daroussin 	struct archive *a;
2023aa4b42aSBaptiste Daroussin 	struct archive_entry *ae;
2033aa4b42aSBaptiste Daroussin 	char *end;
2043aa4b42aSBaptiste Daroussin 	int ret, r;
2053aa4b42aSBaptiste Daroussin 
2063aa4b42aSBaptiste Daroussin 	ret = 0;
2073aa4b42aSBaptiste Daroussin 	a = archive_read_new();
2083aa4b42aSBaptiste Daroussin 	archive_read_support_compression_all(a);
2093aa4b42aSBaptiste Daroussin 	archive_read_support_format_tar(a);
2103aa4b42aSBaptiste Daroussin 
2113aa4b42aSBaptiste Daroussin 	lseek(fd, 0, 0);
2123aa4b42aSBaptiste Daroussin 
2133aa4b42aSBaptiste Daroussin 	if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) {
2143aa4b42aSBaptiste Daroussin 		warnx("archive_read_open_fd: %s",
2153aa4b42aSBaptiste Daroussin 		    archive_error_string(a));
2163aa4b42aSBaptiste Daroussin 		ret = -1;
2173aa4b42aSBaptiste Daroussin 		goto cleanup;
2183aa4b42aSBaptiste Daroussin 	}
2193aa4b42aSBaptiste Daroussin 
2203aa4b42aSBaptiste Daroussin 	ae = NULL;
2213aa4b42aSBaptiste Daroussin 	while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) {
2223aa4b42aSBaptiste Daroussin 		end = strrchr(archive_entry_pathname(ae), '/');
2233aa4b42aSBaptiste Daroussin 		if (end == NULL)
2243aa4b42aSBaptiste Daroussin 			continue;
2253aa4b42aSBaptiste Daroussin 
2263aa4b42aSBaptiste Daroussin 		if (strcmp(end, "/pkg-static") == 0) {
2273aa4b42aSBaptiste Daroussin 			r = archive_read_extract(a, ae,
2283aa4b42aSBaptiste Daroussin 			    ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM |
2293aa4b42aSBaptiste Daroussin 			    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL |
2303aa4b42aSBaptiste Daroussin 			    ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR);
2313aa4b42aSBaptiste Daroussin 			snprintf(p, sz, archive_entry_pathname(ae));
2323aa4b42aSBaptiste Daroussin 			break;
2333aa4b42aSBaptiste Daroussin 		}
2343aa4b42aSBaptiste Daroussin 	}
2353aa4b42aSBaptiste Daroussin 
2363aa4b42aSBaptiste Daroussin 	if (r != ARCHIVE_OK) {
2373aa4b42aSBaptiste Daroussin 		warnx("fail to extract pkg-static");
2383aa4b42aSBaptiste Daroussin 		ret = -1;
2393aa4b42aSBaptiste Daroussin 	}
2403aa4b42aSBaptiste Daroussin 
2413aa4b42aSBaptiste Daroussin cleanup:
2423aa4b42aSBaptiste Daroussin 	archive_read_finish(a);
243*3b05c2a8SBaptiste Daroussin 	return (ret);
2443aa4b42aSBaptiste Daroussin 
2453aa4b42aSBaptiste Daroussin }
2463aa4b42aSBaptiste Daroussin 
2473aa4b42aSBaptiste Daroussin static int
2483aa4b42aSBaptiste Daroussin install_pkg_static(char *path, char *pkgpath)
2493aa4b42aSBaptiste Daroussin {
2503aa4b42aSBaptiste Daroussin 	int pstat;
2513aa4b42aSBaptiste Daroussin 	pid_t pid;
2523aa4b42aSBaptiste Daroussin 
2533aa4b42aSBaptiste Daroussin 	switch ((pid = fork())) {
2543aa4b42aSBaptiste Daroussin 		case -1:
2553aa4b42aSBaptiste Daroussin 			return (-1);
2563aa4b42aSBaptiste Daroussin 		case 0:
257*3b05c2a8SBaptiste Daroussin 			execl(path, "pkg-static", "add", pkgpath,
258*3b05c2a8SBaptiste Daroussin 			    (char *)NULL);
259*3b05c2a8SBaptiste Daroussin 			_exit(1);
2603aa4b42aSBaptiste Daroussin 		default:
2613aa4b42aSBaptiste Daroussin 			break;
2623aa4b42aSBaptiste Daroussin 	}
2633aa4b42aSBaptiste Daroussin 
2643aa4b42aSBaptiste Daroussin 	while (waitpid(pid, &pstat, 0) == -1) {
2653aa4b42aSBaptiste Daroussin 		if (errno != EINTR)
2663aa4b42aSBaptiste Daroussin 			return (-1);
2673aa4b42aSBaptiste Daroussin 	}
2683aa4b42aSBaptiste Daroussin 
2693aa4b42aSBaptiste Daroussin 	return (WEXITSTATUS(pstat));
2703aa4b42aSBaptiste Daroussin }
2713aa4b42aSBaptiste Daroussin 
2723aa4b42aSBaptiste Daroussin static int
2733aa4b42aSBaptiste Daroussin bootstrap_pkg(void)
2743aa4b42aSBaptiste Daroussin {
2753aa4b42aSBaptiste Daroussin 	struct url_stat st;
2763aa4b42aSBaptiste Daroussin 	FILE *remote;
2773aa4b42aSBaptiste Daroussin 	time_t begin_dl;
2783aa4b42aSBaptiste Daroussin 	time_t now;
2793aa4b42aSBaptiste Daroussin 	time_t last = 0;
2803aa4b42aSBaptiste Daroussin 	char url[MAXPATHLEN];
2813aa4b42aSBaptiste Daroussin 	char abi[BUFSIZ];
2823aa4b42aSBaptiste Daroussin 	char tmppkg[MAXPATHLEN];
2833aa4b42aSBaptiste Daroussin 	char buf[10240];
2843aa4b42aSBaptiste Daroussin 	char pkgstatic[MAXPATHLEN];
2853aa4b42aSBaptiste Daroussin 	int fd, retry, ret;
2863aa4b42aSBaptiste Daroussin 	off_t done, r;
2873aa4b42aSBaptiste Daroussin 
2883aa4b42aSBaptiste Daroussin 	done = 0;
2893aa4b42aSBaptiste Daroussin 	ret = 0;
2903aa4b42aSBaptiste Daroussin 	retry = 3;
2913aa4b42aSBaptiste Daroussin 	remote = NULL;
2923aa4b42aSBaptiste Daroussin 
2933aa4b42aSBaptiste Daroussin 	printf("Bootstraping pkg please wait\n");
2943aa4b42aSBaptiste Daroussin 
2953aa4b42aSBaptiste Daroussin 	if (pkg_get_myabi(abi, MAXPATHLEN) != 0) {
2963aa4b42aSBaptiste Daroussin 		warnx("fail to determine my abi");
297*3b05c2a8SBaptiste Daroussin 		return (-1);
2983aa4b42aSBaptiste Daroussin 	}
2993aa4b42aSBaptiste Daroussin 
3003aa4b42aSBaptiste Daroussin 	if (getenv("PACKAGESITE") != NULL) {
3013aa4b42aSBaptiste Daroussin 		snprintf(url, MAXPATHLEN, "%s/pkg.txz",
3023aa4b42aSBaptiste Daroussin 		    getenv("PACKAGESITE"));
3033aa4b42aSBaptiste Daroussin 	} else {
3043aa4b42aSBaptiste Daroussin 		snprintf(url, MAXPATHLEN, "%s/%s/latest/Latest/pkg.txz",
3053aa4b42aSBaptiste Daroussin 		    getenv("PACKAGEROOT") ? getenv("PACKAGEROOT") : _PKGS_URL,
3063aa4b42aSBaptiste Daroussin 		    getenv("ABI") ? getenv("ABI") : abi);
3073aa4b42aSBaptiste Daroussin 	}
3083aa4b42aSBaptiste Daroussin 
3093aa4b42aSBaptiste Daroussin 	snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX",
3103aa4b42aSBaptiste Daroussin 	    getenv("TMPDIR") ? getenv("TMPDIR") : "/tmp");
3113aa4b42aSBaptiste Daroussin 
3123aa4b42aSBaptiste Daroussin 	if ((fd = mkstemp(tmppkg)) == -1) {
3133aa4b42aSBaptiste Daroussin 		warn("mkstemp()");
314*3b05c2a8SBaptiste Daroussin 		return (-1);
3153aa4b42aSBaptiste Daroussin 	}
3163aa4b42aSBaptiste Daroussin 
3173aa4b42aSBaptiste Daroussin 	while (remote == NULL) {
3183aa4b42aSBaptiste Daroussin 		remote = fetchXGetURL(url, &st, "");
3193aa4b42aSBaptiste Daroussin 		if (remote == NULL) {
3203aa4b42aSBaptiste Daroussin 			--retry;
3213aa4b42aSBaptiste Daroussin 			if (retry == 0) {
3223aa4b42aSBaptiste Daroussin 				warnx("Error fetching %s: %s", url,
3233aa4b42aSBaptiste Daroussin 				    fetchLastErrString);
3243aa4b42aSBaptiste Daroussin 				ret = 1;
3253aa4b42aSBaptiste Daroussin 				goto cleanup;
3263aa4b42aSBaptiste Daroussin 			}
3273aa4b42aSBaptiste Daroussin 			sleep(1);
3283aa4b42aSBaptiste Daroussin 		}
3293aa4b42aSBaptiste Daroussin 	}
3303aa4b42aSBaptiste Daroussin 
3313aa4b42aSBaptiste Daroussin 	begin_dl = time(NULL);
3323aa4b42aSBaptiste Daroussin 	while (done < st.size) {
3333aa4b42aSBaptiste Daroussin 		if ((r = fread(buf, 1, sizeof(buf), remote)) < 1)
3343aa4b42aSBaptiste Daroussin 			break;
3353aa4b42aSBaptiste Daroussin 
3363aa4b42aSBaptiste Daroussin 		if (write(fd, buf, r) != r) {
3373aa4b42aSBaptiste Daroussin 			warn("write()");
3383aa4b42aSBaptiste Daroussin 			ret = -1;
3393aa4b42aSBaptiste Daroussin 			goto cleanup;
3403aa4b42aSBaptiste Daroussin 		}
3413aa4b42aSBaptiste Daroussin 
3423aa4b42aSBaptiste Daroussin 		done += r;
3433aa4b42aSBaptiste Daroussin 		now = time(NULL);
3443aa4b42aSBaptiste Daroussin 		if (now > last || done == st.size) {
3453aa4b42aSBaptiste Daroussin 			last = now;
3463aa4b42aSBaptiste Daroussin 		}
3473aa4b42aSBaptiste Daroussin 	}
3483aa4b42aSBaptiste Daroussin 
3493aa4b42aSBaptiste Daroussin 	if (ferror(remote)) {
3503aa4b42aSBaptiste Daroussin 		warnx("Error fetching %s: %s", url,
3513aa4b42aSBaptiste Daroussin 		    fetchLastErrString);
3523aa4b42aSBaptiste Daroussin 		ret = 1;
3533aa4b42aSBaptiste Daroussin 		goto cleanup;
3543aa4b42aSBaptiste Daroussin 	}
3553aa4b42aSBaptiste Daroussin 
3563aa4b42aSBaptiste Daroussin 	if ((ret = extract_pkg_static(fd, pkgstatic, MAXPATHLEN)) == 0)
3573aa4b42aSBaptiste Daroussin 		ret = install_pkg_static(pkgstatic, tmppkg);
3583aa4b42aSBaptiste Daroussin 
3593aa4b42aSBaptiste Daroussin cleanup:
3603aa4b42aSBaptiste Daroussin 	close(fd);
3613aa4b42aSBaptiste Daroussin 	unlink(tmppkg);
3623aa4b42aSBaptiste Daroussin 
363*3b05c2a8SBaptiste Daroussin 	return (0);
3643aa4b42aSBaptiste Daroussin }
3653aa4b42aSBaptiste Daroussin 
3663aa4b42aSBaptiste Daroussin int
3673aa4b42aSBaptiste Daroussin main(__unused int argc, char *argv[])
3683aa4b42aSBaptiste Daroussin {
3693aa4b42aSBaptiste Daroussin 	char pkgpath[MAXPATHLEN];
3703aa4b42aSBaptiste Daroussin 
3713aa4b42aSBaptiste Daroussin 	snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg",
3723aa4b42aSBaptiste Daroussin 	    getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE);
3733aa4b42aSBaptiste Daroussin 
3743aa4b42aSBaptiste Daroussin 	if (access(pkgpath, X_OK) == -1)
3753aa4b42aSBaptiste Daroussin 		bootstrap_pkg();
3763aa4b42aSBaptiste Daroussin 
3773aa4b42aSBaptiste Daroussin 	execv(pkgpath, argv);
3783aa4b42aSBaptiste Daroussin 
379*3b05c2a8SBaptiste Daroussin 	return (EXIT_FAILURE);
3803aa4b42aSBaptiste Daroussin }
381