xref: /freebsd/usr.sbin/pkg/pkg.c (revision e41b8acbd5ef6a61e74b35b39a63ed3169aee4c6)
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>
333b05c2a8SBaptiste 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>
413b05c2a8SBaptiste Daroussin #include <fetch.h>
423aa4b42aSBaptiste Daroussin #include <gelf.h>
43a6454741SBaptiste Daroussin #include <paths.h>
443aa4b42aSBaptiste Daroussin #include <stdlib.h>
453aa4b42aSBaptiste Daroussin #include <stdio.h>
463aa4b42aSBaptiste Daroussin #include <string.h>
473aa4b42aSBaptiste Daroussin #include <time.h>
483aa4b42aSBaptiste Daroussin #include <unistd.h>
493aa4b42aSBaptiste Daroussin 
503aa4b42aSBaptiste Daroussin #include "elf_tables.h"
5129aaa961SBaptiste Daroussin #include "dns_utils.h"
523aa4b42aSBaptiste Daroussin 
533aa4b42aSBaptiste Daroussin #define _LOCALBASE "/usr/local"
5429aaa961SBaptiste Daroussin #define _PKGS_URL "http://pkg.FreeBSD.org"
553aa4b42aSBaptiste Daroussin 
563aa4b42aSBaptiste Daroussin static const char *
573aa4b42aSBaptiste Daroussin elf_corres_to_string(struct _elf_corres *m, int e)
583aa4b42aSBaptiste Daroussin {
59ce36f45dSBaptiste Daroussin 	int i;
603aa4b42aSBaptiste Daroussin 
613aa4b42aSBaptiste Daroussin 	for (i = 0; m[i].string != NULL; i++)
623aa4b42aSBaptiste Daroussin 		if (m[i].elf_nb == e)
633aa4b42aSBaptiste Daroussin 			return (m[i].string);
643aa4b42aSBaptiste Daroussin 
653aa4b42aSBaptiste Daroussin 	return ("unknown");
663aa4b42aSBaptiste Daroussin }
673aa4b42aSBaptiste Daroussin 
683aa4b42aSBaptiste Daroussin static int
693aa4b42aSBaptiste Daroussin pkg_get_myabi(char *dest, size_t sz)
703aa4b42aSBaptiste Daroussin {
713aa4b42aSBaptiste Daroussin 	Elf *elf;
723aa4b42aSBaptiste Daroussin 	Elf_Data *data;
733aa4b42aSBaptiste Daroussin 	Elf_Note note;
743aa4b42aSBaptiste Daroussin 	Elf_Scn *scn;
753aa4b42aSBaptiste Daroussin 	char *src, *osname;
763aa4b42aSBaptiste Daroussin 	const char *abi;
77a6454741SBaptiste Daroussin 	GElf_Ehdr elfhdr;
78a6454741SBaptiste Daroussin 	GElf_Shdr shdr;
793aa4b42aSBaptiste Daroussin 	int fd, i, ret;
803aa4b42aSBaptiste Daroussin 	uint32_t version;
813aa4b42aSBaptiste Daroussin 
823aa4b42aSBaptiste Daroussin 	version = 0;
83a6454741SBaptiste Daroussin 	ret = -1;
843aa4b42aSBaptiste Daroussin 	scn = NULL;
853aa4b42aSBaptiste Daroussin 	abi = NULL;
863aa4b42aSBaptiste Daroussin 
873aa4b42aSBaptiste Daroussin 	if (elf_version(EV_CURRENT) == EV_NONE) {
883b05c2a8SBaptiste Daroussin 		warnx("ELF library initialization failed: %s",
893b05c2a8SBaptiste Daroussin 		    elf_errmsg(-1));
903b05c2a8SBaptiste Daroussin 		return (-1);
913aa4b42aSBaptiste Daroussin 	}
923aa4b42aSBaptiste Daroussin 
933aa4b42aSBaptiste Daroussin 	if ((fd = open("/bin/sh", O_RDONLY)) < 0) {
943aa4b42aSBaptiste Daroussin 		warn("open()");
953b05c2a8SBaptiste Daroussin 		return (-1);
963aa4b42aSBaptiste Daroussin 	}
973aa4b42aSBaptiste Daroussin 
983aa4b42aSBaptiste Daroussin 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
993aa4b42aSBaptiste Daroussin 		ret = -1;
1003aa4b42aSBaptiste Daroussin 		warnx("elf_begin() failed: %s.", elf_errmsg(-1));
1013aa4b42aSBaptiste Daroussin 		goto cleanup;
1023aa4b42aSBaptiste Daroussin 	}
1033aa4b42aSBaptiste Daroussin 
1043aa4b42aSBaptiste Daroussin 	if (gelf_getehdr(elf, &elfhdr) == NULL) {
1053aa4b42aSBaptiste Daroussin 		ret = -1;
1063aa4b42aSBaptiste Daroussin 		warn("getehdr() failed: %s.", elf_errmsg(-1));
1073aa4b42aSBaptiste Daroussin 		goto cleanup;
1083aa4b42aSBaptiste Daroussin 	}
1093aa4b42aSBaptiste Daroussin 
1103aa4b42aSBaptiste Daroussin 	while ((scn = elf_nextscn(elf, scn)) != NULL) {
1113aa4b42aSBaptiste Daroussin 		if (gelf_getshdr(scn, &shdr) != &shdr) {
1123aa4b42aSBaptiste Daroussin 			ret = -1;
1133aa4b42aSBaptiste Daroussin 			warn("getshdr() failed: %s.", elf_errmsg(-1));
1143aa4b42aSBaptiste Daroussin 			goto cleanup;
1153aa4b42aSBaptiste Daroussin 		}
1163aa4b42aSBaptiste Daroussin 
1173aa4b42aSBaptiste Daroussin 		if (shdr.sh_type == SHT_NOTE)
1183aa4b42aSBaptiste Daroussin 			break;
1193aa4b42aSBaptiste Daroussin 	}
1203aa4b42aSBaptiste Daroussin 
1213aa4b42aSBaptiste Daroussin 	if (scn == NULL) {
1223aa4b42aSBaptiste Daroussin 		ret = -1;
123a6454741SBaptiste Daroussin 		warn("failed to get the note section");
1243aa4b42aSBaptiste Daroussin 		goto cleanup;
1253aa4b42aSBaptiste Daroussin 	}
1263aa4b42aSBaptiste Daroussin 
1273aa4b42aSBaptiste Daroussin 	data = elf_getdata(scn, NULL);
1283aa4b42aSBaptiste Daroussin 	src = data->d_buf;
129ce36f45dSBaptiste Daroussin 	for (;;) {
1303aa4b42aSBaptiste Daroussin 		memcpy(&note, src, sizeof(Elf_Note));
1313aa4b42aSBaptiste Daroussin 		src += sizeof(Elf_Note);
1323aa4b42aSBaptiste Daroussin 		if (note.n_type == NT_VERSION)
1333aa4b42aSBaptiste Daroussin 			break;
1343aa4b42aSBaptiste Daroussin 		src += note.n_namesz + note.n_descsz;
1353aa4b42aSBaptiste Daroussin 	}
1363aa4b42aSBaptiste Daroussin 	osname = src;
1373aa4b42aSBaptiste Daroussin 	src += note.n_namesz;
1383aa4b42aSBaptiste Daroussin 	if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB)
1393aa4b42aSBaptiste Daroussin 		version = be32dec(src);
1403aa4b42aSBaptiste Daroussin 	else
1413aa4b42aSBaptiste Daroussin 		version = le32dec(src);
1423aa4b42aSBaptiste Daroussin 
1433aa4b42aSBaptiste Daroussin 	for (i = 0; osname[i] != '\0'; i++)
1443aa4b42aSBaptiste Daroussin 		osname[i] = (char)tolower(osname[i]);
1453aa4b42aSBaptiste Daroussin 
1463aa4b42aSBaptiste Daroussin 	snprintf(dest, sz, "%s:%d:%s:%s",
1473b05c2a8SBaptiste Daroussin 	    osname, version / 100000,
1483aa4b42aSBaptiste Daroussin 	    elf_corres_to_string(mach_corres, (int)elfhdr.e_machine),
1493aa4b42aSBaptiste Daroussin 	    elf_corres_to_string(wordsize_corres,
1503aa4b42aSBaptiste Daroussin 	    (int)elfhdr.e_ident[EI_CLASS]));
1513aa4b42aSBaptiste Daroussin 
152a6454741SBaptiste Daroussin 	ret = 0;
153a6454741SBaptiste Daroussin 
1543aa4b42aSBaptiste Daroussin 	switch (elfhdr.e_machine) {
1553aa4b42aSBaptiste Daroussin 	case EM_ARM:
1563aa4b42aSBaptiste Daroussin 		snprintf(dest + strlen(dest), sz - strlen(dest),
1573b05c2a8SBaptiste Daroussin 		    ":%s:%s:%s", elf_corres_to_string(endian_corres,
1583aa4b42aSBaptiste Daroussin 		    (int)elfhdr.e_ident[EI_DATA]),
1593aa4b42aSBaptiste Daroussin 		    (elfhdr.e_flags & EF_ARM_NEW_ABI) > 0 ?
1603aa4b42aSBaptiste Daroussin 		    "eabi" : "oabi",
1613aa4b42aSBaptiste Daroussin 		    (elfhdr.e_flags & EF_ARM_VFP_FLOAT) > 0 ?
1623aa4b42aSBaptiste Daroussin 		    "softfp" : "vfp");
1633aa4b42aSBaptiste Daroussin 		break;
1643aa4b42aSBaptiste Daroussin 	case EM_MIPS:
1653aa4b42aSBaptiste Daroussin 		/*
1663aa4b42aSBaptiste Daroussin 		 * this is taken from binutils sources:
1673aa4b42aSBaptiste Daroussin 		 * include/elf/mips.h
1683aa4b42aSBaptiste Daroussin 		 * mapping is figured out from binutils:
1693aa4b42aSBaptiste Daroussin 		 * gas/config/tc-mips.c
1703aa4b42aSBaptiste Daroussin 		 */
1713aa4b42aSBaptiste Daroussin 		switch (elfhdr.e_flags & EF_MIPS_ABI) {
1723aa4b42aSBaptiste Daroussin 		case E_MIPS_ABI_O32:
1733aa4b42aSBaptiste Daroussin 			abi = "o32";
1743aa4b42aSBaptiste Daroussin 			break;
1753aa4b42aSBaptiste Daroussin 		case E_MIPS_ABI_N32:
1763aa4b42aSBaptiste Daroussin 			abi = "n32";
1773aa4b42aSBaptiste Daroussin 			break;
1783aa4b42aSBaptiste Daroussin 		default:
1793aa4b42aSBaptiste Daroussin 			if (elfhdr.e_ident[EI_DATA] ==
1803aa4b42aSBaptiste Daroussin 			    ELFCLASS32)
1813aa4b42aSBaptiste Daroussin 				abi = "o32";
1823aa4b42aSBaptiste Daroussin 			else if (elfhdr.e_ident[EI_DATA] ==
1833aa4b42aSBaptiste Daroussin 			    ELFCLASS64)
1843aa4b42aSBaptiste Daroussin 				abi = "n64";
1853aa4b42aSBaptiste Daroussin 			break;
1863aa4b42aSBaptiste Daroussin 		}
1873aa4b42aSBaptiste Daroussin 		snprintf(dest + strlen(dest), sz - strlen(dest),
1883b05c2a8SBaptiste Daroussin 		    ":%s:%s", elf_corres_to_string(endian_corres,
1893b05c2a8SBaptiste Daroussin 		    (int)elfhdr.e_ident[EI_DATA]), abi);
1903aa4b42aSBaptiste Daroussin 		break;
1913aa4b42aSBaptiste Daroussin 	}
1923aa4b42aSBaptiste Daroussin 
1933aa4b42aSBaptiste Daroussin cleanup:
1943aa4b42aSBaptiste Daroussin 	if (elf != NULL)
1953aa4b42aSBaptiste Daroussin 		elf_end(elf);
1963aa4b42aSBaptiste Daroussin 
1973aa4b42aSBaptiste Daroussin 	close(fd);
1983aa4b42aSBaptiste Daroussin 	return (ret);
1993aa4b42aSBaptiste Daroussin }
2003aa4b42aSBaptiste Daroussin 
2013aa4b42aSBaptiste Daroussin static int
2023aa4b42aSBaptiste Daroussin extract_pkg_static(int fd, char *p, int sz)
2033aa4b42aSBaptiste Daroussin {
2043aa4b42aSBaptiste Daroussin 	struct archive *a;
2053aa4b42aSBaptiste Daroussin 	struct archive_entry *ae;
2063aa4b42aSBaptiste Daroussin 	char *end;
2073aa4b42aSBaptiste Daroussin 	int ret, r;
2083aa4b42aSBaptiste Daroussin 
209a6454741SBaptiste Daroussin 	ret = -1;
2103aa4b42aSBaptiste Daroussin 	a = archive_read_new();
211a6454741SBaptiste Daroussin 	if (a == NULL) {
212a6454741SBaptiste Daroussin 		warn("archive_read_new");
213a6454741SBaptiste Daroussin 		return (ret);
214a6454741SBaptiste Daroussin 	}
2153aa4b42aSBaptiste Daroussin 	archive_read_support_compression_all(a);
2163aa4b42aSBaptiste Daroussin 	archive_read_support_format_tar(a);
2173aa4b42aSBaptiste Daroussin 
218a6454741SBaptiste Daroussin 	if (lseek(fd, 0, 0) == -1) {
219a6454741SBaptiste Daroussin 		warn("lseek");
220a6454741SBaptiste Daroussin 		goto cleanup;
221a6454741SBaptiste Daroussin 	}
2223aa4b42aSBaptiste Daroussin 
2233aa4b42aSBaptiste Daroussin 	if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) {
224a6454741SBaptiste Daroussin 		warnx("archive_read_open_fd: %s", archive_error_string(a));
2253aa4b42aSBaptiste Daroussin 		goto cleanup;
2263aa4b42aSBaptiste Daroussin 	}
2273aa4b42aSBaptiste Daroussin 
2283aa4b42aSBaptiste Daroussin 	ae = NULL;
2293aa4b42aSBaptiste Daroussin 	while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) {
2303aa4b42aSBaptiste Daroussin 		end = strrchr(archive_entry_pathname(ae), '/');
2313aa4b42aSBaptiste Daroussin 		if (end == NULL)
2323aa4b42aSBaptiste Daroussin 			continue;
2333aa4b42aSBaptiste Daroussin 
2343aa4b42aSBaptiste Daroussin 		if (strcmp(end, "/pkg-static") == 0) {
2353aa4b42aSBaptiste Daroussin 			r = archive_read_extract(a, ae,
2363aa4b42aSBaptiste Daroussin 			    ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM |
2373aa4b42aSBaptiste Daroussin 			    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL |
2383aa4b42aSBaptiste Daroussin 			    ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR);
239a6454741SBaptiste Daroussin 			strlcpy(p, archive_entry_pathname(ae), sz);
2403aa4b42aSBaptiste Daroussin 			break;
2413aa4b42aSBaptiste Daroussin 		}
2423aa4b42aSBaptiste Daroussin 	}
2433aa4b42aSBaptiste Daroussin 
244a6454741SBaptiste Daroussin 	if (r == ARCHIVE_OK)
245a6454741SBaptiste Daroussin 		ret = 0;
246a6454741SBaptiste Daroussin 	else
2473aa4b42aSBaptiste Daroussin 		warnx("fail to extract pkg-static");
2483aa4b42aSBaptiste Daroussin 
2493aa4b42aSBaptiste Daroussin cleanup:
2503aa4b42aSBaptiste Daroussin 	archive_read_finish(a);
2513b05c2a8SBaptiste Daroussin 	return (ret);
2523aa4b42aSBaptiste Daroussin 
2533aa4b42aSBaptiste Daroussin }
2543aa4b42aSBaptiste Daroussin 
2553aa4b42aSBaptiste Daroussin static int
2563aa4b42aSBaptiste Daroussin install_pkg_static(char *path, char *pkgpath)
2573aa4b42aSBaptiste Daroussin {
2583aa4b42aSBaptiste Daroussin 	int pstat;
2593aa4b42aSBaptiste Daroussin 	pid_t pid;
2603aa4b42aSBaptiste Daroussin 
2613aa4b42aSBaptiste Daroussin 	switch ((pid = fork())) {
2623aa4b42aSBaptiste Daroussin 	case -1:
2633aa4b42aSBaptiste Daroussin 		return (-1);
2643aa4b42aSBaptiste Daroussin 	case 0:
265a6454741SBaptiste Daroussin 		execl(path, "pkg-static", "add", pkgpath, (char *)NULL);
2663b05c2a8SBaptiste Daroussin 		_exit(1);
2673aa4b42aSBaptiste Daroussin 	default:
2683aa4b42aSBaptiste Daroussin 		break;
2693aa4b42aSBaptiste Daroussin 	}
2703aa4b42aSBaptiste Daroussin 
271a6454741SBaptiste Daroussin 	while (waitpid(pid, &pstat, 0) == -1)
2723aa4b42aSBaptiste Daroussin 		if (errno != EINTR)
2733aa4b42aSBaptiste Daroussin 			return (-1);
2743aa4b42aSBaptiste Daroussin 
275a6454741SBaptiste Daroussin 	if (WEXITSTATUS(pstat))
2763aa4b42aSBaptiste Daroussin 		return (WEXITSTATUS(pstat));
277a6454741SBaptiste Daroussin 	else if (WIFSIGNALED(pstat))
278a6454741SBaptiste Daroussin 		return (128 & (WTERMSIG(pstat)));
279a6454741SBaptiste Daroussin 	return (pstat);
2803aa4b42aSBaptiste Daroussin }
2813aa4b42aSBaptiste Daroussin 
2823aa4b42aSBaptiste Daroussin static int
2833aa4b42aSBaptiste Daroussin bootstrap_pkg(void)
2843aa4b42aSBaptiste Daroussin {
28529aaa961SBaptiste Daroussin 	struct url *u;
2863aa4b42aSBaptiste Daroussin 	FILE *remote;
2872fe3761eSBaptiste Daroussin 	FILE *config;
2882fe3761eSBaptiste Daroussin 	char *site;
28929aaa961SBaptiste Daroussin 	struct dns_srvinfo *mirrors, *current;
29029aaa961SBaptiste Daroussin 	/* To store _https._tcp. + hostname + \0 */
29129aaa961SBaptiste Daroussin 	char zone[MAXHOSTNAMELEN + 13];
2923aa4b42aSBaptiste Daroussin 	char url[MAXPATHLEN];
2932fe3761eSBaptiste Daroussin 	char conf[MAXPATHLEN];
2943aa4b42aSBaptiste Daroussin 	char abi[BUFSIZ];
2953aa4b42aSBaptiste Daroussin 	char tmppkg[MAXPATHLEN];
2963aa4b42aSBaptiste Daroussin 	char buf[10240];
2973aa4b42aSBaptiste Daroussin 	char pkgstatic[MAXPATHLEN];
29829aaa961SBaptiste Daroussin 	int fd, retry, ret, max_retry;
299a6454741SBaptiste Daroussin 	struct url_stat st;
3003aa4b42aSBaptiste Daroussin 	off_t done, r;
301a6454741SBaptiste Daroussin 	time_t now;
302a6454741SBaptiste Daroussin 	time_t last;
3033aa4b42aSBaptiste Daroussin 
3043aa4b42aSBaptiste Daroussin 	done = 0;
305a6454741SBaptiste Daroussin 	last = 0;
30629aaa961SBaptiste Daroussin 	max_retry = 3;
307a6454741SBaptiste Daroussin 	ret = -1;
3083aa4b42aSBaptiste Daroussin 	remote = NULL;
3092fe3761eSBaptiste Daroussin 	config = NULL;
31029aaa961SBaptiste Daroussin 	current = mirrors = NULL;
3113aa4b42aSBaptiste Daroussin 
312a6454741SBaptiste Daroussin 	printf("Bootstrapping pkg please wait\n");
3133aa4b42aSBaptiste Daroussin 
3143aa4b42aSBaptiste Daroussin 	if (pkg_get_myabi(abi, MAXPATHLEN) != 0) {
315a6454741SBaptiste Daroussin 		warnx("failed to determine the system ABI");
3163b05c2a8SBaptiste Daroussin 		return (-1);
3173aa4b42aSBaptiste Daroussin 	}
3183aa4b42aSBaptiste Daroussin 
319a6454741SBaptiste Daroussin 	if (getenv("PACKAGESITE") != NULL)
3202fe3761eSBaptiste Daroussin 		snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", getenv("PACKAGESITE"));
321a6454741SBaptiste Daroussin 	else
3223aa4b42aSBaptiste Daroussin 		snprintf(url, MAXPATHLEN, "%s/%s/latest/Latest/pkg.txz",
3233aa4b42aSBaptiste Daroussin 		    getenv("PACKAGEROOT") ? getenv("PACKAGEROOT") : _PKGS_URL,
3243aa4b42aSBaptiste Daroussin 		    getenv("ABI") ? getenv("ABI") : abi);
3253aa4b42aSBaptiste Daroussin 
3263aa4b42aSBaptiste Daroussin 	snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX",
327a6454741SBaptiste Daroussin 	    getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
3283aa4b42aSBaptiste Daroussin 
3293aa4b42aSBaptiste Daroussin 	if ((fd = mkstemp(tmppkg)) == -1) {
3303aa4b42aSBaptiste Daroussin 		warn("mkstemp()");
3313b05c2a8SBaptiste Daroussin 		return (-1);
3323aa4b42aSBaptiste Daroussin 	}
3333aa4b42aSBaptiste Daroussin 
33429aaa961SBaptiste Daroussin 	retry = max_retry;
33529aaa961SBaptiste Daroussin 
33629aaa961SBaptiste Daroussin 	u = fetchParseURL(url);
33729aaa961SBaptiste Daroussin 	while (remote == NULL) {
33829aaa961SBaptiste Daroussin 		if (retry == max_retry) {
33929aaa961SBaptiste Daroussin 			if (strcmp(u->scheme, "file") != 0) {
34029aaa961SBaptiste Daroussin 				snprintf(zone, sizeof(zone),
34129aaa961SBaptiste Daroussin 				    "_%s._tcp.%s", u->scheme, u->host);
34229aaa961SBaptiste Daroussin 				printf("%s\n", zone);
34329aaa961SBaptiste Daroussin 				mirrors = dns_getsrvinfo(zone);
34429aaa961SBaptiste Daroussin 				current = mirrors;
34529aaa961SBaptiste Daroussin 			}
34629aaa961SBaptiste Daroussin 		}
34729aaa961SBaptiste Daroussin 
34829aaa961SBaptiste Daroussin 		if (mirrors != NULL)
34929aaa961SBaptiste Daroussin 			strlcpy(u->host, current->host, sizeof(u->host));
35029aaa961SBaptiste Daroussin 
35129aaa961SBaptiste Daroussin 		remote = fetchXGet(u, &st, "");
35229aaa961SBaptiste Daroussin 		if (remote == NULL) {
35329aaa961SBaptiste Daroussin 			--retry;
35429aaa961SBaptiste Daroussin 			if (retry <= 0)
35529aaa961SBaptiste Daroussin 				goto fetchfail;
35629aaa961SBaptiste Daroussin 			if (mirrors == NULL) {
3573aa4b42aSBaptiste Daroussin 				sleep(1);
35829aaa961SBaptiste Daroussin 			} else {
35929aaa961SBaptiste Daroussin 				current = current->next;
36029aaa961SBaptiste Daroussin 				if (current == NULL)
36129aaa961SBaptiste Daroussin 					current = mirrors;
36229aaa961SBaptiste Daroussin 			}
36329aaa961SBaptiste Daroussin 		}
36429aaa961SBaptiste Daroussin 	}
365a6454741SBaptiste Daroussin 
366a6454741SBaptiste Daroussin 	if (remote == NULL)
367a6454741SBaptiste Daroussin 		goto fetchfail;
3683aa4b42aSBaptiste Daroussin 
3693aa4b42aSBaptiste Daroussin 	while (done < st.size) {
3703aa4b42aSBaptiste Daroussin 		if ((r = fread(buf, 1, sizeof(buf), remote)) < 1)
3713aa4b42aSBaptiste Daroussin 			break;
3723aa4b42aSBaptiste Daroussin 
3733aa4b42aSBaptiste Daroussin 		if (write(fd, buf, r) != r) {
3743aa4b42aSBaptiste Daroussin 			warn("write()");
3753aa4b42aSBaptiste Daroussin 			goto cleanup;
3763aa4b42aSBaptiste Daroussin 		}
3773aa4b42aSBaptiste Daroussin 
3783aa4b42aSBaptiste Daroussin 		done += r;
3793aa4b42aSBaptiste Daroussin 		now = time(NULL);
380a6454741SBaptiste Daroussin 		if (now > last || done == st.size)
3813aa4b42aSBaptiste Daroussin 			last = now;
3823aa4b42aSBaptiste Daroussin 	}
3833aa4b42aSBaptiste Daroussin 
384a6454741SBaptiste Daroussin 	if (ferror(remote))
385a6454741SBaptiste Daroussin 		goto fetchfail;
3863aa4b42aSBaptiste Daroussin 
3873aa4b42aSBaptiste Daroussin 	if ((ret = extract_pkg_static(fd, pkgstatic, MAXPATHLEN)) == 0)
3883aa4b42aSBaptiste Daroussin 		ret = install_pkg_static(pkgstatic, tmppkg);
3893aa4b42aSBaptiste Daroussin 
3902fe3761eSBaptiste Daroussin 	snprintf(conf, MAXPATHLEN, "%s/etc/pkg.conf",
3912fe3761eSBaptiste Daroussin 	    getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE);
3922fe3761eSBaptiste Daroussin 
3932fe3761eSBaptiste Daroussin 	if (access(conf, R_OK) == -1) {
3942fe3761eSBaptiste Daroussin 		site = strrchr(url, '/');
3952fe3761eSBaptiste Daroussin 		if (site == NULL)
3962fe3761eSBaptiste Daroussin 			goto cleanup;
3972fe3761eSBaptiste Daroussin 		site[0] = '\0';
3982fe3761eSBaptiste Daroussin 		site = strrchr(url, '/');
3992fe3761eSBaptiste Daroussin 		if (site == NULL)
4002fe3761eSBaptiste Daroussin 			goto cleanup;
4012fe3761eSBaptiste Daroussin 		site[0] = '\0';
4022fe3761eSBaptiste Daroussin 
4032fe3761eSBaptiste Daroussin 		config = fopen(conf, "w+");
4042fe3761eSBaptiste Daroussin 		if (config == NULL)
4052fe3761eSBaptiste Daroussin 			goto cleanup;
406514ead92SBaptiste Daroussin 		fprintf(config, "packagesite: %s\n", url);
4072fe3761eSBaptiste Daroussin 		fclose(config);
4082fe3761eSBaptiste Daroussin 	}
4092fe3761eSBaptiste Daroussin 
410a6454741SBaptiste Daroussin 	goto cleanup;
411a6454741SBaptiste Daroussin 
412a6454741SBaptiste Daroussin fetchfail:
413a6454741SBaptiste Daroussin 	warnx("Error fetching %s: %s", url, fetchLastErrString);
414a6454741SBaptiste Daroussin 
4153aa4b42aSBaptiste Daroussin cleanup:
4162fe3761eSBaptiste Daroussin 	if (remote != NULL)
4172fe3761eSBaptiste Daroussin 		fclose(remote);
4183aa4b42aSBaptiste Daroussin 	close(fd);
4193aa4b42aSBaptiste Daroussin 	unlink(tmppkg);
4203aa4b42aSBaptiste Daroussin 
421a6454741SBaptiste Daroussin 	return (ret);
4223aa4b42aSBaptiste Daroussin }
4233aa4b42aSBaptiste Daroussin 
424e18ad51cSAlexander Kabaev static const char confirmation_message[] =
425e18ad51cSAlexander Kabaev "The package management tool is not yet installed on your system.\n"
426e18ad51cSAlexander Kabaev "Do you want to fetch and install it now? [y/N]: ";
427e18ad51cSAlexander Kabaev 
428e18ad51cSAlexander Kabaev static int
429e18ad51cSAlexander Kabaev pkg_query_yes_no(void)
430e18ad51cSAlexander Kabaev {
431e18ad51cSAlexander Kabaev 	int ret, c;
432e18ad51cSAlexander Kabaev 
433e18ad51cSAlexander Kabaev 	c = getchar();
434e18ad51cSAlexander Kabaev 
435e18ad51cSAlexander Kabaev 	if (c == 'y' || c == 'Y')
436e18ad51cSAlexander Kabaev 		ret = 1;
437e18ad51cSAlexander Kabaev 	else
438e18ad51cSAlexander Kabaev 		ret = 0;
439e18ad51cSAlexander Kabaev 
440e18ad51cSAlexander Kabaev 	while (c != '\n' && c != EOF)
441e18ad51cSAlexander Kabaev 		c = getchar();
442e18ad51cSAlexander Kabaev 
443e18ad51cSAlexander Kabaev 	return (ret);
444e18ad51cSAlexander Kabaev }
445e18ad51cSAlexander Kabaev 
4463aa4b42aSBaptiste Daroussin int
4473aa4b42aSBaptiste Daroussin main(__unused int argc, char *argv[])
4483aa4b42aSBaptiste Daroussin {
4493aa4b42aSBaptiste Daroussin 	char pkgpath[MAXPATHLEN];
4503aa4b42aSBaptiste Daroussin 
4513aa4b42aSBaptiste Daroussin 	snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg",
4523aa4b42aSBaptiste Daroussin 	    getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE);
4533aa4b42aSBaptiste Daroussin 
454e18ad51cSAlexander Kabaev 	if (access(pkgpath, X_OK) == -1) {
455e18ad51cSAlexander Kabaev 		/*
456d482e1f4SMatthew Seaman 		 * To allow 'pkg -N' to be used as a reliable test for whether
457ecfed9f2SMatthew Seaman 		 * a system is configured to use pkg, don't bootstrap pkg
458ecfed9f2SMatthew Seaman 		 * when that argument is given as argv[1].
459ecfed9f2SMatthew Seaman 		 */
460d8f9490cSMatthew Seaman 		if (argv[1] != NULL && strcmp(argv[1], "-N") == 0)
461*e41b8acbSMatthew Seaman 			errx(EXIT_FAILURE, "pkg is not installed");
462ecfed9f2SMatthew Seaman 
463ecfed9f2SMatthew Seaman 		/*
464e18ad51cSAlexander Kabaev 		 * Do not ask for confirmation if either of stdin or stdout is
465e18ad51cSAlexander Kabaev 		 * not tty. Check the environment to see if user has answer
466e18ad51cSAlexander Kabaev 		 * tucked in there already.
467e18ad51cSAlexander Kabaev 		 */
4683a480126SBaptiste Daroussin 		if (getenv("ASSUME_ALWAYS_YES") == NULL) {
469e18ad51cSAlexander Kabaev 			printf("%s", confirmation_message);
470204ea792SBaptiste Daroussin 			if (!isatty(fileno(stdin)))
4713a480126SBaptiste Daroussin 				exit(EXIT_FAILURE);
472204ea792SBaptiste Daroussin 
473204ea792SBaptiste Daroussin 			if (pkg_query_yes_no() == 0)
474e18ad51cSAlexander Kabaev 				exit(EXIT_FAILURE);
475e18ad51cSAlexander Kabaev 		}
476a6454741SBaptiste Daroussin 		if (bootstrap_pkg() != 0)
477a6454741SBaptiste Daroussin 			exit(EXIT_FAILURE);
478e18ad51cSAlexander Kabaev 	}
4793aa4b42aSBaptiste Daroussin 
4803aa4b42aSBaptiste Daroussin 	execv(pkgpath, argv);
4813aa4b42aSBaptiste Daroussin 
482a6454741SBaptiste Daroussin 	/* NOT REACHED */
4833b05c2a8SBaptiste Daroussin 	return (EXIT_FAILURE);
4843aa4b42aSBaptiste Daroussin }
485