xref: /freebsd/usr.sbin/pkg/pkg.c (revision b70213b5c71b58f032bce1ead254669b1f4e6233)
13aa4b42aSBaptiste Daroussin /*-
29950eceeSBaptiste Daroussin  * Copyright (c) 2012-2013 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>
313b05c2a8SBaptiste Daroussin #include <sys/wait.h>
323aa4b42aSBaptiste Daroussin 
333aa4b42aSBaptiste Daroussin #include <archive.h>
343aa4b42aSBaptiste Daroussin #include <archive_entry.h>
353aa4b42aSBaptiste Daroussin #include <err.h>
363aa4b42aSBaptiste Daroussin #include <errno.h>
37*b70213b5SBaptiste Daroussin #include <fcntl.h>
383b05c2a8SBaptiste Daroussin #include <fetch.h>
39a6454741SBaptiste Daroussin #include <paths.h>
409950eceeSBaptiste Daroussin #include <stdbool.h>
413aa4b42aSBaptiste Daroussin #include <stdlib.h>
423aa4b42aSBaptiste Daroussin #include <stdio.h>
433aa4b42aSBaptiste Daroussin #include <string.h>
443aa4b42aSBaptiste Daroussin #include <time.h>
453aa4b42aSBaptiste Daroussin #include <unistd.h>
463aa4b42aSBaptiste Daroussin 
4729aaa961SBaptiste Daroussin #include "dns_utils.h"
489950eceeSBaptiste Daroussin #include "config.h"
493aa4b42aSBaptiste Daroussin 
503aa4b42aSBaptiste Daroussin static int
513aa4b42aSBaptiste Daroussin extract_pkg_static(int fd, char *p, int sz)
523aa4b42aSBaptiste Daroussin {
533aa4b42aSBaptiste Daroussin 	struct archive *a;
543aa4b42aSBaptiste Daroussin 	struct archive_entry *ae;
553aa4b42aSBaptiste Daroussin 	char *end;
563aa4b42aSBaptiste Daroussin 	int ret, r;
573aa4b42aSBaptiste Daroussin 
58a6454741SBaptiste Daroussin 	ret = -1;
593aa4b42aSBaptiste Daroussin 	a = archive_read_new();
60a6454741SBaptiste Daroussin 	if (a == NULL) {
61a6454741SBaptiste Daroussin 		warn("archive_read_new");
62a6454741SBaptiste Daroussin 		return (ret);
63a6454741SBaptiste Daroussin 	}
64ff75c36aSBaptiste Daroussin 	archive_read_support_filter_all(a);
653aa4b42aSBaptiste Daroussin 	archive_read_support_format_tar(a);
663aa4b42aSBaptiste Daroussin 
67a6454741SBaptiste Daroussin 	if (lseek(fd, 0, 0) == -1) {
68a6454741SBaptiste Daroussin 		warn("lseek");
69a6454741SBaptiste Daroussin 		goto cleanup;
70a6454741SBaptiste Daroussin 	}
713aa4b42aSBaptiste Daroussin 
723aa4b42aSBaptiste Daroussin 	if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) {
73a6454741SBaptiste Daroussin 		warnx("archive_read_open_fd: %s", archive_error_string(a));
743aa4b42aSBaptiste Daroussin 		goto cleanup;
753aa4b42aSBaptiste Daroussin 	}
763aa4b42aSBaptiste Daroussin 
773aa4b42aSBaptiste Daroussin 	ae = NULL;
783aa4b42aSBaptiste Daroussin 	while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK) {
793aa4b42aSBaptiste Daroussin 		end = strrchr(archive_entry_pathname(ae), '/');
803aa4b42aSBaptiste Daroussin 		if (end == NULL)
813aa4b42aSBaptiste Daroussin 			continue;
823aa4b42aSBaptiste Daroussin 
833aa4b42aSBaptiste Daroussin 		if (strcmp(end, "/pkg-static") == 0) {
843aa4b42aSBaptiste Daroussin 			r = archive_read_extract(a, ae,
853aa4b42aSBaptiste Daroussin 			    ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM |
863aa4b42aSBaptiste Daroussin 			    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_ACL |
873aa4b42aSBaptiste Daroussin 			    ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_XATTR);
88a6454741SBaptiste Daroussin 			strlcpy(p, archive_entry_pathname(ae), sz);
893aa4b42aSBaptiste Daroussin 			break;
903aa4b42aSBaptiste Daroussin 		}
913aa4b42aSBaptiste Daroussin 	}
923aa4b42aSBaptiste Daroussin 
93a6454741SBaptiste Daroussin 	if (r == ARCHIVE_OK)
94a6454741SBaptiste Daroussin 		ret = 0;
95a6454741SBaptiste Daroussin 	else
963aa4b42aSBaptiste Daroussin 		warnx("fail to extract pkg-static");
973aa4b42aSBaptiste Daroussin 
983aa4b42aSBaptiste Daroussin cleanup:
99ff75c36aSBaptiste Daroussin 	archive_read_free(a);
1003b05c2a8SBaptiste Daroussin 	return (ret);
1013aa4b42aSBaptiste Daroussin 
1023aa4b42aSBaptiste Daroussin }
1033aa4b42aSBaptiste Daroussin 
1043aa4b42aSBaptiste Daroussin static int
1053aa4b42aSBaptiste Daroussin install_pkg_static(char *path, char *pkgpath)
1063aa4b42aSBaptiste Daroussin {
1073aa4b42aSBaptiste Daroussin 	int pstat;
1083aa4b42aSBaptiste Daroussin 	pid_t pid;
1093aa4b42aSBaptiste Daroussin 
1103aa4b42aSBaptiste Daroussin 	switch ((pid = fork())) {
1113aa4b42aSBaptiste Daroussin 	case -1:
1123aa4b42aSBaptiste Daroussin 		return (-1);
1133aa4b42aSBaptiste Daroussin 	case 0:
114a6454741SBaptiste Daroussin 		execl(path, "pkg-static", "add", pkgpath, (char *)NULL);
1153b05c2a8SBaptiste Daroussin 		_exit(1);
1163aa4b42aSBaptiste Daroussin 	default:
1173aa4b42aSBaptiste Daroussin 		break;
1183aa4b42aSBaptiste Daroussin 	}
1193aa4b42aSBaptiste Daroussin 
120a6454741SBaptiste Daroussin 	while (waitpid(pid, &pstat, 0) == -1)
1213aa4b42aSBaptiste Daroussin 		if (errno != EINTR)
1223aa4b42aSBaptiste Daroussin 			return (-1);
1233aa4b42aSBaptiste Daroussin 
124a6454741SBaptiste Daroussin 	if (WEXITSTATUS(pstat))
1253aa4b42aSBaptiste Daroussin 		return (WEXITSTATUS(pstat));
126a6454741SBaptiste Daroussin 	else if (WIFSIGNALED(pstat))
127a6454741SBaptiste Daroussin 		return (128 & (WTERMSIG(pstat)));
128a6454741SBaptiste Daroussin 	return (pstat);
1293aa4b42aSBaptiste Daroussin }
1303aa4b42aSBaptiste Daroussin 
1313aa4b42aSBaptiste Daroussin static int
1323aa4b42aSBaptiste Daroussin bootstrap_pkg(void)
1333aa4b42aSBaptiste Daroussin {
13429aaa961SBaptiste Daroussin 	struct url *u;
1353aa4b42aSBaptiste Daroussin 	FILE *remote;
1362fe3761eSBaptiste Daroussin 	FILE *config;
1372fe3761eSBaptiste Daroussin 	char *site;
13829aaa961SBaptiste Daroussin 	struct dns_srvinfo *mirrors, *current;
13929aaa961SBaptiste Daroussin 	/* To store _https._tcp. + hostname + \0 */
14029aaa961SBaptiste Daroussin 	char zone[MAXHOSTNAMELEN + 13];
1413aa4b42aSBaptiste Daroussin 	char url[MAXPATHLEN];
1422fe3761eSBaptiste Daroussin 	char conf[MAXPATHLEN];
1433aa4b42aSBaptiste Daroussin 	char tmppkg[MAXPATHLEN];
1449950eceeSBaptiste Daroussin 	const char *packagesite, *mirror_type;
1453aa4b42aSBaptiste Daroussin 	char buf[10240];
1463aa4b42aSBaptiste Daroussin 	char pkgstatic[MAXPATHLEN];
14729aaa961SBaptiste Daroussin 	int fd, retry, ret, max_retry;
148a6454741SBaptiste Daroussin 	struct url_stat st;
1493aa4b42aSBaptiste Daroussin 	off_t done, r;
150a6454741SBaptiste Daroussin 	time_t now;
151a6454741SBaptiste Daroussin 	time_t last;
1523aa4b42aSBaptiste Daroussin 
1533aa4b42aSBaptiste Daroussin 	done = 0;
154a6454741SBaptiste Daroussin 	last = 0;
15529aaa961SBaptiste Daroussin 	max_retry = 3;
156a6454741SBaptiste Daroussin 	ret = -1;
1573aa4b42aSBaptiste Daroussin 	remote = NULL;
1582fe3761eSBaptiste Daroussin 	config = NULL;
15929aaa961SBaptiste Daroussin 	current = mirrors = NULL;
1603aa4b42aSBaptiste Daroussin 
16165008e03SGavin Atkinson 	printf("Bootstrapping pkg, please wait...\n");
1623aa4b42aSBaptiste Daroussin 
1639950eceeSBaptiste Daroussin 	if (config_string(PACKAGESITE, &packagesite) != 0) {
1649950eceeSBaptiste Daroussin 		warnx("No PACKAGESITE defined");
1653b05c2a8SBaptiste Daroussin 		return (-1);
1663aa4b42aSBaptiste Daroussin 	}
1679950eceeSBaptiste Daroussin 	if (config_string(MIRROR_TYPE, &mirror_type) != 0) {
1689950eceeSBaptiste Daroussin 		warnx("No MIRROR_TYPE defined");
1699950eceeSBaptiste Daroussin 		return (-1);
1709950eceeSBaptiste Daroussin 	}
171968d04c3SBaptiste Daroussin 	snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz", packagesite);
1723aa4b42aSBaptiste Daroussin 
1733aa4b42aSBaptiste Daroussin 	snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX",
174a6454741SBaptiste Daroussin 	    getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
1753aa4b42aSBaptiste Daroussin 
1763aa4b42aSBaptiste Daroussin 	if ((fd = mkstemp(tmppkg)) == -1) {
1773aa4b42aSBaptiste Daroussin 		warn("mkstemp()");
1783b05c2a8SBaptiste Daroussin 		return (-1);
1793aa4b42aSBaptiste Daroussin 	}
1803aa4b42aSBaptiste Daroussin 
18129aaa961SBaptiste Daroussin 	retry = max_retry;
18229aaa961SBaptiste Daroussin 
18329aaa961SBaptiste Daroussin 	u = fetchParseURL(url);
18429aaa961SBaptiste Daroussin 	while (remote == NULL) {
18529aaa961SBaptiste Daroussin 		if (retry == max_retry) {
1869950eceeSBaptiste Daroussin 			if (strcmp(u->scheme, "file") != 0 &&
1879950eceeSBaptiste Daroussin 			    strcasecmp(mirror_type, "srv") == 0) {
18829aaa961SBaptiste Daroussin 				snprintf(zone, sizeof(zone),
18929aaa961SBaptiste Daroussin 				    "_%s._tcp.%s", u->scheme, u->host);
19029aaa961SBaptiste Daroussin 				mirrors = dns_getsrvinfo(zone);
19129aaa961SBaptiste Daroussin 				current = mirrors;
19229aaa961SBaptiste Daroussin 			}
19329aaa961SBaptiste Daroussin 		}
19429aaa961SBaptiste Daroussin 
19535e07a7aSBaptiste Daroussin 		if (mirrors != NULL) {
19629aaa961SBaptiste Daroussin 			strlcpy(u->host, current->host, sizeof(u->host));
19735e07a7aSBaptiste Daroussin 			u->port = current->port;
19835e07a7aSBaptiste Daroussin 		}
19929aaa961SBaptiste Daroussin 
20029aaa961SBaptiste Daroussin 		remote = fetchXGet(u, &st, "");
20129aaa961SBaptiste Daroussin 		if (remote == NULL) {
20229aaa961SBaptiste Daroussin 			--retry;
20329aaa961SBaptiste Daroussin 			if (retry <= 0)
20429aaa961SBaptiste Daroussin 				goto fetchfail;
20529aaa961SBaptiste Daroussin 			if (mirrors == NULL) {
2063aa4b42aSBaptiste Daroussin 				sleep(1);
20729aaa961SBaptiste Daroussin 			} else {
20829aaa961SBaptiste Daroussin 				current = current->next;
20929aaa961SBaptiste Daroussin 				if (current == NULL)
21029aaa961SBaptiste Daroussin 					current = mirrors;
21129aaa961SBaptiste Daroussin 			}
21229aaa961SBaptiste Daroussin 		}
21329aaa961SBaptiste Daroussin 	}
214a6454741SBaptiste Daroussin 
215a6454741SBaptiste Daroussin 	if (remote == NULL)
216a6454741SBaptiste Daroussin 		goto fetchfail;
2173aa4b42aSBaptiste Daroussin 
2183aa4b42aSBaptiste Daroussin 	while (done < st.size) {
2193aa4b42aSBaptiste Daroussin 		if ((r = fread(buf, 1, sizeof(buf), remote)) < 1)
2203aa4b42aSBaptiste Daroussin 			break;
2213aa4b42aSBaptiste Daroussin 
2223aa4b42aSBaptiste Daroussin 		if (write(fd, buf, r) != r) {
2233aa4b42aSBaptiste Daroussin 			warn("write()");
2243aa4b42aSBaptiste Daroussin 			goto cleanup;
2253aa4b42aSBaptiste Daroussin 		}
2263aa4b42aSBaptiste Daroussin 
2273aa4b42aSBaptiste Daroussin 		done += r;
2283aa4b42aSBaptiste Daroussin 		now = time(NULL);
229a6454741SBaptiste Daroussin 		if (now > last || done == st.size)
2303aa4b42aSBaptiste Daroussin 			last = now;
2313aa4b42aSBaptiste Daroussin 	}
2323aa4b42aSBaptiste Daroussin 
233a6454741SBaptiste Daroussin 	if (ferror(remote))
234a6454741SBaptiste Daroussin 		goto fetchfail;
2353aa4b42aSBaptiste Daroussin 
2363aa4b42aSBaptiste Daroussin 	if ((ret = extract_pkg_static(fd, pkgstatic, MAXPATHLEN)) == 0)
2373aa4b42aSBaptiste Daroussin 		ret = install_pkg_static(pkgstatic, tmppkg);
2383aa4b42aSBaptiste Daroussin 
2392fe3761eSBaptiste Daroussin 	snprintf(conf, MAXPATHLEN, "%s/etc/pkg.conf",
2402fe3761eSBaptiste Daroussin 	    getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE);
2412fe3761eSBaptiste Daroussin 
2422fe3761eSBaptiste Daroussin 	if (access(conf, R_OK) == -1) {
2432fe3761eSBaptiste Daroussin 		site = strrchr(url, '/');
2442fe3761eSBaptiste Daroussin 		if (site == NULL)
2452fe3761eSBaptiste Daroussin 			goto cleanup;
2462fe3761eSBaptiste Daroussin 		site[0] = '\0';
2472fe3761eSBaptiste Daroussin 		site = strrchr(url, '/');
2482fe3761eSBaptiste Daroussin 		if (site == NULL)
2492fe3761eSBaptiste Daroussin 			goto cleanup;
2502fe3761eSBaptiste Daroussin 		site[0] = '\0';
2512fe3761eSBaptiste Daroussin 
2522fe3761eSBaptiste Daroussin 		config = fopen(conf, "w+");
2532fe3761eSBaptiste Daroussin 		if (config == NULL)
2542fe3761eSBaptiste Daroussin 			goto cleanup;
255514ead92SBaptiste Daroussin 		fprintf(config, "packagesite: %s\n", url);
2562fe3761eSBaptiste Daroussin 		fclose(config);
2572fe3761eSBaptiste Daroussin 	}
2582fe3761eSBaptiste Daroussin 
259a6454741SBaptiste Daroussin 	goto cleanup;
260a6454741SBaptiste Daroussin 
261a6454741SBaptiste Daroussin fetchfail:
262a6454741SBaptiste Daroussin 	warnx("Error fetching %s: %s", url, fetchLastErrString);
26386e220abSBaptiste Daroussin 	fprintf(stderr, "A pre-built version of pkg could not be found for your system.\n");
26486e220abSBaptiste Daroussin 	fprintf(stderr, "Consider changing PACKAGESITE or installing it from ports: 'ports-mgmt/pkg'.\n");
265a6454741SBaptiste Daroussin 
2663aa4b42aSBaptiste Daroussin cleanup:
2672fe3761eSBaptiste Daroussin 	if (remote != NULL)
2682fe3761eSBaptiste Daroussin 		fclose(remote);
2693aa4b42aSBaptiste Daroussin 	close(fd);
2703aa4b42aSBaptiste Daroussin 	unlink(tmppkg);
2713aa4b42aSBaptiste Daroussin 
272a6454741SBaptiste Daroussin 	return (ret);
2733aa4b42aSBaptiste Daroussin }
2743aa4b42aSBaptiste Daroussin 
275e18ad51cSAlexander Kabaev static const char confirmation_message[] =
276e18ad51cSAlexander Kabaev "The package management tool is not yet installed on your system.\n"
277e18ad51cSAlexander Kabaev "Do you want to fetch and install it now? [y/N]: ";
278e18ad51cSAlexander Kabaev 
279e18ad51cSAlexander Kabaev static int
280e18ad51cSAlexander Kabaev pkg_query_yes_no(void)
281e18ad51cSAlexander Kabaev {
282e18ad51cSAlexander Kabaev 	int ret, c;
283e18ad51cSAlexander Kabaev 
284e18ad51cSAlexander Kabaev 	c = getchar();
285e18ad51cSAlexander Kabaev 
286e18ad51cSAlexander Kabaev 	if (c == 'y' || c == 'Y')
287e18ad51cSAlexander Kabaev 		ret = 1;
288e18ad51cSAlexander Kabaev 	else
289e18ad51cSAlexander Kabaev 		ret = 0;
290e18ad51cSAlexander Kabaev 
291e18ad51cSAlexander Kabaev 	while (c != '\n' && c != EOF)
292e18ad51cSAlexander Kabaev 		c = getchar();
293e18ad51cSAlexander Kabaev 
294e18ad51cSAlexander Kabaev 	return (ret);
295e18ad51cSAlexander Kabaev }
296e18ad51cSAlexander Kabaev 
2973aa4b42aSBaptiste Daroussin int
2983aa4b42aSBaptiste Daroussin main(__unused int argc, char *argv[])
2993aa4b42aSBaptiste Daroussin {
3003aa4b42aSBaptiste Daroussin 	char pkgpath[MAXPATHLEN];
301*b70213b5SBaptiste Daroussin 	char pkgstatic[MAXPATHLEN];
3029950eceeSBaptiste Daroussin 	bool yes = false;
303*b70213b5SBaptiste Daroussin 	int fd, ret;
3043aa4b42aSBaptiste Daroussin 
3053aa4b42aSBaptiste Daroussin 	snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg",
3063aa4b42aSBaptiste Daroussin 	    getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE);
3073aa4b42aSBaptiste Daroussin 
308e18ad51cSAlexander Kabaev 	if (access(pkgpath, X_OK) == -1) {
309e18ad51cSAlexander Kabaev 		/*
310d482e1f4SMatthew Seaman 		 * To allow 'pkg -N' to be used as a reliable test for whether
311ecfed9f2SMatthew Seaman 		 * a system is configured to use pkg, don't bootstrap pkg
312ecfed9f2SMatthew Seaman 		 * when that argument is given as argv[1].
313ecfed9f2SMatthew Seaman 		 */
314d8f9490cSMatthew Seaman 		if (argv[1] != NULL && strcmp(argv[1], "-N") == 0)
315e41b8acbSMatthew Seaman 			errx(EXIT_FAILURE, "pkg is not installed");
316ecfed9f2SMatthew Seaman 
317*b70213b5SBaptiste Daroussin 		if (argc > 2 && strcmp(argv[1], "add") == 0 &&
318*b70213b5SBaptiste Daroussin 		    access(argv[2], R_OK) == 0) {
319*b70213b5SBaptiste Daroussin 			fd = open(argv[2], O_RDONLY);
320*b70213b5SBaptiste Daroussin 			if (fd == -1)
321*b70213b5SBaptiste Daroussin 				err(EXIT_FAILURE, "Unable to open %s", argv[2]);
322*b70213b5SBaptiste Daroussin 
323*b70213b5SBaptiste Daroussin 			if ((ret = extract_pkg_static(fd, pkgstatic, MAXPATHLEN)) == 0)
324*b70213b5SBaptiste Daroussin 				ret = install_pkg_static(pkgstatic, argv[2]);
325*b70213b5SBaptiste Daroussin 			close(fd);
326*b70213b5SBaptiste Daroussin 			if (ret != 0)
327*b70213b5SBaptiste Daroussin 				exit(EXIT_FAILURE);
328*b70213b5SBaptiste Daroussin 			exit(EXIT_SUCCESS);
329*b70213b5SBaptiste Daroussin 		}
330ecfed9f2SMatthew Seaman 		/*
331e18ad51cSAlexander Kabaev 		 * Do not ask for confirmation if either of stdin or stdout is
332e18ad51cSAlexander Kabaev 		 * not tty. Check the environment to see if user has answer
333e18ad51cSAlexander Kabaev 		 * tucked in there already.
334e18ad51cSAlexander Kabaev 		 */
3359950eceeSBaptiste Daroussin 		config_init();
3369950eceeSBaptiste Daroussin 		config_bool(ASSUME_ALWAYS_YES, &yes);
3379950eceeSBaptiste Daroussin 		if (!yes) {
338e18ad51cSAlexander Kabaev 			printf("%s", confirmation_message);
339204ea792SBaptiste Daroussin 			if (!isatty(fileno(stdin)))
3403a480126SBaptiste Daroussin 				exit(EXIT_FAILURE);
341204ea792SBaptiste Daroussin 
342204ea792SBaptiste Daroussin 			if (pkg_query_yes_no() == 0)
343e18ad51cSAlexander Kabaev 				exit(EXIT_FAILURE);
344e18ad51cSAlexander Kabaev 		}
345a6454741SBaptiste Daroussin 		if (bootstrap_pkg() != 0)
346a6454741SBaptiste Daroussin 			exit(EXIT_FAILURE);
3479950eceeSBaptiste Daroussin 		config_finish();
348e18ad51cSAlexander Kabaev 	}
3493aa4b42aSBaptiste Daroussin 
3503aa4b42aSBaptiste Daroussin 	execv(pkgpath, argv);
3513aa4b42aSBaptiste Daroussin 
352a6454741SBaptiste Daroussin 	/* NOT REACHED */
3533b05c2a8SBaptiste Daroussin 	return (EXIT_FAILURE);
3543aa4b42aSBaptiste Daroussin }
355