Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Merge branch 'upstream-master'
Shawn Webb committed 2 years ago
commit fd4c88b0299f32e9a063a8b3acc8464e66fe7539
parent 1959c9c
43 files changed +570 -618
modified NEWS
@@ -1,3 +1,10 @@
+
Changes from 1.21.99.0 to 1.21.99.1
+
- fix regression in HANDLE_RC_SCRIPTS option (off by default)
+
- fix processing entries spiner
+
- fix database path handling for rootdir
+
- revert a change in vital/lock handling in the solver cause
+
  some vital packages to never be upgraded.
+

Changes from 1.20.99.12 to 1.21.99.0
- fix regressions in plist parsing

modified auto.def
@@ -6,7 +6,7 @@ use cc cc-lib cc-shared pkg-config
set maj_ver 1
set med_ver 21
set min_ver 99
-
set dev_ver 0
+
set dev_ver 1
define PKG_API [expr {$maj_ver * 1000000 + $med_ver * 1000 + $min_ver}]
define VERSION $maj_ver.$med_ver.$min_ver[expr {$dev_ver ? ".$dev_ver" : ""}]

modified docs/pkg-check.8
@@ -14,7 +14,7 @@
.\"
.\"     @(#)pkg.8
.\"
-
.Dd May 25, 2018
+
.Dd May 2, 2024
.Dt PKG-CHECK 8
.Os
.Sh NAME
@@ -23,37 +23,29 @@
.Sh SYNOPSIS
.Nm
.Sm off
-
.Fl B | Fl d | Fl s | Fl r
+
.Fl d | Fl s
.Sm on
.Op Fl nqvy
.Fl a
.Nm
.Sm off
-
.Fl B | Fl d | Fl s | Fl r
+
.Fl d | Fl s
.Sm on
.Op Fl nqvy
.Op Fl Cgix
.Ar pattern
.Pp
.Nm
-
.Fl -{shlibs,dependencies,checksums,recompute}
+
.Fl -{dependencies,checksums}
.Op Fl -{dry-run,quiet,verbose,yes}
.Fl -all
.Nm
-
.Fl -{shlibs,dependencies,checksums,recompute}
+
.Fl -{dependencies,checksums}
.Op Fl -{dry-run,quiet,verbose,yes}
.Op Fl -{case-sensitive,glob,case-insensitive,regex}
.Ar pattern
.Sh DESCRIPTION
.Nm
-
.Fl B
-
or
-
.Nm
-
.Fl -shlibs
-
regenerates the library dependency metadata for a package by extracting
-
library requirement information from the binary ELF files in the package.
-
.Pp
-
.Nm
.Fl d
or
.Nm
@@ -61,16 +53,6 @@ or
checks for and installs missing dependencies.
.Pp
.Nm
-
.Fl r
-
or
-
.Nm
-
.Fl -recompute
-
recalculates and sets the checksums of installed packages.
-
This command should only be used when the administrator has
-
made modifications that invalidate a package checksum.
-
Spontaneous checksum problems can indicate data or security problems.
-
.Pp
-
.Nm
.Fl s
or
.Nm
@@ -83,8 +65,6 @@ These options are supported by
.Bl -tag -width dependencies
.It Fl a , Fl -all
Process all packages.
-
.It Fl B , Fl -shlibs
-
Regenerates the library dependency metadata for a package
.It Fl C , Fl -case-sensitive
Use case sensitive standard or regular expression
.Fl ( x )
@@ -107,8 +87,6 @@ has been set to true in
.Pa pkg.conf .
.It Fl n , Fl -dry-run
Only check for missing dependencies, do not install them.
-
.It Fl r , Fl -recompute
-
Recalculates and sets the checksums of installed packages
.It Fl s , Fl -checksums
Detects installed packages with invalid checksums
.It Fl v , Fl -verbose
@@ -141,12 +119,6 @@ for additional information.
See
.Xr pkg.conf 5 .
.Sh EXAMPLES
-
Regenerate the library dependency metadata of all installed packages
-
from the library information in each package's binary ELF files:
-
.Bd -literal -offset indent
-
pkg check -Ba
-
.Ed
-
.Pp
Test for missing dependencies needed by nano, installing any that are
missing:
.Bd -literal -offset indent
modified docs/pkg-create.8
@@ -14,7 +14,7 @@
.\"
.\"     @(#)pkg.8
.\"
-
.Dd October 13, 2020
+
.Dd May 3, 2024
.Dt PKG-CREATE 8
.Os
.\" ---------------------------------------------------------------------------
@@ -31,6 +31,7 @@
.Op Fl p Ar plist
.Op Fl r Ar rootdir
.Op Fl t Ar timestamp
+
.Op Fl T Ar threads
.Fl m Ar metadatadir
.Nm
.Op Fl enqv
@@ -39,6 +40,7 @@
.Op Fl o Ar outdir
.Op Fl r Ar rootdir
.Op Fl t Ar timestamp
+
.Op Fl T Ar threads
.Fl M Ar manifest
.Nm
.Op Fl egnqvx
@@ -47,6 +49,7 @@
.Op Fl o Ar outdir
.Op Fl r Ar rootdir
.Op Fl t Ar timestamp
+
.Op Fl T Ar threads
.Ar pkg-name ...
.Nm
.Op Fl enqv
@@ -55,6 +58,7 @@
.Op Fl o Ar outdir
.Op Fl r Ar rootdir
.Op Fl t Ar timestamp
+
.Op Fl T Ar threads
.Fl a
.\" ---------------------------------------------------------------------------
.Pp
@@ -274,6 +278,14 @@ disturbing similar content already on the system.
If unspecified, the default is effectively
.Pa / ,
the actual root directory.
+
.It Fl T Ar threads
+
.Ar threads
+
represent the number of threads to use during the compression of the archive.
+
Set it to
+
.Qq 0
+
or
+
.Qq auto
+
to let detect the number of CPU and use it.
.El
.\" ---------------------------------------------------------------------------
.Sh MANIFEST FILE DETAILS
modified docs/pkg.conf.5
@@ -127,6 +127,8 @@ Set the default compression level, special values are:
.It 0 default value per libarchive developers
.It -1 default value per pkg developers (default)
.El
+
.It Cm COMPRESSION_THREADS: integer
+
Set the number of threads to use during compression (only functional for txz and tzst)
.It Cm CONSERVATIVE_UPGRADE: boolean
Ensure in multi repository mode that the priority is given as much as possible
to the repository where a package was first installed from.
modified docs/pkg_create.3
@@ -1,4 +1,4 @@
-
.Dd January 23, 2024
+
.Dd May 3, 2024
.Dt PKG_CREATE 3
.Os
.Sh NAME
@@ -6,7 +6,8 @@
.Nm pkg_create_new , pkg_create_free ,
.Nm pkg_create_set_format , pkg_create_set_overwrite ,
.Nm pkg_create_set_compression_level , pkg_create_set_rootdir ,
-
.Nm pkg_create_set_output_dir , pkg_create_set_timestamp
+
.Nm pkg_create_set_output_dir , pkg_create_set_timestamp ,
+
.Nm pkg_create_set_compression_threads
.Nd create packages
.Sh LIBRARY
.Lb libpkg
@@ -21,6 +22,8 @@
.Ft void
.Fn pkg_create_set_compression_level "struct pkg_create *" "int"
.Ft void
+
.Fn pkg_create_set_compression_threads "struct pkg_create *" "int"
+
.Ft void
.Fn pkg_create_set_overwrite "struct pkg_create *" "bool"
.Ft void
.Fn pkg_create_set_rootdir "struct pkg_create *" "const char *"
@@ -63,6 +66,11 @@ Set the default (as specified in libarchive)
Set the best compression ratio
.El
.Pp
+
.Fn pkg_create_set_compression_threads
+
take a
+
.Ft int
+
arguments which represents the expected numbers of threads used during
+
compression.
.Fn pkg_create_set_overwrite
Accept a boolean to define the default behaviour when creating a package and
a local file already exists.
modified libpkg/elfhints.c
@@ -30,6 +30,13 @@
#include <bsd_compat.h>
#include <sys/mman.h>
#include <sys/stat.h>
+
#ifdef HAVE_SYS_ENDIAN_H
+
#include <sys/endian.h>
+
#elif HAVE_ENDIAN_H
+
#include <endian.h>
+
#elif HAVE_MACHINE_ENDIAN_H
+
#include <machine/endian.h>
+
#endif

#include <assert.h>
#include <ctype.h>
modified libpkg/fetch.c
@@ -249,7 +249,7 @@ pkg_fetch_file_to_fd(struct pkg_repo *repo, int dest, struct fetch_item *fi,
	 * Error if using plain http://, https:// etc with SRV
	 */

-
	pkg_debug(1, "Request to fetch %s", fi->url);
+
	pkg_dbg(PKG_DBG_FETCH, 1, "Request to fetch %s", fi->url);
	if (repo == NULL) {
		fakerepo = xcalloc(1, sizeof(struct pkg_repo));
		fakerepo->url = xstrdup(fi->url);
@@ -292,7 +292,7 @@ pkg_fetch_file_to_fd(struct pkg_repo *repo, int dest, struct fetch_item *fi,

	if ((retcode = repo->fetcher->open(repo, fi)) != EPKG_OK)
		goto cleanup;
-
	pkg_debug(1, "Fetch: fetcher used: %s", repo->fetcher->scheme);
+
	pkg_dbg(PKG_DBG_FETCH, 1, "Fetch: fetcher used: %s", repo->fetcher->scheme);

	retcode = repo->fetcher->fetch(repo, dest, fi);
	if (retcode == EPKG_OK)
modified libpkg/fetch_file.c
@@ -95,9 +95,9 @@ stdio_fetch(struct pkg_repo *repo, int dest, struct fetch_item *fi)
		done += r;
		if (fi->size > 0) {
			left -= r;
-
			pkg_debug(4, "Read status: %jd over %jd", (intmax_t)done, (intmax_t)fi->size);
+
			pkg_dbg(PKG_DBG_FETCH, 1, "Read status: %jd over %jd", (intmax_t)done, (intmax_t)fi->size);
		} else
-
			pkg_debug(4, "Read status: %jd", (intmax_t)done);
+
			pkg_dbg(PKG_DBG_FETCH, 1,  "Read status: %jd", (intmax_t)done);
		if (fi->size > 0)
			pkg_emit_progress_tick(done, fi->size);
	}
modified libpkg/fetch_libcurl.c
@@ -149,9 +149,9 @@ curl_do_fetch(struct curl_userdata *data, CURL *cl, struct curl_repodata *cr)
	curl_easy_setopt(cl, CURLOPT_FOLLOWLOCATION, 1L);
	curl_easy_setopt(cl, CURLOPT_PRIVATE, &data);

-
	if (ctx.debug_level > 0)
+
	if (ctx.debug_flags & PKG_DBG_FETCH && ctx.debug_level >= 1)
		curl_easy_setopt(cl, CURLOPT_VERBOSE, 1L);
-
	if (ctx.debug_level > 1)
+
	if (ctx.debug_flags & PKG_DBG_FETCH && ctx.debug_level >= 1)
		curl_easy_setopt(cl, CURLOPT_DEBUGFUNCTION, my_trace);

	/* compat with libfetch */
@@ -212,7 +212,7 @@ http_getmirrors(struct pkg_repo *r, struct curl_repodata *cr)
	size_t cap = 0;
	struct http_mirror *m, *mirrors = NULL;
	CURLU *url;
-
	pkg_debug(1, "CURL> fetching http mirror list if any");
+
	pkg_dbg(PKG_DBG_FETCH, 2, "CURL> fetching http mirror list if any");

	cl = curl_easy_init();
	data.fh = open_memstream(& buf, &cap);
@@ -247,7 +247,7 @@ http_getmirrors(struct pkg_repo *r, struct curl_repodata *cr)
		}
		m = xmalloc(sizeof(*m));
		m->url = url;
-
		pkg_debug(1, "CURL> appending an http mirror: %s", line);
+
		pkg_dbg(PKG_DBG_FETCH, 2, "CURL> appending an http mirror: %s", line);
		LL_APPEND(mirrors, m);
	}
	free(buf);
@@ -287,7 +287,7 @@ int
curl_open(struct pkg_repo *repo, struct fetch_item *fi __unused)
{
	struct curl_repodata *cr;
-
	pkg_debug(1, "curl_open");
+
	pkg_dbg(PKG_DBG_FETCH, 2, "curl_open");

	if (repo->fetch_priv != NULL)
		return (EPKG_OK);
@@ -378,7 +378,7 @@ curl_fetch(struct pkg_repo *repo, int dest, struct fetch_item *fi)
	data.totalsize = fi->size;
	data.url = fi->url;

-
	pkg_debug(1, "curl> fetching %s\n", fi->url);
+
	pkg_dbg(PKG_DBG_FETCH, 2, "curl> fetching %s\n", fi->url);
	retry = pkg_object_int(pkg_config_get("FETCH_RETRY"));
	if (repo->mirror_type == SRV || repo->mirror_type == HTTP) {
		CURLU *cu = curl_url();
@@ -435,16 +435,16 @@ do_retry:
		free(p);
		char *lurl;
		curl_url_get(hu, CURLUPART_URL, &lurl, 0);
-
		pkg_debug(1, "CURL> new http mirror url: %s", lurl);
+
		pkg_dbg(PKG_DBG_FETCH, 2, "CURL> new http mirror url: %s", lurl);
		curl_easy_setopt(cl, CURLOPT_CURLU, hu);
	} else {
-
		pkg_debug(1, "CURL> No mirror set url to %s\n", fi->url);
+
		pkg_dbg(PKG_DBG_FETCH, 2, "CURL> No mirror set url to %s\n", fi->url);
		curl_easy_setopt(cl, CURLOPT_URL, fi->url);
	}
-
	if (ctx.debug_level > 0) {
+
	if (ctx.debug_flags & PKG_DBG_FETCH && ctx.debug_level >= 1) {
		const char *lurl = NULL;
		curl_easy_getinfo(cl, CURLINFO_EFFECTIVE_URL, &lurl);
-
		pkg_debug(1, "CURL> attempting to fetch from %s, left retry %ld\n",
+
		pkg_dbg(PKG_DBG_FETCH, 2, "CURL> attempting to fetch from %s, left retry %ld\n",
				lurl, retry);
	}
	curl_easy_setopt(cl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY);
modified libpkg/fetch_libfetch.c
@@ -117,7 +117,7 @@ fetch_connect(struct pkg_repo *repo, struct url *u)
	doc = u->doc;
	reldoc = doc + strlen(repourl->doc);
	fetchFreeURL(repourl);
-
	pkg_debug(1, "Fetch > libfetch: connecting");
+
	pkg_dbg(PKG_DBG_FETCH, "Fetch > libfetch: connecting");

	while (repo->fh == NULL) {
		if (repo != NULL && repo->mirror_type == SRV &&
@@ -172,7 +172,7 @@ fetch_connect(struct pkg_repo *repo, struct url *u)
			fputc('v', fetchOpts->fp);

		opts = xstring_get(fetchOpts);
-
		pkg_debug(1,"Fetch: fetching from: %s://%s%s%s%s with opts \"%s\"",
+
		pkg_dbg(PKG_DBG_FETCH, "Fetch: fetching from: %s://%s%s%s%s with opts \"%s\"",
		    u->scheme,
		    u->user,
		    u->user[0] != '\0' ? "@" : "",
@@ -225,7 +225,7 @@ fetch_open(struct pkg_repo *repo, struct url *u, off_t *sz, time_t *t)
{
	int retcode = EPKG_FATAL;

-
	pkg_debug(1, "opening libfetch fetcher");
+
	pkg_dbg(PKG_DBG_FETCH, "opening libfetch fetcher");
	if (repo->fh == NULL)
		retcode = fetch_connect(repo, u);

modified libpkg/fetch_ssh.c
@@ -64,7 +64,7 @@ tcp_connect(struct pkg_repo *repo, struct yuarel *u)
	int sd = -1;
	int retcode;

-
	pkg_debug(1, "TCP> tcp_connect");
+
	pkg_dbg(PKG_DBG_FETCH, 1, "TCP> tcp_connect");
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = PF_UNSPEC;
	if (repo->ip == IPV4)
@@ -114,12 +114,12 @@ tcp_connect(struct pkg_repo *repo, struct yuarel *u)

	if (getline(&line, &linecap, repo->fh) > 0) {
		if (strncmp(line, "ok:", 3) != 0) {
-
			pkg_debug(1, "SSH> server rejected, got: %s", line);
+
			pkg_dbg(PKG_DBG_FETCH, 1, "SSH> server rejected, got: %s", line);
			goto tcp_cleanup;
		}
-
		pkg_debug(1, "SSH> server is: %s", line +4);
+
		pkg_dbg(PKG_DBG_FETCH, 1, "SSH> server is: %s", line +4);
	} else {
-
		pkg_debug(1, "SSH> nothing to read, got: %s", line);
+
		pkg_dbg(PKG_DBG_FETCH, 1, "SSH> nothing to read, got: %s", line);
		goto tcp_cleanup;
	}
	retcode = EPKG_OK;
@@ -182,7 +182,7 @@ ssh_connect(struct pkg_repo *repo, struct yuarel *u)
			fprintf(cmd->fp, "%s@", u->username);
		fprintf(cmd->fp, "%s pkg ssh", u->host);
		cmdline = xstring_get(cmd);
-
		pkg_debug(1, "Fetch: running '%s'", cmdline);
+
		pkg_dbg(PKG_DBG_FETCH, 1, "Fetch: running '%s'", cmdline);
		argv[0] = _PATH_BSHELL;
		argv[1] = "-c";
		argv[2] = cmdline;
@@ -201,7 +201,7 @@ ssh_connect(struct pkg_repo *repo, struct yuarel *u)
		goto ssh_cleanup;
	}

-
	pkg_debug(1, "SSH> connected");
+
	pkg_dbg(PKG_DBG_FETCH, 1, "SSH> connected");

	repo->sshio.in = sshout[0];
	repo->sshio.out = sshin[1];
@@ -215,12 +215,12 @@ ssh_connect(struct pkg_repo *repo, struct yuarel *u)

	if (getline(&line, &linecap, repo->fh) > 0) {
		if (strncmp(line, "ok:", 3) != 0) {
-
			pkg_debug(1, "SSH> server rejected, got: %s", line);
+
			pkg_dbg(PKG_DBG_FETCH, 1, "SSH> server rejected, got: %s", line);
			goto ssh_cleanup;
		}
-
		pkg_debug(1, "SSH> server is: %s", line +4);
+
		pkg_dbg(PKG_DBG_FETCH, 1, "SSH> server is: %s", line +4);
	} else {
-
		pkg_debug(1, "SSH> nothing to read, got: %s", line);
+
		pkg_dbg(PKG_DBG_FETCH, 1, "SSH> nothing to read, got: %s", line);
		goto ssh_cleanup;
	}
	retcode = EPKG_OK;
@@ -252,7 +252,7 @@ pkgprotocol_open(struct pkg_repo *repo, struct fetch_item *fi,
		return (EPKG_FATAL);
	}

-
	pkg_debug(1, "SSH> tcp_open");
+
	pkg_dbg(PKG_DBG_FETCH, 1, "SSH> tcp_open");
	if (repo->fh == NULL)
		retcode = proto_connect(repo, &url);
	else
@@ -261,13 +261,13 @@ pkgprotocol_open(struct pkg_repo *repo, struct fetch_item *fi,
	if (retcode != EPKG_OK)
		return (retcode);

-
	pkg_debug(1, "SSH> get %s %" PRIdMAX "", url.path, (intmax_t)fi->mtime);
+
	pkg_dbg(PKG_DBG_FETCH, 1, "SSH> get %s %" PRIdMAX "", url.path, (intmax_t)fi->mtime);
	fprintf(repo->fh, "get %s %" PRIdMAX "\n", url.path, (intmax_t)fi->mtime);
	if ((linelen = getline(&line, &linecap, repo->fh)) > 0) {
		if (line[linelen -1 ] == '\n')
			line[linelen -1 ] = '\0';

-
		pkg_debug(1, "SSH> recv: %s", line);
+
		pkg_dbg(PKG_DBG_FETCH, 1, "SSH> recv: %s", line);
		if (strncmp(line, "ok:", 3) == 0) {
			fi->size = strtonum(line + 4, 0, LONG_MAX, &errstr);
			if (errstr) {
@@ -414,7 +414,7 @@ ssh_write(void *data, const char *buf, int l)
	iov.iov_base = __DECONST(char *, buf);
	iov.iov_len = l;

-
	pkg_debug(1, "writing data");
+
	pkg_dbg(PKG_DBG_FETCH, 1, "SSH> writing data");

	return (ssh_writev(repo->sshio.out, &iov, 1, repo->fetcher->timeout));
}
@@ -428,7 +428,7 @@ ssh_read(void *data, char *buf, int len)
	ssize_t rlen;
	int deltams;

-
	pkg_debug(2, "ssh: start reading");
+
	pkg_dbg(PKG_DBG_FETCH, 1, "SSH> start reading");

	if (repo->fetcher->timeout > 0) {
		gettimeofday(&timeout, NULL);
@@ -442,7 +442,7 @@ ssh_read(void *data, char *buf, int len)

	for (;;) {
		rlen = read(pfd.fd, buf, len);
-
		pkg_debug(2, "read %jd", (intmax_t)rlen);
+
		pkg_dbg(PKG_DBG_FETCH, 1, "SSH> read %jd", (intmax_t)rlen);
		if (rlen >= 0) {
			break;
		} else if (rlen == -1) {
@@ -468,17 +468,17 @@ ssh_read(void *data, char *buf, int len)

		errno = 0;
		pfd.revents = 0;
-
		pkg_debug(1, "begin poll()");
+
		pkg_dbg(PKG_DBG_FETCH, 2, "SSH> begin poll()");
		if (poll(&pfd, 1, deltams) < 0) {
			if (errno == EINTR)
				continue;
			return (-1);
		}
-
		pkg_debug(1, "end poll()");
+
		pkg_dbg(PKG_DBG_FETCH, 2, "SSH> end poll()");

	}

-
	pkg_debug(2, "ssh: have read %jd bytes", (intmax_t)rlen);
+
	pkg_dbg(PKG_DBG_FETCH, 1, "SSH> have read %jd bytes", (intmax_t)rlen);

	return (rlen);
}
modified libpkg/libpkg.ver
@@ -32,6 +32,7 @@ global:
	pkg_create_installed;
	pkg_create_new;
	pkg_create_repo;
+
	pkg_create_set_compression_threads;
	pkg_create_set_compression_level;
	pkg_create_set_expand_manifest;
	pkg_create_set_format;
@@ -135,7 +136,6 @@ global:
	pkg_plugins_shutdown;
	pkg_printf;
	pkg_rdeps;
-
	pkg_recompute;
	pkg_repo_cached_name;
	pkg_repo_create;
	pkg_repo_create_free;
@@ -219,7 +219,6 @@ global:
	pkgdb_query_shlib_provide;
	pkgdb_query_shlib_require;
	pkgdb_query_which;
-
	pkgdb_reanalyse_shlibs;
	pkgdb_register_ports;
	pkgdb_release_lock;
	pkgdb_repo_query;
modified libpkg/packing.c
@@ -2,7 +2,7 @@
 * Copyright (c) 2011-2021 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011 Will Andrews <will@FreeBSD.org>
 * All rights reserved.
-
 * 
+
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
@@ -12,7 +12,7 @@
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
-
 * 
+
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
@@ -43,9 +43,11 @@
#include "private/pkg.h"
#include "private/packing.h"

+
#define dbg(x, ...) pkg_dbg(PKG_DBG_PACKING, x, __VA_ARGS__);
+

int
packing_init(struct packing **pack, const char *path, pkg_formats format, int clevel,
-
	time_t timestamp, bool overwrite, bool compat_symlink)
+
	int threads, time_t timestamp, bool overwrite, bool compat_symlink)
{
	char archive_path[MAXPATHLEN];
	char archive_symlink[MAXPATHLEN];
@@ -77,7 +79,7 @@ packing_init(struct packing **pack, const char *path, pkg_formats format, int cl

	(*pack)->awrite = archive_write_new();
	archive_write_set_format_pax_restricted((*pack)->awrite);
-
	ext = packing_set_format((*pack)->awrite, format, clevel);
+
	ext = packing_set_format((*pack)->awrite, format, clevel, threads);
	if (ext == NULL) {
		archive_read_close((*pack)->aread);
		archive_read_free((*pack)->aread);
@@ -106,7 +108,7 @@ packing_init(struct packing **pack, const char *path, pkg_formats format, int cl
		errno = EEXIST;
		return (EPKG_EXIST);
	}
-
	pkg_debug(1, "Packing to file '%s'", archive_path);
+
	dbg(1, "target file '%s'", archive_path);
	if (archive_write_open_filename(
	    (*pack)->awrite, archive_path) != ARCHIVE_OK) {
		pkg_emit_errno("archive_write_open_filename",
@@ -140,6 +142,7 @@ packing_append_iovec(struct packing *pack, const char *path, struct iovec *iov,
	struct archive_entry *entry;
	int ret = EPKG_OK, size = 0;

+
	dbg(1, "adding file '%s'", path);
	for (int idx = 0; idx < niov; idx++) {
		size += iov[idx].iov_len;
	}
@@ -180,6 +183,7 @@ packing_append_buffer(struct packing *pack, const char *buffer,
{
	struct iovec iov;

+
	dbg(1, "adding file '%s'", path);
	iov.iov_base = __DECONST(char *, buffer);
	iov.iov_len = size;
	return (packing_append_iovec(pack, path, &iov, 1));
@@ -202,7 +206,7 @@ packing_append_file_attr(struct packing *pack, const char *filepath,
	entry = archive_entry_new();
	archive_entry_copy_sourcepath(entry, filepath);

-
	pkg_debug(2, "Packing file '%s'", filepath);
+
	dbg(1, "adding file '%s'", filepath);

	if (lstat(filepath, &st) != 0) {
		pkg_emit_errno("lstat", filepath);
@@ -312,7 +316,7 @@ packing_finish(struct packing *pack)
}

const char *
-
packing_set_format(struct archive *a, pkg_formats format, int clevel)
+
packing_set_format(struct archive *a, pkg_formats format, int clevel, int threads)
{
	const char *notsupp_fmt = "%s is not supported, trying %s";

@@ -370,44 +374,50 @@ out:
	if (format == TAR && clevel != 0)
		pkg_emit_error("Plain tar and a compression level does not make sense");

-
	if (elected_format != TAR && clevel != 0) {
+
	if (elected_format != TAR) {
		char buf[16];
-

-
		/*
-
		 * A bit of a kludge but avoids dragging in headers for all of
-
		 * these libraries.
-
		 */
-
		if (clevel == INT_MIN) {
-
			switch (elected_format) {
-
			case TZS:
-
				clevel = -5;
-
				break;
-
			case TXZ:
-
			case TBZ:
-
			case TGZ:
-
				clevel = 1;
-
				break;
-
			default:
-
				__unreachable();
-
			}
-
		} else if (clevel == INT_MAX) {
-
			switch (elected_format) {
-
			case TZS:
-
				clevel = 19;
-
				break;
-
			case TXZ:
-
			case TBZ:
-
			case TGZ:
-
				clevel = 9;
-
				break;
-
			default:
-
				__unreachable();
+
		if (clevel != 0) {
+
			/*
+
			 * A bit of a kludge but avoids dragging in headers for all of
+
			 * these libraries.
+
			 */
+
			if (clevel == INT_MIN) {
+
				switch (elected_format) {
+
					case TZS:
+
						clevel = -5;
+
						break;
+
					case TXZ:
+
					case TBZ:
+
					case TGZ:
+
						clevel = 1;
+
						break;
+
					default:
+
						__unreachable();
+
				}
+
			} else if (clevel == INT_MAX) {
+
				switch (elected_format) {
+
					case TZS:
+
						clevel = 19;
+
						break;
+
					case TXZ:
+
					case TBZ:
+
					case TGZ:
+
						clevel = 9;
+
						break;
+
					default:
+
						__unreachable();
+
				}
			}
-
		}

-
		snprintf(buf, sizeof(buf), "%d", clevel);
-
		if (archive_write_set_filter_option(a, NULL, "compression-level", buf) != ARCHIVE_OK)
-
			pkg_emit_error("bad compression-level %d", clevel);
+
			snprintf(buf, sizeof(buf), "%d", clevel);
+
			if (archive_write_set_filter_option(a, NULL, "compression-level", buf) != ARCHIVE_OK)
+
				pkg_emit_error("bad compression-level %d", clevel);
+
		}
+
		if (threads >= 0) {
+
			snprintf(buf, sizeof(buf), "%d", threads);
+
			if (archive_write_set_filter_option(a, NULL, "threads", buf) != ARCHIVE_OK)
+
				pkg_emit_error("bad threads value %d", threads);
+
		}
	}

	return (packing_format_to_string(elected_format));
modified libpkg/pkg.c
@@ -1,33 +1,13 @@
/*-
-
 * Copyright (c) 2011-2016 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2024 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2012 Bryan Drewery <bryan@shatow.net>
 * Copyright (c) 2013 Matthew Seaman <matthew@FreeBSD.org>
 * Copyright (c) 2017 Vsevolod Stakhov <vsevolod@FreeBSD.org>
 * Copyright (c) 2023, Serenity Cyber Security, LLC
 *                     Author: Gleb Popov <arrowd@FreeBSD.org>
-
 * All rights reserved.
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <archive.h>
@@ -1371,50 +1351,6 @@ pkg_test_filesum(struct pkg *pkg)
}

int
-
pkg_recompute(struct pkgdb *db, struct pkg *pkg)
-
{
-
	struct pkg_file *f = NULL;
-
	hardlinks_t hl = tll_init();
-
	int64_t flatsize = 0;
-
	struct stat st;
-
	bool regular = false;
-
	char *sum;
-
	int rc = EPKG_OK;
-

-
	while (pkg_files(pkg, &f) == EPKG_OK) {
-
		if (lstat(f->path, &st) != 0)
-
			continue;
-
		regular = true;
-
		sum = pkg_checksum_generate_file(f->path,
-
		    PKG_HASH_TYPE_SHA256_HEX);
-

-
		if (S_ISLNK(st.st_mode))
-
			regular = false;
-

-
		if (sum == NULL) {
-
			rc = EPKG_FATAL;
-
			break;
-
		}
-

-
		if (st.st_nlink > 1)
-
			regular = !check_for_hardlink(&hl, &st);
-

-
		if (regular)
-
			flatsize += st.st_size;
-

-
		if (strcmp(sum, f->sum) != 0)
-
			pkgdb_file_set_cksum(db, f, sum);
-
		free(sum);
-
	}
-
	tll_free_and_free(hl, free);
-

-
	if (flatsize != pkg->flatsize)
-
		pkg->flatsize = flatsize;
-

-
	return (rc);
-
}
-

-
int
pkg_try_installed(struct pkgdb *db, const char *name,
		struct pkg **pkg, unsigned flags) {
	struct pkgdb_it *it = NULL;
modified libpkg/pkg.h.in
@@ -1479,8 +1479,6 @@ int pkg_initialized(void);
void pkg_shutdown(void);

int pkg_test_filesum(struct pkg *);
-
int pkg_recompute(struct pkgdb *, struct pkg *);
-
int pkgdb_reanalyse_shlibs(struct pkgdb *, struct pkg *);

void pkgdb_cmd(int argc, char **argv);
int pkg_sshserve(int fd);
@@ -1680,6 +1678,7 @@ void pkg_drop_privileges(void);
struct pkg_create *pkg_create_new(void);
void pkg_create_free(struct pkg_create *);
bool pkg_create_set_format(struct pkg_create *, const char *);
+
void pkg_create_set_compression_threads(struct pkg_create *, int);
void pkg_create_set_compression_level(struct pkg_create *, int);
void pkg_create_set_overwrite(struct pkg_create *, bool);
void pkg_create_set_rootdir(struct pkg_create *, const char *);
modified libpkg/pkg_add.c
@@ -261,7 +261,7 @@ set_attrsat(int fd, const char *path, mode_t perm, uid_t uid, gid_t gid,
	/* zfs drops the setuid on fchownat */
	if (fchmodat(fd, RELATIVE_PATH(path), perm, AT_SYMLINK_NOFOLLOW) == -1) {
		if (errno == ENOTSUP) {
-
			/* 
+
			/*
			 * Executing fchmodat on a symbolic link results in
			 * ENOENT (file not found) on platforms that do not
			 * support AT_SYMLINK_NOFOLLOW. The file mode of
@@ -322,7 +322,7 @@ reopen_tempdir(int rootfd, struct tempdir *t)
}

static struct tempdir *
-
get_tempdir(int rootfd, const char *path, tempdirs_t *tempdirs)
+
get_tempdir(int rootfd, const char *path, tempdirs_t *tempdirs, stringlist_t *symlinks_allowed)
{
	struct tempdir *tmpdir = NULL;

@@ -333,7 +333,7 @@ get_tempdir(int rootfd, const char *path, tempdirs_t *tempdirs)
		}
	}

-
	tmpdir = open_tempdir(rootfd, path);
+
	tmpdir = open_tempdir(rootfd, path, symlinks_allowed);
	if (tmpdir != NULL)
		tll_push_back(*tempdirs, tmpdir);

@@ -351,14 +351,14 @@ close_tempdir(struct tempdir *t)
}

static int
-
create_dir(struct pkg *pkg, struct pkg_dir *d, tempdirs_t *tempdirs)
+
create_dir(struct pkg *pkg, struct pkg_dir *d, tempdirs_t *tempdirs, stringlist_t *symlinks_allowed)
{
	struct stat st;
	struct tempdir *tmpdir = NULL;
	int fd;
	const char *path;

-
	tmpdir = get_tempdir(pkg->rootfd, d->path, tempdirs);
+
	tmpdir = get_tempdir(pkg->rootfd, d->path, tempdirs, symlinks_allowed);
	if (tmpdir == NULL) {
		fd = pkg->rootfd;
		path = d->path;
@@ -401,7 +401,7 @@ create_dir(struct pkg *pkg, struct pkg_dir *d, tempdirs_t *tempdirs)
/* In case of directories create the dir and extract the creds */
static int
do_extract_dir(struct pkg* pkg, struct archive *a __unused, struct archive_entry *ae,
-
    const char *path, struct pkg *local __unused, tempdirs_t *tempdirs)
+
    const char *path, struct pkg *local __unused, tempdirs_t *tempdirs, stringlist_t *symlinks_allowed)
{
	struct pkg_dir *d;
	const struct stat *aest;
@@ -420,7 +420,7 @@ do_extract_dir(struct pkg* pkg, struct archive *a __unused, struct archive_entry
	fill_timespec_buf(aest, d->time);
	archive_entry_fflags(ae, &d->fflags, &clear);

-
	if (create_dir(pkg, d, tempdirs) == EPKG_FATAL) {
+
	if (create_dir(pkg, d, tempdirs, symlinks_allowed) == EPKG_FATAL) {
		return (EPKG_FATAL);
	}

@@ -446,14 +446,15 @@ try_mkdir(int fd, const char *path)
}

static int
-
create_symlinks(struct pkg *pkg, struct pkg_file *f, const char *target, tempdirs_t *tempdirs)
+
create_symlinks(struct pkg *pkg, struct pkg_file *f, const char *target, tempdirs_t *tempdirs,
+
    stringlist_t *symlinks_allowed)
{
	struct tempdir *tmpdir = NULL;
	int fd;
	const char *path;
	bool tried_mkdir = false;

-
	tmpdir = get_tempdir(pkg->rootfd, f->path, tempdirs);
+
	tmpdir = get_tempdir(pkg->rootfd, f->path, tempdirs, symlinks_allowed);
	if (tmpdir == NULL && errno == 0)
		hidden_tempfile(f->temppath, sizeof(f->temppath), f->path);
	if (tmpdir == NULL) {
@@ -492,7 +493,8 @@ retry:
/* In case of a symlink create it directly with a random name */
static int
do_extract_symlink(struct pkg *pkg, struct archive *a __unused, struct archive_entry *ae,
-
    const char *path, struct pkg *local __unused, tempdirs_t *tempdirs)
+
    const char *path, struct pkg *local __unused, tempdirs_t *tempdirs,
+
    stringlist_t *symlinks_allowed)
{
	struct pkg_file *f;
	const struct stat *aest;
@@ -512,7 +514,7 @@ do_extract_symlink(struct pkg *pkg, struct archive *a __unused, struct archive_e
	fill_timespec_buf(aest, f->time);
	archive_entry_fflags(ae, &f->fflags, &clear);

-
	if (create_symlinks(pkg, f, archive_entry_symlink(ae), tempdirs) == EPKG_FATAL)
+
	if (create_symlinks(pkg, f, archive_entry_symlink(ae), tempdirs, symlinks_allowed) == EPKG_FATAL)
		return (EPKG_FATAL);

	metalog_add(PKG_METALOG_LINK, RELATIVE_PATH(path),
@@ -523,7 +525,8 @@ do_extract_symlink(struct pkg *pkg, struct archive *a __unused, struct archive_e
}

static int
-
create_hardlink(struct pkg *pkg, struct pkg_file *f, const char *path, tempdirs_t *tempdirs)
+
create_hardlink(struct pkg *pkg, struct pkg_file *f, const char *path, tempdirs_t *tempdirs,
+
    stringlist_t *symlinks_allowed)
{
	bool tried_mkdir = false;
	struct pkg_file *fh;
@@ -532,7 +535,7 @@ create_hardlink(struct pkg *pkg, struct pkg_file *f, const char *path, tempdirs_
	struct tempdir *tmpdir = NULL;
	struct tempdir *tmphdir = NULL;

-
	tmpdir = get_tempdir(pkg->rootfd, f->path, tempdirs);
+
	tmpdir = get_tempdir(pkg->rootfd, f->path, tempdirs, symlinks_allowed);
	if (tmpdir == NULL && errno == 0)
		hidden_tempfile(f->temppath, sizeof(f->temppath), f->path);
	if (tmpdir != NULL) {
@@ -598,7 +601,8 @@ retry:

static int
do_extract_hardlink(struct pkg *pkg, struct archive *a __unused, struct archive_entry *ae,
-
    const char *path, struct pkg *local __unused, tempdirs_t *tempdirs)
+
    const char *path, struct pkg *local __unused, tempdirs_t *tempdirs,
+
    stringlist_t *symlinks_allowed)
{
	struct pkg_file *f;
	const struct stat *aest;
@@ -612,7 +616,7 @@ do_extract_hardlink(struct pkg *pkg, struct archive *a __unused, struct archive_
	lp = archive_entry_hardlink(ae);
	aest = archive_entry_stat(ae);

-
	if (create_hardlink(pkg, f, lp, tempdirs) == EPKG_FATAL)
+
	if (create_hardlink(pkg, f, lp, tempdirs, symlinks_allowed) == EPKG_FATAL)
		return (EPKG_FATAL);

	metalog_add(PKG_METALOG_FILE, RELATIVE_PATH(path),
@@ -644,7 +648,8 @@ retry:

static int
create_regfile(struct pkg *pkg, struct pkg_file *f, struct archive *a,
-
    struct archive_entry *ae, int fromfd, struct pkg *local, tempdirs_t *tempdirs)
+
    struct archive_entry *ae, int fromfd, struct pkg *local, tempdirs_t *tempdirs,
+
    stringlist_t *symlinks_allowed)
{
	int fd = -1;
	size_t len;
@@ -655,7 +660,7 @@ create_regfile(struct pkg *pkg, struct pkg_file *f, struct archive *a,
	void *attrval;
	size_t attrsz;

-
	tmpdir = get_tempdir(pkg->rootfd, f->path, tempdirs);
+
	tmpdir = get_tempdir(pkg->rootfd, f->path, tempdirs, symlinks_allowed);
	if (tmpdir == NULL && errno == 0)
		hidden_tempfile(f->temppath, sizeof(f->temppath), f->path);

@@ -758,7 +763,7 @@ create_regfile(struct pkg *pkg, struct pkg_file *f, struct archive *a,

static int
do_extract_regfile(struct pkg *pkg, struct archive *a, struct archive_entry *ae,
-
    const char *path, struct pkg *local, tempdirs_t *tempdirs)
+
    const char *path, struct pkg *local, tempdirs_t *tempdirs, stringlist_t *symlinks_allowed)
{
	struct pkg_file *f;
	const struct stat *aest;
@@ -778,7 +783,7 @@ do_extract_regfile(struct pkg *pkg, struct archive *a, struct archive_entry *ae,
	fill_timespec_buf(aest, f->time);
	archive_entry_fflags(ae, &f->fflags, &clear);

-
	if (create_regfile(pkg, f, a, ae, -1, local, tempdirs) == EPKG_FATAL)
+
	if (create_regfile(pkg, f, a, ae, -1, local, tempdirs, symlinks_allowed) == EPKG_FATAL)
		return (EPKG_FATAL);

	metalog_add(PKG_METALOG_FILE, RELATIVE_PATH(path),
@@ -790,14 +795,15 @@ do_extract_regfile(struct pkg *pkg, struct archive *a, struct archive_entry *ae,

static int
do_extract(struct archive *a, struct archive_entry *ae,
-
    int nfiles, struct pkg *pkg, struct pkg *local, tempdirs_t *tempdirs)
+
    int nfiles, struct pkg *pkg, struct pkg *local, tempdirs_t *tempdirs,
+
    stringlist_t *symlinks_allowed)
{
	int	retcode = EPKG_OK;
	int	ret = 0, cur_file = 0;
	char	path[MAXPATHLEN];
	int (*extract_cb)(struct pkg *pkg, struct archive *a,
	    struct archive_entry *ae, const char *path, struct pkg *local,
-
	    tempdirs_t *tempdirs);
+
	    tempdirs_t *tempdirs, stringlist_t *sa);

#ifndef HAVE_ARC4RANDOM
	srand(time(NULL));
@@ -860,7 +866,7 @@ do_extract(struct archive *a, struct archive_entry *ae,
			break;
		}

-
		if (extract_cb(pkg, a, ae, path, local, tempdirs) != EPKG_OK) {
+
		if (extract_cb(pkg, a, ae, path, local, tempdirs, symlinks_allowed) != EPKG_OK) {
			retcode = EPKG_FATAL;
			goto cleanup;
		}
@@ -1264,6 +1270,7 @@ pkg_add_common(struct pkgdb *db, const char *path, unsigned flags,
	int			 ret;
	int			 nfiles;
	tempdirs_t		 tempdirs = tll_init();
+
	stringlist_t		 symlinks_allowed = tll_init();

	assert(path != NULL);

@@ -1368,7 +1375,8 @@ pkg_add_common(struct pkgdb *db, const char *path, unsigned flags,
	 */
	if (extract) {
		pkg_register_cleanup_callback(pkg_rollback_cb, pkg);
-
		retcode = do_extract(a, ae, nfiles, pkg, local, &tempdirs);
+
		tll_push_back(symlinks_allowed, pkg->prefix);
+
		retcode = do_extract(a, ae, nfiles, pkg, local, &tempdirs, &symlinks_allowed);
		pkg_unregister_cleanup_callback(pkg_rollback_cb, pkg);
		if (retcode != EPKG_OK) {
			/* If the add failed, clean up (silently) */
@@ -1521,6 +1529,8 @@ pkg_add_fromdir(struct pkg *pkg, const char *src)
	size_t link_len;
	bool install_as_user;
	tempdirs_t tempdirs = tll_init();
+
	stringlist_t symlinks_allowed = tll_init();
+
	tll_push_back(symlinks_allowed, pkg->prefix);

	install_as_user = (getenv("INSTALL_AS_USER") != NULL);

@@ -1576,7 +1586,7 @@ pkg_add_fromdir(struct pkg *pkg, const char *src)
#endif
#endif

-
		if (create_dir(pkg, d, &tempdirs) == EPKG_FATAL) {
+
		if (create_dir(pkg, d, &tempdirs, &symlinks_allowed) == EPKG_FATAL) {
			retcode = EPKG_FATAL;
			goto cleanup;
		}
@@ -1648,7 +1658,7 @@ pkg_add_fromdir(struct pkg *pkg, const char *src)
				    "'%s'", f->path);
			}
			target[link_len] = '\0';
-
			if (create_symlinks(pkg, f, target, &tempdirs) == EPKG_FATAL) {
+
			if (create_symlinks(pkg, f, target, &tempdirs, &symlinks_allowed) == EPKG_FATAL) {
				retcode = EPKG_FATAL;
				goto cleanup;
			}
@@ -1669,13 +1679,13 @@ pkg_add_fromdir(struct pkg *pkg, const char *src)
				}
			}
			if (path != NULL) {
-
				if (create_hardlink(pkg, f, path, &tempdirs) == EPKG_FATAL) {
+
				if (create_hardlink(pkg, f, path, &tempdirs, &symlinks_allowed) == EPKG_FATAL) {
					close(fd);
					retcode = EPKG_FATAL;
					goto cleanup;
				}
			} else {
-
				if (create_regfile(pkg, f, NULL, NULL, fd, NULL, &tempdirs) == EPKG_FATAL) {
+
				if (create_regfile(pkg, f, NULL, NULL, fd, NULL, &tempdirs, &symlinks_allowed) == EPKG_FATAL) {
					close(fd);
					retcode = EPKG_FATAL;
					goto cleanup;
@@ -1697,6 +1707,7 @@ pkg_add_fromdir(struct pkg *pkg, const char *src)
	retcode = pkg_extract_finalize(pkg, &tempdirs);

cleanup:
+
	tll_free(symlinks_allowed);
	tll_free_and_free(hardlinks, free);
	close(fromfd);
	return (retcode);
modified libpkg/pkg_audit.c
@@ -692,7 +692,7 @@ pkg_audit_preprocess(struct pkg_audit_entry *h)
	}

	/* Calculate jump indexes for the first byte of the package name */
-
	bzero(audit_entry_first_byte_idx, sizeof(audit_entry_first_byte_idx));
+
	memset(audit_entry_first_byte_idx, '\0', sizeof(audit_entry_first_byte_idx));
	for (n = 1, i = 0; n < 256; n++) {
		while (ret[i].e != NULL &&
		    (size_t)(ret[i].e->pkgname[0]) < n)
modified libpkg/pkg_config.c
@@ -1,5 +1,5 @@
/*
-
 * Copyright (c) 2011-2021 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2024 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2014 Matthew Seaman <matthew@FreeBSD.org>
 * Copyright (c) 2016 Vsevolod Stakhov <vsevolod@FreeBSD.org>
@@ -63,6 +63,8 @@
#define INDEXFILE	"INDEX"
#endif

+
#define dbg(x, ...) pkg_dbg(PKG_DBG_CONFIG, x, __VA_ARGS__)
+

struct pkg_ctx ctx = {
	.eventpipe = -1,
	.debug_level = 0,
@@ -80,6 +82,7 @@ struct pkg_ctx ctx = {
	.triggers = true,
	.compression_format = NULL,
	.compression_level = -1,
+
	.compression_threads = -1,
	.defer_triggers = false,
};

@@ -507,6 +510,18 @@ static struct config_entry c[] = {
		NULL,
		"patterns of files to not extract from the package",
	},
+
	{
+
		PKG_ARRAY,
+
		"PKG_DEBUG_FLAGS",
+
		NULL,
+
		"debug flags to activate",
+
	},
+
	{
+
		PKG_INT,
+
		"COMPRESSION_THREADS",
+
		"-1",
+
		"Set the default number of threads used for compression",
+
	}
};

static bool parsed = false;
@@ -613,7 +628,7 @@ add_repo(const ucl_object_t *obj, struct pkg_repo *r, const char *rname, pkg_ini
	int use_ipvx = 0;
	int priority = 0;

-
	pkg_debug(1, "PkgConfig: parsing repository object %s", rname);
+
	dbg(1, "parsing repository object %s", rname);

	env = NULL;
	enabled = ucl_object_find_key(obj, "enabled");
@@ -626,7 +641,7 @@ add_repo(const ucl_object_t *obj, struct pkg_repo *r, const char *rname, pkg_ini
			 * We basically want to remove the existing repo r and
			 * forget all stuff parsed
			 */
-
			pkg_debug(1, "PkgConfig: disabling repo %s", rname);
+
			dbg(1, "disabling repo %s", rname);
			DL_DELETE(repos, r);
			pkg_repo_free(r);
			return;
@@ -715,7 +730,7 @@ add_repo(const ucl_object_t *obj, struct pkg_repo *r, const char *rname, pkg_ini
	}

	if (r == NULL && url == NULL) {
-
		pkg_debug(1, "No repo and no url for %s", rname);
+
		dbg(1, "No repo and no url for %s", rname);
		return;
	}

@@ -786,10 +801,10 @@ add_repo_obj(const ucl_object_t *obj, const char *file, pkg_init_flags flags)
	const char *key;

	key = ucl_object_key(obj);
-
	pkg_debug(1, "PkgConfig: parsing repo key '%s' in file '%s'", key, file);
+
	dbg(1, "parsing repo key '%s' in file '%s'", key, file);
	r = pkg_repo_find(key);
	if (r != NULL)
-
		pkg_debug(1, "PkgConfig: overwriting repository %s", key);
+
		dbg(1, "overwriting repository %s", key);
       add_repo(obj, r, key, flags);
}

@@ -804,10 +819,10 @@ walk_repo_obj(const ucl_object_t *obj, const char *file, pkg_init_flags flags)

	while ((cur = ucl_iterate_object(obj, &it, true))) {
		key = ucl_object_key(cur);
-
		pkg_debug(1, "PkgConfig: parsing key '%s'", key);
+
		dbg(1, "parsing key '%s'", key);
		r = pkg_repo_find(key);
		if (r != NULL)
-
			pkg_debug(1, "PkgConfig: overwriting repository %s", key);
+
			dbg(1, "overwriting repository %s", key);
		if (cur->type == UCL_OBJECT)
			add_repo(cur, r, key, flags);
		else {
@@ -858,7 +873,7 @@ load_repo_file(int dfd, const char *repodir, const char *repofile,
	errno = 0;
	obj = NULL;

-
	pkg_debug(1, "PKgConfig: loading %s/%s", repodir, repofile);
+
	dbg(1, "loading %s/%s", repodir, repofile);
	fd = openat(dfd, repofile, O_RDONLY);
	if (fd == -1) {
		pkg_errno("Unable to open '%s/%s'", repodir, repofile);
@@ -911,7 +926,7 @@ load_repo_files(const char *repodir, pkg_init_flags flags, struct os_info *oi)
	struct dirent **ent;
	int nents, i, fd;

-
	pkg_debug(1, "PkgConfig: loading repositories in %s", repodir);
+
	dbg(1, "loading repositories in %s", repodir);
	if ((fd = open(repodir, O_DIRECTORY|O_CLOEXEC)) == -1)
		return;

@@ -989,6 +1004,41 @@ type_to_string(int type)
		return ("boolean");
	return ("unknown");
}
+

+
const struct pkg_dbg_flags *
+
_find_flag(const char *str)
+
{
+
	for (size_t i = 0; i < NELEM(debug_flags); i++) {
+
		if (STRIEQ(debug_flags[i].name, str))
+
			return (&debug_flags[i]);
+
	}
+
	return (NULL);
+
}
+
static uint64_t
+
config_validate_debug_flags(const ucl_object_t *o)
+
{
+
	ucl_object_iter_t it = NULL;
+
	const ucl_object_t *cur;
+
	int ret = EPKG_OK;
+
	const struct pkg_dbg_flags *f;
+

+
	if (o == NULL)
+
		return (ret);
+

+
	while ((cur = ucl_iterate_object(o, &it, true))) {
+
		const char *str = ucl_object_tostring(cur);
+
		f = _find_flag(str);
+
		if (f == NULL) {
+
			pkg_emit_error("Invalid debug flag %s",
+
			    ucl_object_tostring(cur));
+
			ret = EPKG_FATAL;
+
			continue;
+
		}
+
		ctx.debug_flags |= f->flag;
+
	}
+
	return (ret);
+
}
+

int
pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
{
@@ -1013,6 +1063,7 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
	struct os_info oi;
	size_t ukeylen;
	int err = EPKG_OK;
+
	const char *envabi;

	k = NULL;
	o = NULL;
@@ -1023,8 +1074,14 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
	}

	memset(&oi, 0, sizeof(oi));
-
	pkg_get_myarch(myabi, BUFSIZ, &oi);
-
	pkg_get_myarch_legacy(myabi_legacy, BUFSIZ);
+
	envabi = getenv("ABI");
+
	if (envabi == NULL) {
+
		pkg_get_myarch(myabi, BUFSIZ, &oi);
+
		pkg_get_myarch_legacy(myabi_legacy, BUFSIZ);
+
	} else {
+
		strlcpy(myabi, envabi, sizeof(myabi));
+
		pkg_arch_to_legacy(myabi, myabi_legacy, BUFSIZ);
+
	}
#ifdef __FreeBSD__
	ctx.osversion = oi.osversion;
	snprintf(myosversion, sizeof(myosversion), "%d", ctx.osversion);
@@ -1326,7 +1383,7 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
		goto out;
	}

-
	pkg_debug(1, "%s", "pkg initialized");
+
	dbg(1, "pkg initialized");

#ifdef __FreeBSD__
	ctx.osversion = pkg_object_int(pkg_config_get("OSVERSION"));
@@ -1337,6 +1394,9 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
		connect_evpipe(evpipe);

	ctx.debug_level = pkg_object_int(pkg_config_get("DEBUG_LEVEL"));
+
	err = config_validate_debug_flags(ucl_object_find_key(config, "PKG_DEBUG_FLAGS"));
+
	if (err != EPKG_OK)
+
		goto out;
	ctx.developer_mode = pkg_object_bool(pkg_config_get("DEVELOPER_MODE"));
	ctx.dbdir = pkg_object_string(pkg_config_get("PKG_DBDIR"));
	ctx.cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR"));
@@ -1346,6 +1406,7 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
	ctx.triggers_path = pkg_object_string(pkg_config_get("PKG_TRIGGERS_DIR"));
	ctx.compression_format = pkg_object_string(pkg_config_get("COMPRESSION_FORMAT"));
	ctx.compression_level = pkg_object_int(pkg_config_get("COMPRESSION_LEVEL"));
+
	ctx.compression_threads = pkg_object_int(pkg_config_get("COMPRESSION_THREADS"));
	ctx.archive_symlink = pkg_object_bool(pkg_config_get("ARCHIVE_SYMLINK"));
	ctx.repo_accept_legacy_pkg = pkg_object_bool(pkg_config_get("REPO_ACCEPT_LEGACY_PKG"));

@@ -1353,7 +1414,7 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
	object = ucl_object_find_key(config, "PKG_ENV");
	while ((cur = ucl_iterate_object(object, &it, true))) {
		evkey = ucl_object_key(cur);
-
		pkg_debug(1, "Setting env var: %s", evkey);
+
		dbg(1, "Setting env var: %s", evkey);
		if (evkey != NULL && evkey[0] != '\0')
			setenv(evkey, ucl_object_tostring_forced(cur), 1);
	}
modified libpkg/pkg_create.c
@@ -216,7 +216,7 @@ pkg_create_archive(struct pkg *pkg, struct pkg_create *pc, unsigned required_fla
	}

	if (packing_init(&pkg_archive, pkg_path, pc->format,
-
	    pc->compression_level, pc->timestamp, pc->overwrite, false) != EPKG_OK) {
+
	    pc->compression_level, pc->compression_threads, pc->timestamp, pc->overwrite, false) != EPKG_OK) {
		pkg_archive = NULL;
	}

@@ -258,6 +258,7 @@ pkg_create_new(void)
	pc = xcalloc(1, sizeof(*pc));
	pc->format = packing_format_from_string(ctx.compression_format);
	pc->compression_level = ctx.compression_level;
+
	pc->compression_threads = ctx.compression_threads;
	pc->timestamp = (time_t) -1;
	pc->overwrite = true;
	pc->expand_manifest = false;
@@ -296,6 +297,12 @@ pkg_create_set_compression_level(struct pkg_create *pc, int clevel)
}

void
+
pkg_create_set_compression_threads(struct pkg_create *pc, int threads)
+
{
+
	pc->compression_threads = threads;
+
}
+

+
void
pkg_create_set_expand_manifest(struct pkg_create *pc, bool expand)
{
	pc->expand_manifest = expand;
modified libpkg/pkg_elf.c
@@ -1093,7 +1093,7 @@ pkg_arch_to_legacy(const char *arch, char *dest, size_t sz)
	int i = 0;
	struct arch_trans *arch_trans;

-
	bzero(dest, sz);
+
	memset(dest, '\0', sz);
	/* Lower case the OS */
	while (arch[i] != ':' && arch[i] != '\0') {
		dest[i] = tolower(arch[i]);
modified libpkg/pkg_event.c
@@ -993,6 +993,44 @@ pkg_debug(int level, const char *fmt, ...)
}

void
+
pkg_dbg(uint64_t flags, int level, const char *fmt, ...)
+
{
+
	struct pkg_event ev;
+
	va_list ap;
+
	xstring *string_fmt = xstring_new();
+
	char *nfmt;
+

+
	if (ctx.debug_level < level)
+
		return;
+

+
	if ((ctx.debug_flags & (flags|PKG_DBG_ALL)) == 0)
+
		return;
+

+
	ev.type = PKG_EVENT_DEBUG;
+
	ev.e_debug.level = level;
+
	for (size_t i = 0; i < NELEM(debug_flags); i++) {
+
		if (flags & debug_flags[i].flag) {
+
			if (string_fmt->size == 0) {
+
				fprintf(string_fmt->fp, "(%s", debug_flags[i].name);
+
				fflush(string_fmt->fp);
+
			} else {
+
				fprintf(string_fmt->fp, "|%s", debug_flags[i].name);
+
			}
+
		}
+
	}
+
	fprintf(string_fmt->fp, ") %s", fmt);
+
	nfmt = xstring_get(string_fmt);
+
	va_start(ap, fmt);
+
	vasprintf(&ev.e_debug.msg, nfmt, ap);
+
	va_end(ap);
+

+
	pkg_emit_event(&ev);
+
	free(ev.e_debug.msg);
+
	free(nfmt);
+
}
+

+

+
void
pkg_emit_backup(void)
{
	struct pkg_event ev;
modified libpkg/pkg_macho.c
@@ -307,7 +307,7 @@ pkg_arch_to_legacy(const char *arch, char *dest, size_t sz)
	const char *arch_name;
	bool is64;

-
	bzero(dest, sz);
+
	memset(dest, '\0', sz);
	/* Lower case the OS */
	while (arch[i] != ':' && arch[i] != '\0') {
		dest[i] = tolower(arch[i]);
modified libpkg/pkg_manifest.c
@@ -43,6 +43,8 @@
#include "private/pkg.h"
#include "private/utils.h"

+
#define dbg(x, ...) pkg_dbg(PKG_DBG_MANIFEST, x, __VA_ARGS__)
+

enum {
	MANIFEST_ANNOTATIONS,
	MANIFEST_CATEGORIES,
@@ -380,7 +382,7 @@ pkg_array(struct pkg *pkg, const ucl_object_t *obj, uint32_t attr)
	ucl_object_iter_t it = NULL;
	int ret;

-
	pkg_debug(3, "%s", "Manifest: parsing array");
+
	dbg(3, "%s", "parsing array");
	while ((cur = ucl_iterate_object(obj, &it, true))) {
		switch (attr) {
		case MANIFEST_CATEGORIES:
@@ -477,7 +479,7 @@ pkg_obj(struct pkg *pkg, const ucl_object_t *obj, uint32_t attr)
	const char *key, *buf;
	size_t len;

-
	pkg_debug(3, "%s", "Manifest: parsing object");
+
	dbg(3, "%s", "parsing object");
	while ((cur = ucl_iterate_object(obj, &it, true))) {
		key = ucl_object_key(cur);
		if (key == NULL)
@@ -635,7 +637,7 @@ pkg_set_files_from_object(struct pkg *pkg, const ucl_object_t *obj)
			else
				perm = getmode(set, 0);
		} else {
-
			pkg_debug(1, "Skipping unknown key for file(%s): %s",
+
			dbg(1, "Skipping unknown key for file(%s): %s",
			    fname->buf, key);
		}
	}
@@ -681,7 +683,7 @@ pkg_set_dirs_from_object(struct pkg *pkg, const ucl_object_t *obj)
		} else if (!strcasecmp(key, "try") && cur->type == UCL_BOOLEAN) {
			/* ignore on purpose : compatibility*/
		} else {
-
			pkg_debug(1, "Skipping unknown key for dir(%s): %s",
+
			dbg(1, "Skipping unknown key for dir(%s): %s",
			    dirname->buf, key);
		}
	}
@@ -706,7 +708,7 @@ pkg_set_deps_from_object(struct pkg *pkg, const ucl_object_t *obj)
	okey = ucl_object_key(obj);
	if (okey == NULL)
		return (EPKG_FATAL);
-
	pkg_debug(2, "Found %s", okey);
+
	dbg(2, "Found %s", okey);
	while ((self = ucl_iterate_object(obj, &it, (obj->type == UCL_ARRAY)))) {
		it2 = NULL;
		while ((cur = ucl_iterate_object(self, &it2, true))) {
@@ -760,9 +762,9 @@ parse_manifest(struct pkg *pkg, ucl_object_t *obj)
		key = ucl_object_key(cur);
		if (key == NULL)
			continue;
-
		pkg_debug(3, "Manifest: found key: '%s'", key);
+
		dbg(3, "found key: '%s'", key);
		if ((selected_key = select_manifest_key(key)) == NULL) {
-
			pkg_debug(1, "Skipping unknown key '%s'", key);
+
			dbg(1, "Skipping unknown key '%s'", key);
			continue;
		}
		if (TYPE_SHIFT(ucl_object_type(cur)) & selected_key->valid_type) {
@@ -812,7 +814,7 @@ pkg_parse_manifest(struct pkg *pkg, const char *buf, size_t len)
	assert(pkg != NULL);
	assert(buf != NULL);

-
	pkg_debug(2, "%s", "Parsing manifest from buffer");
+
	dbg(2, "%s", "Parsing from buffer");

	p = ucl_parser_new(UCL_PARSER_NO_FILEVARS);
	if (!ucl_parser_add_chunk(p, buf, len)) {
@@ -847,7 +849,7 @@ pkg_parse_manifest_fileat(int dfd, struct pkg *pkg, const char *file)
	assert(pkg != NULL);
	assert(file != NULL);

-
	pkg_debug(1, "Parsing manifest from '%s'", file);
+
	dbg(1, "Parsing from '%s'", file);

	errno = 0;

@@ -949,7 +951,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
		pkg->abi = xstrdup(pkg->arch);
	pkg_arch_to_legacy(pkg->abi, legacyarch, BUFSIZ);
	pkg->arch = xstrdup(legacyarch);
-
	pkg_debug(4, "Emitting basic metadata");
+
	dbg(4, "Emitting basic metadata");
	MANIFEST_EXPORT_FIELD(top, pkg, name, string);
	MANIFEST_EXPORT_FIELD(top, pkg, origin, string);
	MANIFEST_EXPORT_FIELD(top, pkg, version, string);
@@ -989,7 +991,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
		break;
	}

-
	pkg_debug(4, "Emitting licenses");
+
	dbg(4, "Emitting licenses");
	seq = NULL;
	tll_foreach(pkg->licenses, l) {
		if (seq == NULL)
@@ -1011,7 +1013,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
			"desc", 4, false);
	}

-
	pkg_debug(4, "Emitting deps");
+
	dbg(4, "Emitting deps");
	map = NULL;
	while (pkg_deps(pkg, &dep) == EPKG_OK) {
		submap = ucl_object_typed_new(UCL_OBJECT);
@@ -1024,7 +1026,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
	if (map)
		ucl_object_insert_key(top, map, "deps", 4, false);

-
	pkg_debug(4, "Emitting categories");
+
	dbg(4, "Emitting categories");
	seq = NULL;
	tll_foreach(pkg->categories, c) {
		if (seq == NULL)
@@ -1034,7 +1036,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
	if (seq)
		ucl_object_insert_key(top, seq, "categories", 10, false);

-
	pkg_debug(4, "Emitting users");
+
	dbg(4, "Emitting users");
	seq = NULL;
	tll_foreach(pkg->users, u) {
		if (seq == NULL)
@@ -1044,7 +1046,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
	if (seq)
		ucl_object_insert_key(top, seq, "users", 5, false);

-
	pkg_debug(4, "Emitting groups");
+
	dbg(4, "Emitting groups");
	seq = NULL;
	tll_foreach(pkg->groups, g) {
		if (seq == NULL)
@@ -1054,7 +1056,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
	if (seq)
		ucl_object_insert_key(top, seq, "groups", 6, false);

-
	pkg_debug(4, "Emitting shibs_required");
+
	dbg(4, "Emitting shibs_required");
	seq = NULL;
	tll_foreach(pkg->shlibs_required, s) {
		if (seq == NULL)
@@ -1064,7 +1066,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
	if (seq)
		ucl_object_insert_key(top, seq, "shlibs_required", 15, false);

-
	pkg_debug(4, "Emitting shlibs_provided");
+
	dbg(4, "Emitting shlibs_provided");
	seq = NULL;
	tll_foreach(pkg->shlibs_provided, s) {
		if (seq == NULL)
@@ -1074,7 +1076,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
	if (seq)
		ucl_object_insert_key(top, seq, "shlibs_provided", 15, false);

-
	pkg_debug(4, "Emitting conflicts");
+
	dbg(4, "Emitting conflicts");
	seq = NULL;
	while (pkg_conflicts(pkg, &conflict) == EPKG_OK) {
		if (seq == NULL)
@@ -1084,7 +1086,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
	if (seq)
		ucl_object_insert_key(top, seq, "conflicts", 9, false);

-
	pkg_debug(4, "Emitting provides");
+
	dbg(4, "Emitting provides");
	seq = NULL;
	tll_foreach(pkg->provides, p) {
		if (seq == NULL)
@@ -1094,7 +1096,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
	if (seq)
		ucl_object_insert_key(top, seq, "provides", 8, false);

-
	pkg_debug(4, "Emitting requires");
+
	dbg(4, "Emitting requires");
	seq = NULL;
	tll_foreach(pkg->requires, r) {
		if (seq == NULL)
@@ -1104,10 +1106,10 @@ pkg_emit_object(struct pkg *pkg, short flags)
	if (seq)
		ucl_object_insert_key(top, seq, "requires", 8, false);

-
	pkg_debug(4, "Emitting options");
+
	dbg(4, "Emitting options");
	map = NULL;
	while (pkg_options(pkg, &option) == EPKG_OK) {
-
		pkg_debug(2, "Emiting option: %s", option->value);
+
		dbg(4, "Emitting option: %s", option->value);
		if (map == NULL)
			map = ucl_object_typed_new(UCL_OBJECT);
		ucl_object_insert_key(map,
@@ -1135,7 +1137,7 @@ pkg_emit_object(struct pkg *pkg, short flags)

	if ((flags & PKG_MANIFEST_EMIT_COMPACT) == 0) {
		if ((flags & PKG_MANIFEST_EMIT_NOFILES) == 0) {
-
			pkg_debug(4, "Emitting files");
+
			dbg(4, "Emitting files");
			map = NULL;
			while (pkg_files(pkg, &file) == EPKG_OK) {
				char dpath[MAXPATHLEN];
@@ -1163,7 +1165,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
			if (map)
				ucl_object_insert_key(top, map, "files", 5, false);

-
			pkg_debug(3, "Emitting config files");
+
			dbg(4, "Emitting config files");
			seq = NULL;
			while (pkg_config_files(pkg, &cf) == EPKG_OK) {
				urlencode(cf->path, &tmpsbuf);
@@ -1174,7 +1176,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
			if (seq)
				ucl_object_insert_key(top, seq, "config", 6, false);

-
			pkg_debug(4, "Emitting directories");
+
			dbg(4, "Emitting directories");
			map = NULL;
			while (pkg_dirs(pkg, &dir) == EPKG_OK) {
				urlencode(dir->path, &tmpsbuf);
@@ -1188,7 +1190,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
				ucl_object_insert_key(top, map, "directories", 11, false);
		}

-
		pkg_debug(4, "Emitting scripts");
+
		dbg(4, "Emitting scripts");
		map = NULL;
		for (i = 0; i < PKG_NUM_SCRIPTS; i++) {
			if (pkg_script_get(pkg, i) == NULL)
@@ -1225,7 +1227,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
		if (map)
			ucl_object_insert_key(top, map, "scripts", 7, false);

-
		pkg_debug(4, "Emitting lua scripts");
+
		dbg(4, "Emitting lua scripts");
		map = NULL;
		for (i = 0; i < PKG_NUM_LUA_SCRIPTS; i++) {
			if (tll_length(pkg->lua_scripts[i]) == 0)
@@ -1254,7 +1256,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
			ucl_object_insert_key(top, map, "lua_scripts", 11, false);
	}

-
	pkg_debug(4, "Emitting message");
+
	dbg(4, "Emitting message");
	if (pkg_has_message(pkg))  {
		ucl_object_insert_key(top,
			pkg_message_to_ucl(pkg),
modified libpkg/pkg_repo_create.c
@@ -1084,7 +1084,7 @@ pkg_repo_pack_db(const char *name, const char *archive, char *path,
	struct packing *pack;
	int ret = EPKG_OK;

-
	if (packing_init(&pack, archive, prc->meta->packing_format, 0, (time_t)-1, true, true) != EPKG_OK)
+
	if (packing_init(&pack, archive, prc->meta->packing_format, 0, 0, (time_t)-1, true, true) != EPKG_OK)
		return (EPKG_FATAL);

	if (sctx != NULL) {
modified libpkg/pkg_solve.c
@@ -1,7 +1,5 @@
/*-
 * Copyright (c) 2013-2017 Vsevolod Stakhov <vsevolod@FreeBSD.org>
-
 * Copyright (c) 2024 Serenity Cyber Security, LLC <license@futurecrew.ru>
-
 *                    Author: Gleb Popov <arrowd@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
@@ -48,6 +46,8 @@

struct pkg_solve_item;

+
#define dbg(x, ...) pkg_dbg(PKG_DBG_SOLVER, x, __VA_ARGS__)
+

enum pkg_solve_rule_type {
	PKG_RULE_DEPEND = 0,
	PKG_RULE_UPGRADE_CONFLICT,
@@ -55,7 +55,6 @@ enum pkg_solve_rule_type {
	PKG_RULE_REQUEST_CONFLICT,
	PKG_RULE_REQUEST,
	PKG_RULE_REQUIRE,
-
	PKG_RULE_VITAL,
	PKG_RULE_MAX
};

@@ -66,7 +65,6 @@ static const char *rule_reasons[] = {
	[PKG_RULE_EXPLICIT_CONFLICT] = "conflict",
	[PKG_RULE_REQUEST] = "request",
	[PKG_RULE_REQUIRE] = "require",
-
	[PKG_RULE_VITAL] = "vital",
	[PKG_RULE_MAX] = NULL
};

@@ -248,10 +246,6 @@ pkg_print_rule_buf(struct pkg_solve_rule *rule, xstring *sb)
					it->next ? ", " : "");
		}
		break;
-
	case PKG_RULE_VITAL:
-
		fprintf(sb->fp, "The following package is marked vital: %s-%s",
-
				rule->items->var->uid, rule->items->var->unit->pkg->version);
-
		break;
	default:
		break;
	}
@@ -270,7 +264,7 @@ pkg_debug_print_rule(struct pkg_solve_rule *rule)
	pkg_print_rule_buf(rule, sb);

	fflush(sb->fp);
-
	pkg_debug(2, "%s", sb->buf);
+
	dbg(2, "rule: %s", sb->buf);
	xstring_free(sb);
}

@@ -305,7 +299,7 @@ pkg_solve_handle_provide (struct pkg_solve_problem *problem,
			libfound = stringlist_contains(&pkg->shlibs_provided, pr->provide);
			/* Skip incompatible ABI as well */
			if (libfound && strcmp(pkg->arch, orig->arch) != 0) {
-
				pkg_debug(2, "solver: require %s: package %s-%s(%c) provides wrong ABI %s, "
+
				dbg(2, "require %s: package %s-%s(%c) provides wrong ABI %s, "
					"wanted %s", pr->provide, pkg->name, pkg->version,
					pkg->type == PKG_INSTALLED ? 'l' : 'r', pkg->arch, orig->arch);
				continue;
@@ -316,7 +310,7 @@ pkg_solve_handle_provide (struct pkg_solve_problem *problem,
		}

		if (!providefound && !libfound) {
-
			pkg_debug(4, "solver: %s provide is not satisfied by %s-%s(%c)", pr->provide,
+
			dbg(4, "%s provide is not satisfied by %s-%s(%c)", pr->provide,
					pkg->name, pkg->version, pkg->type == PKG_INSTALLED ?
							'l' : 'r');
			continue;
@@ -326,7 +320,7 @@ pkg_solve_handle_provide (struct pkg_solve_problem *problem,
			curvar->assumed_reponame = reponame;
		}

-
		pkg_debug(4, "solver: %s provide is satisfied by %s-%s(%c)", pr->provide,
+
		dbg(4, "%s provide is satisfied by %s-%s(%c)", pr->provide,
				pkg->name, pkg->version, pkg->type == PKG_INSTALLED ?
				'l' : 'r');

@@ -359,7 +353,7 @@ pkg_solve_add_depend_rule(struct pkg_solve_problem *problem,
		depvar = NULL;
		depvar = pkghash_get_value(problem->variables_by_uid, uid);
		if (depvar == NULL) {
-
			pkg_debug(2, "cannot find variable dependency %s", uid);
+
			dbg(2, "cannot find variable dependency %s", uid);
			continue;
		}

@@ -377,7 +371,7 @@ pkg_solve_add_depend_rule(struct pkg_solve_problem *problem,
	}

	if (cnt == 0) {
-
		pkg_debug(2, "cannot find any suitable dependency for %s", var->uid);
+
		dbg(2, "cannot find any suitable dependency for %s", var->uid);
		pkg_solve_rule_free(rule);

		return (EPKG_FATAL);
@@ -402,7 +396,7 @@ pkg_solve_add_conflict_rule(struct pkg_solve_problem *problem,
	uid = conflict->uid;
	confvar = pkghash_get_value(problem->variables_by_uid, uid);
	if (confvar == NULL) {
-
		pkg_debug(2, "cannot find conflict %s", uid);
+
		dbg(2, "cannot find conflict %s", uid);
		return (EPKG_END);
	}

@@ -464,7 +458,7 @@ pkg_solve_add_require_rule(struct pkg_solve_problem *problem,

	prhead = pkghash_get_value(problem->j->universe->provides, requirement);
	if (prhead != NULL) {
-
		pkg_debug(4, "solver: Add require rule: %s-%s(%c) wants %s",
+
		dbg(4, "Add require rule: %s-%s(%c) wants %s",
			pkg->name, pkg->version, pkg->type == PKG_INSTALLED ? 'l' : 'r',
			requirement);
		/* Require rule: ( !A | P1 | P2 | P3 ... ) must be true */
@@ -495,7 +489,7 @@ pkg_solve_add_require_rule(struct pkg_solve_problem *problem,
		 * This is terribly broken now so ignore till provides/requires
		 * are really fixed.
		 */
-
		pkg_debug(1, "solver: for package: %s cannot find provide for requirement: %s",
+
		dbg(1, "for package: %s cannot find provide for requirement: %s",
		    pkg->name, requirement);
	}

@@ -527,7 +521,7 @@ pkg_solve_add_request_rule(struct pkg_solve_problem *problem,
	struct pkg_solve_variable *confvar, *curvar;
	int cnt;

-
	pkg_debug(4, "solver: add variable from %s request with uid %s-%s",
+
	dbg(4, "add variable from %s request with uid %s-%s",
		inverse < 0 ? "delete" : "install", var->uid, var->digest);

	/*
@@ -629,17 +623,6 @@ pkg_solve_add_chain_rule(struct pkg_solve_problem *problem,
}

static int
-
pkg_solve_add_vital_rule(struct pkg_solve_problem *problem,
-
	struct pkg_solve_variable *var)
-
{
-
	struct pkg_solve_rule* rule = pkg_solve_rule_new(PKG_RULE_VITAL);
-
	pkg_solve_item_new(rule, var, 1);
-
	tll_push_front(problem->rules, rule);
-

-
	return (EPKG_OK);
-
}
-

-
static int
pkg_solve_process_universe_variable(struct pkg_solve_problem *problem,
		struct pkg_solve_variable *var)
{
@@ -650,7 +633,6 @@ pkg_solve_process_universe_variable(struct pkg_solve_problem *problem,
	struct pkg_jobs *j = problem->j;
	struct pkg_job_request *jreq = NULL;
	bool chain_added = false;
-
	bool force = j->flags & PKG_FLAG_FORCE;

	LL_FOREACH(var, cur_var) {
		pkg = cur_var->unit->pkg;
@@ -669,10 +651,6 @@ pkg_solve_process_universe_variable(struct pkg_solve_problem *problem,
			cur_var->assumed_reponame = pkg->reponame;
		}

-
		if (pkg->locked || (pkg->vital && !force)) {
-
			pkg_solve_add_vital_rule(problem, cur_var);
-
		}
-

		/* Depends */
		LL_FOREACH(pkg->depends, dep) {
			if (pkg_solve_add_depend_rule(problem, cur_var, dep,
@@ -733,7 +711,7 @@ pkg_solve_add_variable(struct pkg_job_universe_item *un,
		pkg_solve_variable_set(var, ucur);

		if (tvar == NULL) {
-
			pkg_debug(4, "solver: add variable from universe with uid %s", var->uid);
+
			dbg(4, "add variable from universe with uid %s", var->uid);
			pkghash_safe_add(problem->variables_by_uid, var->uid, var, NULL);
			tvar = var;
		}
@@ -796,7 +774,7 @@ pkg_solve_jobs_to_sat(struct pkg_jobs *j)
	}

	if (tll_length(problem->rules) == 0)
-
		pkg_debug(1, "problem has no requests");
+
		dbg(1, "problem has no requests");

	return (problem);
}
@@ -892,12 +870,12 @@ pkg_solve_set_initial_assumption(struct pkg_solve_problem *problem,
			 * We are interested merely in dependencies of top variables
			 * or of previously assumed dependencies
			 */
-
			pkg_debug(4, "solver: not interested in dependencies for %s-%s",
+
			dbg(4, "not interested in dependencies for %s-%s",
					var->unit->pkg->name, var->unit->pkg->version);
			return;
		}
		else {
-
			pkg_debug(4, "solver: examine dependencies for %s-%s",
+
			dbg(4, "examine dependencies for %s-%s",
					var->unit->pkg->name, var->unit->pkg->version);
		}

@@ -950,13 +928,13 @@ pkg_solve_set_initial_assumption(struct pkg_solve_problem *problem,
			LL_FOREACH(var, cvar) {
				if (cvar->unit == selected) {
					picosat_set_default_phase_lit(problem->sat, cvar->order, 1);
-
					pkg_debug(4, "solver: assumed %s-%s(%s) to be installed",
+
					dbg(4, "assumed %s-%s(%s) to be installed",
							selected->pkg->name, selected->pkg->version,
							selected->pkg->type == PKG_INSTALLED ? "l" : "r");
					cvar->flags |= PKG_VAR_ASSUMED_TRUE;
				}
				else {
-
					pkg_debug(4, "solver: assumed %s-%s(%s) to be NOT installed",
+
					dbg(4, "assumed %s-%s(%s) to be NOT installed",
							cvar->unit->pkg->name, cvar->unit->pkg->version,
							cvar->unit->pkg->type == PKG_INSTALLED ? "l" : "r");
					picosat_set_default_phase_lit(problem->sat, cvar->order, -1);
@@ -970,12 +948,6 @@ pkg_solve_set_initial_assumption(struct pkg_solve_problem *problem,
	case PKG_RULE_REQUIRE:
		/* XXX: deal with require rules somehow */
		break;
-
	case PKG_RULE_VITAL:
-
		assert (rule->items != NULL);
-
		item = rule->items;
-
		var = item->var;
-
		picosat_set_default_phase_lit(problem->sat, var->order, 1);
-
		break;
	default:
		/* No nothing */
		return;
@@ -1099,7 +1071,7 @@ reiterate:
			else
				var->flags &= ~PKG_VAR_INSTALL;

-
			pkg_debug(2, "decided %s %s-%s to %s",
+
			dbg(2, "decided %s %s-%s to %s",
					var->unit->pkg->type == PKG_INSTALLED ? "local" : "remote",
							var->uid, var->digest,
							var->flags & PKG_VAR_INSTALL ? "install" : "delete");
@@ -1129,7 +1101,7 @@ reiterate:
				 * iteration to ensure that we have no other choices
				 */
				if (failed_var) {
-
					pkg_debug (1, "trying to delete local package %s-%s on install/upgrade,"
+
					dbg (1, "trying to delete local package %s-%s on install/upgrade,"
							" reiterate on SAT",
							var->unit->pkg->name, var->unit->pkg->version);
					need_reiterate = true;
@@ -1292,7 +1264,7 @@ pkg_solve_insert_res_job (struct pkg_solve_variable *var,
				res->type = (j->type == PKG_JOBS_FETCH) ?
								PKG_SOLVED_FETCH : PKG_SOLVED_INSTALL;
				tll_push_back(j->jobs, res);
-
				pkg_debug(3, "pkg_solve: schedule installation of %s %s",
+
				dbg(3, "pkg_solve: schedule installation of %s %s",
					add_var->uid, add_var->digest);
			}
			else {
@@ -1301,7 +1273,7 @@ pkg_solve_insert_res_job (struct pkg_solve_variable *var,
				res->items[1] = del_var->unit;
				res->type = PKG_SOLVED_UPGRADE;
				tll_push_back(j->jobs, res);
-
				pkg_debug(3, "pkg_solve: schedule upgrade of %s from %s to %s",
+
				dbg(3, "pkg_solve: schedule upgrade of %s from %s to %s",
					del_var->uid, del_var->digest, add_var->digest);
			}
			j->count ++;
@@ -1322,14 +1294,14 @@ pkg_solve_insert_res_job (struct pkg_solve_variable *var,
				res->items[0] = cur_var->unit;
				res->type = PKG_SOLVED_DELETE;
				tll_push_back(j->jobs, res);
-
				pkg_debug(3, "pkg_solve: schedule deletion of %s %s",
+
				dbg(3, "schedule deletion of %s %s",
					cur_var->uid, cur_var->digest);
				j->count ++;
			}
		}
	}
	else {
-
		pkg_debug(2, "solver: ignoring package %s(%s) as its state has not been changed",
+
		dbg(2, "ignoring package %s(%s) as its state has not been changed",
				var->uid, var->digest);
	}
}
@@ -1342,7 +1314,7 @@ pkg_solve_sat_to_jobs(struct pkg_solve_problem *problem)

	while (pkghash_next(&it)) {
		var = (struct pkg_solve_variable *)it.value;
-
		pkg_debug(4, "solver: check variable with uid %s", var->uid);
+
		dbg(4, "check variable with uid %s", var->uid);
		pkg_solve_insert_res_job(var, problem);
	}

modified libpkg/pkgdb.c
@@ -1,5 +1,5 @@
/*-
-
 * Copyright (c) 2011-2023 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2024 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2011 Will Andrews <will@FreeBSD.org>
 * Copyright (c) 2011 Philippe Pepiot <phil@philpep.org>
@@ -10,28 +10,8 @@
 * Copyright (c) 2013-2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
 * Copyright (c) 2023 Serenity Cyber Security, LLC
 *                    Author: Gleb Popov <arrowd@FreeBSD.org>
-
 * All rights reserved.
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#ifdef HAVE_CONFIG_H
@@ -76,6 +56,8 @@

extern struct pkg_ctx ctx;

+
#define dbg(x, ...) pkg_dbg(PKG_DBG_DB, x, __VA_ARGS__)
+

/* An application using a libpkg() DBVERSION is assumed to be compatible
   with:

@@ -810,7 +792,7 @@ pkgdb_profile_callback(unsigned type __unused, void *ud __unused,
	/* According to sqlite3 documentation, nsec has milliseconds accuracy */
	nsec /= 1000000LLU;
	if (nsec > 0)
-
		pkg_debug(1, "Sqlite request %s was executed in %lu milliseconds",
+
		dbg(1, "Sqlite request %s was executed in %lu milliseconds",
			req, (unsigned long)nsec);
	return (0);
}
@@ -1081,7 +1063,7 @@ retry:

	profile = pkg_object_bool(pkg_config_get("SQLITE_PROFILE"));
	if (profile) {
-
		pkg_debug(1, "pkgdb profiling is enabled");
+
		dbg(1, "pkgdb profiling is enabled");
		sqlite3_trace_v2(db->sqlite, SQLITE_TRACE_PROFILE,
		    pkgdb_profile_callback, NULL);
	}
@@ -1198,16 +1180,19 @@ pkgdb_transaction_rollback_sqlite(sqlite3 *sqlite, const char *savepoint)
int
pkgdb_transaction_begin(struct pkgdb *db, const char *savepoint)
{
+
	dbg(2, "new transaction");
	return (pkgdb_transaction_begin_sqlite(db->sqlite, savepoint));
}
int
pkgdb_transaction_commit(struct pkgdb *db, const char *savepoint)
{
+
	dbg(2, "end transaction");
	return (pkgdb_transaction_commit_sqlite(db->sqlite, savepoint));
}
int
pkgdb_transaction_rollback(struct pkgdb *db, const char *savepoint)
{
+
	dbg(2, "end transaction");
	return (pkgdb_transaction_rollback_sqlite(db->sqlite, savepoint));
}

@@ -1575,7 +1560,7 @@ run_prstmt(sql_prstmt_index s, ...)

	va_end(ap);

-
	pkg_debug(4, "Pkgdb, running '%s'", sqlite3_expanded_sql(stmt));
+
	dbg(4, "running '%s'", sqlite3_expanded_sql(stmt));
	retcode = sqlite3_step(stmt);

	return (retcode);
@@ -2060,69 +2045,6 @@ pkgdb_insert_annotations(struct pkg *pkg, int64_t package_id, sqlite3 *s)
}

int
-
pkgdb_reanalyse_shlibs(struct pkgdb *db, struct pkg *pkg)
-
{
-
	sqlite3		*s;
-
	int64_t		 package_id;
-
	int		 ret = EPKG_OK;
-
	int		 i;
-
	const char	*sql[] = {
-
		"DELETE FROM pkg_shlibs_required WHERE package_id = ?1",
-

-
		"DELETE FROM pkg_shlibs_provided WHERE package_id = ?1",
-

-
		"DELETE FROM shlibs "
-
		"WHERE id NOT IN "
-
		"(SELECT DISTINCT shlib_id FROM pkg_shlibs_required)"
-
		"AND id NOT IN "
-
		"(SELECT DISTINCT shlib_id FROM pkg_shlibs_provided)",
-
	};
-

-
	sqlite3_stmt	*stmt_del;
-

-
	assert(db != NULL);
-

-
	if (pkg_is_valid(pkg) != EPKG_OK) {
-
		pkg_emit_error("the package is not valid");
-
		return (EPKG_FATAL);
-
	}
-

-
	if ((ret = pkg_analyse_files(db, pkg, NULL)) == EPKG_OK) {
-
		s = db->sqlite;
-
		package_id = pkg->id;
-

-
		for (i = 0; i < 2; i++) {
-
			/* Clean out old shlibs first */
-
			stmt_del = prepare_sql(db->sqlite, sql[i]);
-
			if (stmt_del == NULL)
-
				return (EPKG_FATAL);
-

-
			sqlite3_bind_int64(stmt_del, 1, package_id);
-
			pkgdb_debug(4, stmt_del);
-

-
			ret = sqlite3_step(stmt_del);
-

-
			if (ret != SQLITE_DONE) {
-
				ERROR_STMT_SQLITE(db->sqlite, stmt_del);
-
				sqlite3_finalize(stmt_del);
-
				return (EPKG_FATAL);
-
			}
-
			sqlite3_finalize(stmt_del);
-
		}
-

-
		if (sql_exec(db->sqlite, sql[2]) != EPKG_OK)
-
			return (EPKG_FATAL);
-

-
		/* Save shlibs */
-
		ret = pkgdb_update_shlibs_required(pkg, package_id, s);
-
		if (ret == EPKG_OK)
-
			ret = pkgdb_update_shlibs_provided(pkg, package_id, s);
-
	}
-

-
	return (ret);
-
}
-

-
int
pkgdb_add_annotation(struct pkgdb *db, struct pkg *pkg, const char *tag,
    const char *value)
{
@@ -2348,7 +2270,7 @@ sql_exec(sqlite3 *s, const char *sql, ...)
		sql_to_exec = sql;
	}

-
	pkg_debug(4, "Pkgdb: executing '%s'", sql_to_exec);
+
	dbg(4, "executing '%s'", sql_to_exec);
	if (sqlite3_exec(s, sql_to_exec, NULL, NULL, &errmsg) != SQLITE_OK) {
		ERROR_SQLITE(s, sql_to_exec);
		sqlite3_free(errmsg);
@@ -2357,7 +2279,7 @@ sql_exec(sqlite3 *s, const char *sql, ...)

	ret = EPKG_OK;

-
	cleanup:
+
cleanup:
	if (sqlbuf != NULL)
		sqlite3_free(sqlbuf);

@@ -2655,7 +2577,7 @@ pkgdb_check_lock_pid(struct pkgdb *db)
		pid = sqlite3_column_int64(stmt, 0);
		if (pid != lpid) {
			if (kill((pid_t)pid, 0) == -1) {
-
				pkg_debug(1, "found stale pid %lld in lock database, my pid is: %lld",
+
				dbg(1, "found stale pid %lld in lock database, my pid is: %lld",
						(long long)pid, (long long)lpid);
				if (pkgdb_remove_lock_pid(db, pid) != EPKG_OK){
					sqlite3_finalize(stmt);
@@ -2717,7 +2639,7 @@ pkgdb_try_lock(struct pkgdb *db, const char *lock_sql, pkgdb_lock_t type,
		ret = sqlite3_exec(db->sqlite, lock_sql, NULL, NULL, NULL);
		if (ret != SQLITE_OK) {
			if (ret == SQLITE_READONLY && type == PKGDB_LOCK_READONLY) {
-
				pkg_debug(1, "want read lock but cannot write to database, "
+
				dbg(1, "want read lock but cannot write to database, "
						"slightly ignore this error for now");
				return (EPKG_OK);
			}
@@ -2728,7 +2650,7 @@ pkgdb_try_lock(struct pkgdb *db, const char *lock_sql, pkgdb_lock_t type,
		if (sqlite3_changes(db->sqlite) == 0) {
			if (pkgdb_check_lock_pid(db) == EPKG_END) {
				/* No live processes found, so we can safely reset lock */
-
				pkg_debug(1, "no concurrent processes found, cleanup the lock");
+
				dbg(1, "no concurrent processes found, cleanup the lock");
				pkgdb_reset_lock(db);

				if (upgrade) {
@@ -2752,7 +2674,7 @@ pkgdb_try_lock(struct pkgdb *db, const char *lock_sql, pkgdb_lock_t type,
			else if (num_timeout > 0) {
				ts.tv_sec = (int)num_timeout;
				ts.tv_nsec = (num_timeout - (int)num_timeout) * 1000000000.;
-
				pkg_debug(1, "waiting for database lock for %d times, "
+
				dbg(1, "waiting for database lock for %d times, "
						"next try in %.2f seconds", tries, num_timeout);
				(void)nanosleep(&ts, NULL);
			}
@@ -2794,14 +2716,14 @@ pkgdb_obtain_lock(struct pkgdb *db, pkgdb_lock_t type)
		if (!ucl_object_toboolean(pkg_config_get("READ_LOCK")))
				return (EPKG_OK);
		lock_sql = readonly_lock_sql;
-
		pkg_debug(1, "want to get a read only lock on a database");
+
		dbg(1, "want to get a read only lock on a database");
		break;
	case PKGDB_LOCK_ADVISORY:
		lock_sql = advisory_lock_sql;
-
		pkg_debug(1, "want to get an advisory lock on a database");
+
		dbg(1, "want to get an advisory lock on a database");
		break;
	case PKGDB_LOCK_EXCLUSIVE:
-
		pkg_debug(1, "want to get an exclusive lock on a database");
+
		dbg(1, "want to get an exclusive lock on a database");
		lock_sql = exclusive_lock_sql;
		break;
	}
@@ -2809,7 +2731,7 @@ pkgdb_obtain_lock(struct pkgdb *db, pkgdb_lock_t type)
	ret = pkgdb_try_lock(db, lock_sql, type, false);

	if (ret != EPKG_OK)
-
		pkg_debug(1, "failed to obtain the lock: %s",
+
		dbg(1, "failed to obtain the lock: %s",
		    sqlite3_errmsg(db->sqlite));

	return (ret);
@@ -2825,7 +2747,7 @@ pkgdb_upgrade_lock(struct pkgdb *db, pkgdb_lock_t old_type, pkgdb_lock_t new_typ
	assert(db != NULL);

	if (old_type == PKGDB_LOCK_ADVISORY && new_type == PKGDB_LOCK_EXCLUSIVE) {
-
		pkg_debug(1, "want to upgrade advisory to exclusive lock");
+
		dbg(1, "want to upgrade advisory to exclusive lock");
		ret = pkgdb_try_lock(db, advisory_exclusive_lock_sql,
				new_type, true);
	}
@@ -2846,7 +2768,7 @@ pkgdb_downgrade_lock(struct pkgdb *db, pkgdb_lock_t old_type,

	if (old_type == PKGDB_LOCK_EXCLUSIVE &&
	    new_type == PKGDB_LOCK_ADVISORY) {
-
		pkg_debug(1, "want to downgrade exclusive to advisory lock");
+
		dbg(1, "want to downgrade exclusive to advisory lock");
		ret = pkgdb_try_lock(db, downgrade_exclusive_lock_sql,
		    new_type, true);
	}
@@ -2875,15 +2797,15 @@ pkgdb_release_lock(struct pkgdb *db, pkgdb_lock_t type)
			return (EPKG_OK);

		unlock_sql = readonly_unlock_sql;
-
		pkg_debug(1, "release a read only lock on a database");
+
		dbg(1, "release a read only lock on a database");

		break;
	case PKGDB_LOCK_ADVISORY:
		unlock_sql = advisory_unlock_sql;
-
		pkg_debug(1, "release an advisory lock on a database");
+
		dbg(1, "release an advisory lock on a database");
		break;
	case PKGDB_LOCK_EXCLUSIVE:
-
		pkg_debug(1, "release an exclusive lock on a database");
+
		dbg(1, "release an exclusive lock on a database");
		unlock_sql = exclusive_unlock_sql;
		break;
	}
@@ -3059,6 +2981,6 @@ pkgdb_debug(int level, sqlite3_stmt *stmt)
		return;

	str = sqlite3_expanded_sql(stmt);
-
	pkg_debug(level, "Pkgdb: running: '%s'", str);
+
	dbg(level, "running: '%s'", str);
	sqlite3_free(str);
}
modified libpkg/private/event.h
@@ -1,5 +1,5 @@
/*-
-
 * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2024 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
 * Copyright (c) 2015 Matthew Seaman <matthew@FreeBSD.org>
@@ -32,6 +32,8 @@
#ifndef _PKG_EVENT
#define _PKG_EVENT

+
#include <stdint.h>
+

#ifndef PKG_FORMAT_ATTRIBUTE
#ifdef __GNUC__
#define PKG_FORMAT_ATTRIBUTE(x, y) __attribute__ ((format (printf, (x), (y))));
@@ -50,6 +52,33 @@ void pkg_emit_pkg_errno(pkg_error_t err, const char *func, const char *arg);
	return (EPKG_FATAL);           \
} while (0);

+
typedef enum {
+
	PKG_DBG_NONE = (1UL << 0),
+
	PKG_DBG_FETCH = (1UL << 1),
+
	PKG_DBG_CONFIG = (1UL << 2),
+
	PKG_DBG_PACKING = (1UL << 3),
+
	PKG_DBG_DB = (1UL << 4),
+
	PKG_DBG_MANIFEST = (1UL << 5),
+
	PKG_DBG_SOLVER = (1UL << 6),
+
	PKG_DBG_ALL = (1UL << 63),
+
} pkg_debug_flags;
+

+
struct pkg_dbg_flags {
+
	uint64_t flag;
+
	const char *name;
+
};
+

+
static const struct pkg_dbg_flags debug_flags[] = {
+
	{ PKG_DBG_NONE, "none" },
+
	{ PKG_DBG_FETCH, "fetch" },
+
	{ PKG_DBG_CONFIG, "config" },
+
	{ PKG_DBG_PACKING, "packing" },
+
	{ PKG_DBG_DB, "db" },
+
	{ PKG_DBG_MANIFEST, "manifest" },
+
	{ PKG_DBG_SOLVER, "solver" },
+
	{ PKG_DBG_ALL, "all" },
+
};
+

void pkg_emit_already_installed(struct pkg *p);
void pkg_emit_fetch_begin(const char *url);
void pkg_emit_fetch_finished(const char *url);
@@ -79,6 +108,7 @@ void pkg_emit_incremental_update(const char *reponame, int processed);
void pkg_emit_backup(void);
void pkg_emit_restore(void);
void pkg_debug(int level, const char *fmt, ...) PKG_FORMAT_ATTRIBUTE(2, 3);
+
void pkg_dbg(uint64_t flag, int level, const char *fmt, ...) PKG_FORMAT_ATTRIBUTE(3, 4);
int pkg_emit_sandbox_call(pkg_sandbox_cb call, int fd, void *ud);
int pkg_emit_sandbox_get_string(pkg_sandbox_cb call, void *ud, char **str, int64_t *len);

modified libpkg/private/packing.h
@@ -2,7 +2,7 @@
 * Copyright (c) 2011-2021 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011 Will Andrews <will@FreeBSD.org>
 * All rights reserved.
-
 * 
+
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
@@ -12,7 +12,7 @@
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
-
 * 
+
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
@@ -35,5 +35,5 @@ struct packing {
	time_t timestamp;
};

-
const char *packing_set_format(struct archive *a, pkg_formats format, int clevel);
+
const char *packing_set_format(struct archive *a, pkg_formats format, int clevel, int threads);
#endif
modified libpkg/private/pkg.h
@@ -122,7 +122,6 @@
#define DL_FREE(head, free_func) DL_FREE2(head, free_func, prev, next)

typedef tll(struct pkg_kv *) kvlist_t;
-
typedef tll(char *) stringlist_t;

typedef enum {
	IPALL = 0,
@@ -151,12 +150,14 @@ struct pkg_stringlist_iterator {
struct pkg_ctx {
	int eventpipe;
	int64_t debug_level;
+
	uint64_t debug_flags;
	bool developer_mode;
	const char *pkg_rootdir;
	const char *dbdir;
	const char *cachedir;
	const char *compression_format;
	int compression_level;
+
	int compression_threads;
	int rootfd;
	int cachedirfd;
	int devnullfd;
@@ -298,6 +299,7 @@ struct pkg_create {
	bool overwrite;
	bool expand_manifest;
	int compression_level;
+
	int compression_threads;
	pkg_formats format;
	time_t timestamp;
	const char *rootdir;
@@ -713,7 +715,7 @@ void pkg_config_file_free(struct pkg_config_file *);
struct iovec;
struct packing;

-
int packing_init(struct packing **pack, const char *path, pkg_formats format, int clevel, time_t timestamp, bool overwrite, bool archive_symlink);
+
int packing_init(struct packing **pack, const char *path, pkg_formats format, int clevel, int threads, time_t timestamp, bool overwrite, bool archive_symlink);
int packing_append_file_attr(struct packing *pack, const char *filepath,
     const char *newpath, const char *uname, const char *gname, mode_t perm,
     u_long fflags);
modified libpkg/private/utils.h
@@ -39,8 +39,11 @@
#include <xstring.h>

#define STARTS_WITH(string, needle) (strncasecmp(string, needle, strlen(needle)) == 0)
+
#define STRIEQ(string, needle) (strcasecmp(string, needle) == 0)
#define RELATIVE_PATH(p) (p + (*p == '/' ? 1 : 0))

+
typedef tll(char *) stringlist_t;
+

#define ERROR_SQLITE(db, query) do { \
	pkg_emit_error("sqlite error while executing %s in file %s:%d: %s", query, \
	__FILE__, __LINE__, sqlite3_errmsg(db)); \
@@ -114,7 +117,7 @@ char *rtrimspace(char *buf);
void hidden_tempfile(char *buf, int buflen, const char *path);
void append_random_suffix(char *buf, int buflen, int suffixlen);
char *json_escape(const char *str);
-
struct tempdir *open_tempdir(int rootfd, const char *path);
+
struct tempdir *open_tempdir(int rootfd, const char *path, stringlist_t *strlist);
const char *get_http_auth(void);

#endif
modified libpkg/repo/binary/common.c
@@ -230,13 +230,14 @@ pkg_repo_binary_run_prstatement(sql_prstmt_index s, ...)
	return (retcode);
}

+
/*
+
 * Returns a path relative to the dbdir.
+
 */
const char *
pkg_repo_binary_get_filename(struct pkg_repo *repo)
{
	if (repo->dbpath == NULL)
-
		xasprintf(&repo->dbpath, "%s/repos/%s/db", ctx.dbdir,
-
		    repo->name);
-

+
		xasprintf(&repo->dbpath, "repos/%s/db", repo->name);
	return (repo->dbpath);
}

@@ -254,5 +255,4 @@ pkg_repo_binary_finalize_prstatements(void)
			STMT(i) = NULL;
		}
	}
-
	return;
}
modified libpkg/repo/binary/init.c
@@ -219,7 +219,7 @@ pkg_repo_binary_open(struct pkg_repo *repo, unsigned mode)
			repo->name);
		sqlite3_close(sqlite);
		if (mode & W_OK)
-
			unlink(filepath);
+
			(void)unlinkat(dbdirfd, filepath, 0);
		return (EPKG_REPOSCHEMA);
	}

@@ -249,14 +249,14 @@ pkg_repo_binary_open(struct pkg_repo *repo, unsigned mode)
int
pkg_repo_binary_create(struct pkg_repo *repo)
{
-
	char filepath[MAXPATHLEN];
+
	const char *filepath;
	sqlite3 *sqlite = NULL;
	int retcode, dbdirfd;

	sqlite3_initialize();

	dbdirfd = pkg_get_dbdirfd();
-
	snprintf(filepath, sizeof(filepath), "repos/%s/db", repo->name);
+
	filepath = pkg_repo_binary_get_filename(repo);
	/* Should never ever happen */
	if (faccessat(dbdirfd, filepath, R_OK, 0) == 0)
		return (EPKG_CONFLICT);
modified libpkg/repo/binary/query.c
@@ -187,7 +187,7 @@ pkg_repo_binary_query(struct pkg_repo *repo, const char *cond, const char *patte
	sqlite3_stmt	*stmt = NULL;
	char *sql = NULL;
	const char	*comp = NULL;
-
	char basesql_quick[] = ""
+
	const char basesql_quick[] = ""
		"SELECT DISTINCT(p.id), origin, p.name, p.name as uniqueid, version, comment, "
		"prefix, desc, arch, maintainer, www, "
		"licenselogic, flatsize, pkgsize, "
@@ -196,7 +196,7 @@ pkg_repo_binary_query(struct pkg_repo *repo, const char *cond, const char *patte
		" %s "
		"%s%s%s "
		"ORDER BY p.name;";
-
	char basesql[] = ""
+
	const char basesql[] = ""
		"WITH flavors AS "
		"  (SELECT package_id, value.annotation AS flavor FROM pkg_annotation "
		"   LEFT JOIN annotation tag ON pkg_annotation.tag_id = tag.annotation_id "
@@ -214,10 +214,8 @@ pkg_repo_binary_query(struct pkg_repo *repo, const char *cond, const char *patte
		" %s "
		"%s%s%s "
		"ORDER BY p.name;";
-
	char *bsql = basesql;

-
	if (match == MATCH_INTERNAL)
-
		bsql = basesql_quick;
+
	const char *bsql = (match == MATCH_INTERNAL) ? basesql_quick : basesql;

	if (match != MATCH_ALL && (pattern == NULL || pattern[0] == '\0'))
		return (NULL);
@@ -361,6 +359,7 @@ pkg_repo_binary_require(struct pkg_repo *repo, const char *provide)

	return (pkg_repo_binary_it_new(repo, stmt, PKGDB_IT_FLAG_ONCE));
}
+

static const char *
pkg_repo_binary_search_how(match_t match)
{
@@ -397,7 +396,7 @@ static int
pkg_repo_binary_build_search_query(xstring *sql, match_t match,
    pkgdb_field field, pkgdb_field sort)
{
-
	const char	*how = NULL;
+
	const char	*how;
	const char	*what = NULL;
	const char	*orderby = NULL;

modified libpkg/repo/binary/update.c
@@ -685,7 +685,7 @@ pkg_repo_binary_update(struct pkg_repo *repo, bool force)
	char *lockpath = NULL;
	const char update_finish_sql[] = ""
		"DROP TABLE repo_update;";
-
	const char *filename;
+
	char filename[PATH_MAX];
	sqlite3 *sqlite;

	struct stat st;
@@ -701,7 +701,8 @@ pkg_repo_binary_update(struct pkg_repo *repo, bool force)

	pkg_debug(1, "PkgRepo: verifying update for %s", repo->name);

-
	filename = pkg_repo_binary_get_filename(repo);
+
	(void)snprintf(filename, sizeof(filename), "%s/%s",
+
	    ctx.dbdir, pkg_repo_binary_get_filename(repo));

	/* First of all, try to open and init repo and check whether it is fine */
	if (repo->dfd == -1 && pkg_repo_open(repo) == EPKG_FATAL)
modified libpkg/utils.c
@@ -704,7 +704,8 @@ pkg_absolutepath(const char *src, char *dest, size_t dest_size, bool fromroot) {
	const char *cur, *next;

	src_len = strlen(src);
-
	bzero(dest, dest_size);
+
	memset(dest, '\0', dest_size);
+

	if (src_len != 0 && src[0] != '/') {
		if (fromroot)
			*dest = '/';
@@ -967,7 +968,7 @@ json_escape(const char *str)
}

struct tempdir *
-
open_tempdir(int rootfd, const char *path)
+
open_tempdir(int rootfd, const char *path, stringlist_t *symlinks_allowed)
{
	struct stat st;
	char walk[MAXPATHLEN];
@@ -979,12 +980,19 @@ open_tempdir(int rootfd, const char *path)
	while ((dir = strrchr(walk, '/')) != NULL) {
		*dir = '\0';
		cnt++;
-
		/* accept symlinks pointing to directories */
+
		/* accept symlinks pointing to directories only for prefix */
		len = strlen(walk);
		if (len == 0 && cnt == 1)
			break;
		if (len > 0) {
-
			if (fstatat(rootfd, RELATIVE_PATH(walk), &st, 0) == -1)
+
			int flag = AT_SYMLINK_NOFOLLOW;
+
			if (symlinks_allowed != NULL) {
+
				tll_foreach(*symlinks_allowed, t) {
+
					if (strcmp(RELATIVE_PATH(walk), RELATIVE_PATH(t->item)) == 0)
+
						flag = 0;
+
				}
+
			}
+
			if (fstatat(rootfd, RELATIVE_PATH(walk), &st, flag) == -1)
				continue;
			if (S_ISDIR(st.st_mode) && cnt == 1)
				break;
modified src/audit.c
@@ -2,28 +2,9 @@
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2014-2015 Matthew Seaman <matthew@FreeBSD.org>
 * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
-
 * All rights reserved.
+
 * Copyright (c) 2011-2024 Baptiste Daroussin <matthew@FreeBSD.org>
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include "pkg_config.h"
@@ -35,6 +16,7 @@
#include <archive.h>
#include <err.h>
#include <errno.h>
+
#include <fts.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <getopt.h>
@@ -208,6 +190,7 @@ exec_audit(int argc, char **argv)
	char			*name;
	char			*version;
	char			*audit_file = NULL;
+
	char			*dirname = NULL;
	int			 affected = 0, vuln = 0;
	bool			 fetch = false, recursive = false;
	int			 ch, i;
@@ -219,6 +202,7 @@ exec_audit(int argc, char **argv)
	ucl_object_t		*obj = NULL;

	struct option longopts[] = {
+
		{ "directory",	required_argument,	NULL,	'd' },
		{ "fetch",	no_argument,		NULL,	'F' },
		{ "file",	required_argument,	NULL,	'f' },
		{ "recursive",	no_argument,	NULL,	'r' },
@@ -227,8 +211,11 @@ exec_audit(int argc, char **argv)
		{ NULL,		0,			NULL,	0   },
	};

-
	while ((ch = getopt_long(argc, argv, "+Ff:qrR::", longopts, NULL)) != -1) {
+
	while ((ch = getopt_long(argc, argv, "+d:Ff:qrR::", longopts, NULL)) != -1) {
		switch (ch) {
+
		case 'd':
+
			dirname = optarg;
+
			break;
		case 'F':
			fetch = true;
			break;
@@ -273,6 +260,11 @@ exec_audit(int argc, char **argv)
			return (EXIT_FAILURE);
		}
	}
+
	if (dirname != NULL && argc > 1) {
+
		warnx("No argument expected with -d");
+
		usage_audit();
+
		return (EXIT_FAILURE);
+
	}

	if (pkg_audit_load(audit, audit_file) != EPKG_OK) {
		if (errno == ENOENT)
@@ -288,7 +280,35 @@ exec_audit(int argc, char **argv)
	}

	check = pkghash_new();
-
	if (argc >= 1) {
+
	if (dirname != NULL) {
+
		char * path[2];
+
		FTSENT *fts_ent;
+
		path[0] = dirname;
+
		path[1] = NULL;
+
		FTS *fts = fts_open(path, FTS_PHYSICAL|FTS_NOSTAT, NULL);
+
		if (fts == NULL)
+
			err(EXIT_FAILURE, "fts_open(%s)", dirname);
+
		while ((fts_ent = fts_read(fts)) != NULL) {
+
			char *ext = strrchr(fts_ent->fts_name, '.');
+
			if (ext == NULL)
+
				continue;
+
			if (strcmp(ext, ".pkg") != 0)
+
				continue;
+
			*ext = '\0';
+
			ext = strrchr(fts_ent->fts_name, '-');
+
			if (ext == NULL)
+
				continue;
+
			*ext = '\0';
+
			ext++;
+
			if (pkg_new(&pkg, PKG_FILE) != EPKG_OK)
+
				err(EXIT_FAILURE, "malloc");
+
			pkg_set(pkg, PKG_ATTR_NAME, fts_ent->fts_name);
+
			pkg_set(pkg, PKG_ATTR_VERSION, ext);
+
			add_to_check(check, pkg);
+
			pkg = NULL;
+
		}
+
		fts_close(fts);
+
	} else if (argc >= 1) {
		for (i = 0; i < argc; i ++) {
			name = argv[i];
			version = strrchr(name, '-');
@@ -466,7 +486,7 @@ exec_audit(int argc, char **argv)

		if (top == NULL) {
			if (!quiet)
-
				printf("%u problem(s) in %u installed package(s) found.\n",
+
				printf("%u problem(s) in %u package(s) found.\n",
				   affected, vuln);

		} else {
modified src/check.c
@@ -1,30 +1,10 @@
/*-
-
 * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2024 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
 * Copyright (c) 2014 Matthew Seaman <matthew@FreeBSD.org>
 * Copyright (c) 2016 Vsevolod Stakhov <vsevolod@FreeBSD.org>
-
 * All rights reserved.
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <sys/param.h>
@@ -246,9 +226,9 @@ void
usage_check(void)
{
	fprintf(stderr,
-
	    "Usage: pkg check -B|-d[n]|-s|-r [-qvy] -a\n");
+
	    "Usage: pkg check -d[n]|-s [-qvy] -a\n");
	fprintf(stderr,
-
	    "       pkg check -B|-d[n]|-s|-r [-qvy] [-Cgix] <pattern>\n\n");
+
	    "       pkg check -d[n]|-s [-qvy] [-Cgix] <pattern>\n\n");
	fprintf(stderr, "For more information see 'pkg help check'.\n");
}

@@ -265,8 +245,6 @@ exec_check(int argc, char **argv)
	int ch;
	bool dcheck = false;
	bool checksums = false;
-
	bool recompute = false;
-
	bool reanalyse_shlibs = false;
	bool noinstall = false;
	int nbpkgs = 0;
	int i, processed, total = 0;
@@ -299,8 +277,7 @@ exec_check(int argc, char **argv)
			match = MATCH_ALL;
			break;
		case 'B':
-
			reanalyse_shlibs = true;
-
			flags |= PKG_LOAD_FILES;
+
			/* backward compatibility but do nothing */
			break;
		case 'C':
			pkgdb_set_case_sensitivity(true);
@@ -322,8 +299,7 @@ exec_check(int argc, char **argv)
			quiet = true;
			break;
		case 'r':
-
			recompute = true;
-
			flags |= PKG_LOAD_FILES;
+
			/* backward compatibility but do nothing */
			break;
		case 's':
			checksums = true;
@@ -347,18 +323,14 @@ exec_check(int argc, char **argv)
	argv += optind;

	/* Default to all packages if no pkg provided */
-
	if (argc == 0 && (dcheck || checksums || recompute || reanalyse_shlibs)) {
+
	if (argc == 0 && (dcheck || checksums)) {
		match = MATCH_ALL;
-
	} else if ((argc == 0 && match != MATCH_ALL) || !(dcheck || checksums || recompute || reanalyse_shlibs)) {
+
	} else if ((argc == 0 && match != MATCH_ALL) || !(dcheck || checksums)) {
		usage_check();
		return (EXIT_FAILURE);
	}

-
	if (recompute || reanalyse_shlibs)
-
		ret = pkgdb_access(PKGDB_MODE_READ|PKGDB_MODE_WRITE,
-
				   PKGDB_DB_LOCAL);
-
	else
-
		ret = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL);
+
	ret = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL);

	if (ret == EPKG_ENODB) {
		if (!quiet)
@@ -372,21 +344,10 @@ exec_check(int argc, char **argv)
		return (EXIT_FAILURE);
	}

-
	if (pkgdb_access(PKGDB_MODE_WRITE, PKGDB_DB_LOCAL) == EPKG_ENOACCESS) {
-
		warnx("Insufficient privileges");
-
		return (EXIT_FAILURE);
-
	}
-

	ret = pkgdb_open(&db, PKGDB_DEFAULT);
	if (ret != EPKG_OK)
		return (EXIT_FAILURE);

-
	if (pkgdb_obtain_lock(db, PKGDB_LOCK_ADVISORY) != EPKG_OK) {
-
		pkgdb_close(db);
-
		warnx("Cannot get an advisory lock on a database, it is locked by another process");
-
		return (EXIT_FAILURE);
-
	}
-

	i = 0;
	nbdone = 0;
	do {
@@ -451,41 +412,6 @@ exec_check(int argc, char **argv)
					rc = EXIT_FAILURE;
				}
			}
-
			if (recompute) {
-
				if (pkgdb_upgrade_lock(db, PKGDB_LOCK_ADVISORY,
-
						PKGDB_LOCK_EXCLUSIVE) == EPKG_OK) {
-
					if (!quiet && verbose)
-
						printf(" recomputing...");
-
					if (pkg_recompute(db, pkg) != EPKG_OK) {
-
						rc = EXIT_FAILURE;
-
					}
-
					pkgdb_downgrade_lock(db,
-
					    PKGDB_LOCK_EXCLUSIVE,
-
					    PKGDB_LOCK_ADVISORY);
-
				}
-
				else {
-
					rc = EXIT_FAILURE;
-
				}
-
			}
-
			if (reanalyse_shlibs) {
-
				if (pkgdb_upgrade_lock(db, PKGDB_LOCK_ADVISORY,
-
						PKGDB_LOCK_EXCLUSIVE) == EPKG_OK) {
-
					if (!quiet && verbose)
-
						printf(" shared libraries...");
-
					if (pkgdb_reanalyse_shlibs(db, pkg) != EPKG_OK) {
-
						pkg_fprintf(stderr, "Failed to "
-
						    "reanalyse for shlibs: "
-
						    "%n-%v\n", pkg, pkg);
-
						rc = EXIT_FAILURE;
-
					}
-
					pkgdb_downgrade_lock(db,
-
					    PKGDB_LOCK_EXCLUSIVE,
-
					    PKGDB_LOCK_ADVISORY);
-
				}
-
				else {
-
					rc = EXIT_FAILURE;
-
				}
-
			}

			if (!quiet) {
				if (!verbose)
@@ -536,7 +462,6 @@ cleanup:
	xstring_free(msg);
	tll_free_and_free(dh, free);
	pkg_free(pkg);
-
	pkgdb_release_lock(db, PKGDB_LOCK_ADVISORY);
	pkgdb_close(db);

	return (rc);
modified src/create.c
@@ -57,13 +57,13 @@ void
usage_create(void)
{
	fprintf(stderr, "Usage: pkg create [-eOhnqv] [-f format] [-l level] "
-
		"[-o outdir] [-p plist] [-r rootdir] -m metadatadir\n");
+
		"[-T threads] [-o outdir] [-p plist] [-r rootdir] -m metadatadir\n");
	fprintf(stderr, "Usage: pkg create [-eOhnqv] [-f format] [-l level] "
-
		"[-o outdir] [-r rootdir] -M manifest\n");
+
		"[-T threads] [-o outdir] [-r rootdir] -M manifest\n");
	fprintf(stderr, "       pkg create [-eOhgnqvx] [-f format] [-l level] "
-
		"[-o outdir] [-r rootdir] pkg-name ...\n");
+
		"[-T threads] [-o outdir] [-r rootdir] pkg-name ...\n");
	fprintf(stderr, "       pkg create [-eOhnqv] [-f format] [-l level] "
-
		"[-o outdir] [-r rootdir] -a\n\n");
+
		"[-T threads] [-o outdir] [-r rootdir] -a\n\n");
	fprintf(stderr, "For more information see 'pkg help create'.\n");
}

@@ -172,6 +172,8 @@ exec_create(int argc, char **argv)
	int		 ch;
	int		 level;
	bool		 level_is_set = false;
+
	int		 threads;
+
	bool		 threads_is_set = false;
	int		 ret;
	bool		 hash = false;
	bool		 overwrite = true;
@@ -208,7 +210,7 @@ exec_create(int argc, char **argv)
		{ NULL,		0,			NULL,	0   },
	};

-
	while ((ch = getopt_long(argc, argv, "+aeghxf:l:r:m:M:no:p:qvt:", longopts, NULL)) != -1) {
+
	while ((ch = getopt_long(argc, argv, "+aeghxf:l:r:m:M:no:p:qvt:T:", longopts, NULL)) != -1) {
		switch (ch) {
		case 'a':
			match = MATCH_ALL;
@@ -272,6 +274,21 @@ exec_create(int argc, char **argv)
				return (EXIT_FAILURE);
			}
			break;
+
		case 'T':
+
			{
+
			const char *errstr;
+

+
			threads_is_set = true;
+
			threads = strtonum(optarg, 0, INT_MAX, &errstr);
+
			if (errstr == NULL)
+
				break;
+
			if (strcasecmp(optarg, "auto") == 0) {
+
				threads = 0;
+
				break;
+
			}
+
			warnx("Invalid compression threads %s", optarg);
+
			return (EXIT_FAILURE);
+
			}
		case 'v':
			quiet = false;
			break;
@@ -310,7 +327,9 @@ exec_create(int argc, char **argv)
			warnx("unknown format %s, using the default", format);
	}
	if (level_is_set)
-
	    pkg_create_set_compression_level(pc, level);
+
		pkg_create_set_compression_level(pc, level);
+
	if (threads_is_set)
+
		pkg_create_set_compression_threads(pc, threads);
	pkg_create_set_overwrite(pc, overwrite);
	pkg_create_set_rootdir(pc, rootdir);
	pkg_create_set_output_dir(pc, outdir);
modified tests/frontend/upgrade.sh
@@ -9,7 +9,7 @@ tests_init \
	dual_conflict \
	file_become_dir \
	dir_become_file \
-
	vital
+
	dir_is_symlink_to_a_dir

issue1881_body() {
	atf_check -s exit:0 sh ${RESOURCEDIR}/test_subr.sh new_pkg pkg1 pkg_a 1
@@ -264,43 +264,23 @@ dir_become_file_body() {
	atf_check -o ignore pkg -o REPOS_DIR="${TMPDIR}" -r ${TMPDIR}/target install -Uy ${TMPDIR}/pkg-2.pkg
}

-
vital_body() {
-
	atf_check -s exit:0 sh ${RESOURCEDIR}/test_subr.sh new_pkg "meta" "mymeta" "1"
-
	mkdir file-pkg-1
-
	cat << EOF >> meta.ucl
-
vital = true;
-
EOF
-
	echo entry > file-pkg-1/file
-
	echo "${TMPDIR}/file-pkg-1/file" > plist-1
-
	atf_check pkg create -M meta.ucl -p plist-1
+
dir_is_symlink_to_a_dir_body()
+
{
+
	atf_check -s exit:0 sh ${RESOURCEDIR}/test_subr.sh new_pkg "pkg" "pkg" "1"
+
	mkdir share lib lib/something
+
	ln -sf ../lib/something share/something
+
	echo "entry" > lib/something/file
+
	echo "${TMPDIR}/lib/something/file" > plist-1
+
	echo "${TMPDIR}/share/something" >> plist-1
+
	atf_check pkg create -M pkg.ucl -p plist-1
	mkdir target
-
	atf_check -o ignore pkg -o REPOS_DIR="${TMPDIR}" -r ${TMPDIR}/target install -Uy ${TMPDIR}/mymeta-1.pkg
-
	atf_check -s exit:0 sh ${RESOURCEDIR}/test_subr.sh new_pkg "plop" "myplop" "1"
-
	atf_check pkg create -M plop.ucl
-
	atf_check -o ignore pkg -o REPOS_DIR="${TMPDIR}" -r ${TMPDIR}/target install -Uy ${TMPDIR}/myplop-1.pkg
-
	atf_check -s exit:0 sh ${RESOURCEDIR}/test_subr.sh new_pkg "plop" "myplop" "2"
-
	echo "${TMPDIR}/file-pkg-1/file" > plist-2
-
	atf_check pkg create -M plop.ucl -p plist-2
-
	mkdir repoconf
-
	cat << EOF > repoconf/repo.conf
-
local: {
-
	url: file:///$TMPDIR,
-
	enabled: true
-
}
-
EOF
-

-
	atf_check -o ignore pkg repo .
-
	atf_check -o ignore pkg -o REPOS_DIR="$TMPDIR/repoconf" -r ${TMPDIR}/target -o PKG_CACHEDIR="$TMPDIR" update
-
	OUTPUT="Updating local repository catalogue...
-
local repository is up to date.
-
All repositories are up to date.
-
Checking for upgrades (2 candidates):  done
-
Processing candidates (2 candidates):  done
-
Checking integrity... done (1 conflicting)
-
  - myplop-2 conflicts with mymeta-1 on ${TMPDIR}/file-pkg-1/file
-
Cannot solve problem using SAT solver, trying another plan
-
Checking integrity... done (0 conflicting)
-
Your packages are up to date.
-
"
-
	atf_check -o inline:"${OUTPUT}" pkg -o REPOS_DIR="$TMPDIR/repoconf" -r ${TMPDIR}/target -o PKG_CACHEDIR="$TMPDIR" upgrade -y
+
	atf_check -o ignore pkg -o REPOS_DIR="${TMPDIR}" -r ${TMPDIR}/target install -Uy ${TMPDIR}/pkg-1.pkg
+
	atf_check -s exit:0 sh ${RESOURCEDIR}/test_subr.sh new_pkg "pkg" "pkg" "2"
+
	rm share/something
+
	mkdir share/something
+
	echo "entry" > share/something/file
+
	echo "${TMPDIR}/lib/something/file" > plist-2
+
	echo "${TMPDIR}/share/something/file" >> plist-2
+
	atf_check pkg create -M pkg.ucl -p plist-2
+
	atf_check -o ignore pkg -o REPOS_DIR="${TMPDIR}" -r ${TMPDIR}/target install -Uy ${TMPDIR}/pkg-2.pkg
}
modified tests/frontend/vital.sh
@@ -40,8 +40,8 @@ EOF

	atf_check \
		-o empty \
-
		-e empty  \
-
		-s exit:1 \
+
		-e inline:"${PROGNAME}: Cannot delete vital package: test!\n${PROGNAME}: If you are sure you want to remove test, \n${PROGNAME}: unset the 'vital' flag with: pkg set -v 0 test\n" \
+
		-s exit:3 \
		pkg -r ${TMPDIR}/target delete -qy test
	atf_check \
		-o empty \
modified tests/lib/packing.c
@@ -74,33 +74,33 @@ ATF_TC_BODY(packing_set_format, tc)
	ATF_CHECK(a != NULL);

#if defined(HAVE_ARCHIVE_WRITE_ADD_FILTER_ZSTD) && __FreeBSD_version >= 1300000
-
	ATF_REQUIRE_STREQ(packing_set_format(a, TZS, -1), "tzst");
+
	ATF_REQUIRE_STREQ(packing_set_format(a, TZS, -1, -1), "tzst");
#endif
-
	ATF_REQUIRE_STREQ(packing_set_format(a, TXZ, -1), "txz");
-
	ATF_REQUIRE_STREQ(packing_set_format(a, TBZ, -1), "tbz");
-
	ATF_REQUIRE_STREQ(packing_set_format(a, TGZ, -1), "tgz");
-
	ATF_REQUIRE_STREQ(packing_set_format(a, TAR, -1), "tar");
-
	ATF_REQUIRE_EQ(packing_set_format(a, 28, -1), NULL);
+
	ATF_REQUIRE_STREQ(packing_set_format(a, TXZ, -1, -1), "txz");
+
	ATF_REQUIRE_STREQ(packing_set_format(a, TBZ, -1, -1), "tbz");
+
	ATF_REQUIRE_STREQ(packing_set_format(a, TGZ, -1, -1), "tgz");
+
	ATF_REQUIRE_STREQ(packing_set_format(a, TAR, -1, -1), "tar");
+
	ATF_REQUIRE_EQ(packing_set_format(a, 28, -1, -1), NULL);

	/* compression min */
#if defined(HAVE_ARCHIVE_WRITE_ADD_FILTER_ZSTD) && __FreeBSD_version >= 1300000
-
	ATF_REQUIRE_STREQ(packing_set_format(a, TZS, INT_MIN), "tzst");
+
	ATF_REQUIRE_STREQ(packing_set_format(a, TZS, INT_MIN, -1), "tzst");
#endif
-
	ATF_REQUIRE_STREQ(packing_set_format(a, TXZ, INT_MIN), "txz");
-
	ATF_REQUIRE_STREQ(packing_set_format(a, TBZ, INT_MIN), "tbz");
-
	ATF_REQUIRE_STREQ(packing_set_format(a, TGZ, INT_MIN), "tgz");
-
	ATF_REQUIRE_STREQ(packing_set_format(a, TAR, INT_MIN), "tar");
-
	ATF_REQUIRE_EQ(packing_set_format(a, 28, INT_MIN), NULL);
+
	ATF_REQUIRE_STREQ(packing_set_format(a, TXZ, INT_MIN, -1), "txz");
+
	ATF_REQUIRE_STREQ(packing_set_format(a, TBZ, INT_MIN, -1), "tbz");
+
	ATF_REQUIRE_STREQ(packing_set_format(a, TGZ, INT_MIN, -1), "tgz");
+
	ATF_REQUIRE_STREQ(packing_set_format(a, TAR, INT_MIN, -1), "tar");
+
	ATF_REQUIRE_EQ(packing_set_format(a, 28, INT_MIN, -1), NULL);

	/* compression max */
#if defined(HAVE_ARCHIVE_WRITE_ADD_FILTER_ZSTD) && __FreeBSD_version >= 1300000
-
	ATF_REQUIRE_STREQ(packing_set_format(a, TZS, INT_MAX), "tzst");
+
	ATF_REQUIRE_STREQ(packing_set_format(a, TZS, INT_MAX, -1), "tzst");
#endif
-
	ATF_REQUIRE_STREQ(packing_set_format(a, TXZ, INT_MAX), "txz");
-
	ATF_REQUIRE_STREQ(packing_set_format(a, TBZ, INT_MAX), "tbz");
-
	ATF_REQUIRE_STREQ(packing_set_format(a, TGZ, INT_MAX), "tgz");
-
	ATF_REQUIRE_STREQ(packing_set_format(a, TAR, INT_MAX), "tar");
-
	ATF_REQUIRE_EQ(packing_set_format(a, 28, INT_MAX), NULL);
+
	ATF_REQUIRE_STREQ(packing_set_format(a, TXZ, INT_MAX, -1), "txz");
+
	ATF_REQUIRE_STREQ(packing_set_format(a, TBZ, INT_MAX, -1), "tbz");
+
	ATF_REQUIRE_STREQ(packing_set_format(a, TGZ, INT_MAX, -1), "tgz");
+
	ATF_REQUIRE_STREQ(packing_set_format(a, TAR, INT_MAX, -1), "tar");
+
	ATF_REQUIRE_EQ(packing_set_format(a, 28, INT_MAX, -1), NULL);
}

ATF_TP_ADD_TCS(tp)
modified tests/lib/utils.c
@@ -75,10 +75,10 @@ ATF_TC_BODY(open_tempdir, tc) {
	struct tempdir *t;
	int rootfd = open(getenv("TMPDIR"), O_DIRECTORY);
	ATF_REQUIRE_MSG(rootfd  != -1, "impossible to open TMPDIR");
-
	t = open_tempdir(rootfd, "/plop");
+
	t = open_tempdir(rootfd, "/plop", NULL);
	ATF_REQUIRE(t == NULL);
	mkdirat(rootfd, "usr", 0755);
-
	t = open_tempdir(rootfd, "/usr/local/directory");
+
	t = open_tempdir(rootfd, "/usr/local/directory", NULL);
	ATF_REQUIRE(t != NULL);
	ATF_REQUIRE_STREQ(t->name, "/usr/local");
	ATF_REQUIRE_EQ(t->len, strlen("/usr/local"));
@@ -86,7 +86,7 @@ ATF_TC_BODY(open_tempdir, tc) {
	ATF_REQUIRE(t->fd != -1);
	close(t->fd);
	free(t);
-
	t = open_tempdir(rootfd, "/nousr/local/directory");
+
	t = open_tempdir(rootfd, "/nousr/local/directory", NULL);
	ATF_REQUIRE(t != NULL);
	ATF_REQUIRE_STREQ(t->name, "/nousr");
	ATF_REQUIRE_EQ(t->len, strlen("/nousr"));
@@ -97,7 +97,7 @@ ATF_TC_BODY(open_tempdir, tc) {
	mkdirat(rootfd, "dir", 0755);
	/* a file in the path */
	close(openat(rootfd, "dir/file1", O_CREAT|O_WRONLY, 0644));
-
	t = open_tempdir(rootfd, "/dir/file1/test");
+
	t = open_tempdir(rootfd, "/dir/file1/test", NULL);
	ATF_REQUIRE(t != NULL);
	ATF_REQUIRE_STREQ(t->name, "/dir/file1");
	ATF_REQUIRE_EQ(t->len, strlen("/dir/file1"));