Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Merge remote-tracking branch 'upstream/master'
Shawn Webb committed 2 years ago
commit 609fca8f90b51cea5d7abd2c149f472c3277a268
parent 7649071
11 files changed +364 -216
modified NEWS
@@ -1,3 +1,17 @@
+
Chanegs from 1.20.99.8 to 1.20.99.9
+
- pkgbase: .snap now comes after .alpha in versionning
+
- update: lock pkg update to avoid concurrent instance of pkg update to compete
+
- bundled sqlite: update to 3.45.0
+
- bootstrap now accepts -y
+
- update bundled curl to 8.5.0
+
- New PKG_ISCHROOTED env var for scripts so they can grow the knowledge they
+
  are being run in a pkg -c chroot environement
+
- update autosetup to 7.1
+
- lots of small code optimizations
+
- remove now unsupported arm architectures
+
- refactor pkg_repo_create API to make it more flexible, while here document it
+
- repo: to not generate anymore the meta.{pkg,txz} which is unused since pkg 1.13
+

Changes from 1.20.99.7 to 1.20.99.8
- fix a race in vulnxml fetch trigger
- add a new data.pkg which contains a fully valid json and aim at replacing
modified auto.def
@@ -6,7 +6,7 @@ use cc cc-lib cc-shared pkg-config
set maj_ver 1
set med_ver 20
set min_ver 99
-
set dev_ver 8
+
set dev_ver 9
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/Makefile.autosetup
@@ -2,6 +2,7 @@ include @builddir@/mk/defs.mk

MAN3=	pkg_printf.3 \
	pkg_create.3 \
+
	pkg_repo_create.3 \
	pkg_repos.3
MAN5=	pkg-repository.5 \
	pkg-keywords.5 \
modified docs/pkg_create.3
@@ -1,12 +1,12 @@
-
.Dd April 24, 2020
+
.Dd January 23, 2024
.Dt PKG_CREATE 3
.Os
.Sh NAME
.Nm pkg_create , pkg_create_i ,
.Nm pkg_create_new , pkg_create_free ,
.Nm pkg_create_set_format , pkg_create_set_overwrite ,
-
.Nm pkg_create_set_compression_level , pkg_set_rootdir , pkg_set_output_dir ,
-
.Nm pkg_create_set_timestamp
+
.Nm pkg_create_set_compression_level , pkg_create_set_rootdir ,
+
.Nm pkg_create_set_output_dir , pkg_create_set_timestamp
.Nd create packages
.Sh LIBRARY
.Lb libpkg
@@ -64,7 +64,7 @@ Set the best compression ratio
.El
.Pp
.Fn pkg_create_set_overwrite
-
Accept Va a boolean to define the default behaviour when creating a package and
+
Accept a boolean to define the default behaviour when creating a package and
a local file already exists.
The default behaviour is to overwrite.
.Pp
added docs/pkg_repo_create.3
@@ -0,0 +1,86 @@
+
.Dd January 23, 2024
+
.Dt PKG_REPO_CREATE 3
+
.Os
+
.Sh NAME
+
.Nm pkg_repo_create ,
+
.Nm pkg_repo_create_new , pkg_repo_create_free ,
+
.Nm pkg_repo_create_set_output_dir , pkg_repo_create_set_create_filelist ,
+
.Nm pkg_repo_create_set_hash , pkg_repo_create_set_hash_symlink ,
+
.Nm pkg_repo_create_set_metafile , pkg_repo_create_set_sign
+
.Nd create repository of packages
+
.Sh LIBRARY
+
.Lb libpkg
+
.Sh SYNOPSIS
+
.In pkg.h
+
.Ft struct pkg_repo_create *
+
.Fn pkg_repo_create_new
+
.Ft void
+
.Fn pkg_repo_create_free "struct pkg_repo_create *"
+
.Ft bool
+
.Fn pkg_repo_create_set_output_dir "struct pkg_repo_create *" "const char *"
+
.Ft void
+
.Fn pkg_repo_create_set_create_filelist "struct pkg_repo_create *" "bool"
+
.Ft void
+
.Fn pkg_repo_create_set_hash "struct pkg_repo_create *" "bool"
+
.Ft void
+
.Fn pkg_repo_create_set_hash_symlink "struct pkg_repo_create *" "bool"
+
.Ft void
+
.Fn pkg_repo_create_set_metafile "struct pkg_repo_create *" "const char *"
+
.Ft void
+
.Fn pkg_repo_create_set_sign "struct pkg_repo_create *" "char **" "int" "pkg_password *"
+
.Ft int
+
.Fn pkg_repo_create "struct pkg_repo_create *" "char *"
+
.Sh DESCRIPTION
+
.Fn pkg_repo_create_new
+
Allocates a new
+
.Ft struct pkg_repo_create *
+
which should be freed by the caller using
+
.Fn pkg_repo_create_free .
+
.Pp
+
.Fn pkg_repo_create_set_output_dir
+
defined the output directory where to generate the data.
+
By default it will be the
+
.Va path
+
provided to the
+
.Fn pkg_repo_create
+
function.
+
.Pp
+
.Fn pkg_repo_create_set_create_filelist
+
Accept a boolean to define if a the file database should be created
+
along with the metadata database
+
.Pq deprecated .
+
Defaults to
+
.Va false .
+
.Pp
+
.Fn pkg_repo_create_set_hash
+
When creating the repository, move all the packages found into a
+
.Qq Hashed
+
subdirectory with the
+
.Qq hash
+
of the package appended to the name of the package.
+
Defaults to
+
.Va false .
+
.Pp
+
.Fn pkg_repo_create_set_hash_symlink
+
If the
+
.Va hash
+
functionnality has been activated, then there will be a symlink for each
+
packages in the
+
.Qq Hashed
+
directory will be created in the root of the repository.
+
Defaults to
+
.Va false .
+
.Pp
+
.Fn pkg_repo_create_set_metafile
+
Define the
+
.Va path
+
to the metafile that will be used when creating the repository. If none is
+
specified that it will fallback on the internal default.
+
.Pp
+
.Fn pkg_repo_create_set_sign
+
Define the signing mecanism, which will be used to sign the metadata of the
+
repository. Defaults to none.
+
.Pp
+
.Fn pkg_repo_create
+
Create a repository out of the packages found in the provided
+
.Va path
modified libpkg/libpkg.ver
@@ -45,7 +45,7 @@ global:
	pkg_deps;
	pkg_dirs;
	pkg_dprintf;
-
	pkg_emit_manifest;
+
	pkg_drop_privileges;
	pkg_emit_manifest_file;
	pkg_event_register;
	pkg_execute_deferred_triggers;
@@ -55,12 +55,18 @@ global:
	pkg_finish_repo;
	pkg_fprintf;
	pkg_free;
+
	pkg_get_b;
	pkg_get_cachedir;
	pkg_get_cachedirfd;
	pkg_get_dbdirfd;
	pkg_get_dir;
	pkg_get_element;
	pkg_get_file;
+
	pkg_get_i;
+
	pkg_get_invalid;
+
	pkg_get_kv;
+
	pkg_get_s;
+
	pkg_get_sl;
	pkg_handle_sandboxed_call;
	pkg_handle_sandboxed_get_string;
	pkg_has_dir;
@@ -91,6 +97,8 @@ global:
	pkg_jobs_type;
	pkg_kvlist_iterator;
	pkg_kvlist_next;
+
	pkg_license_name;
+
	pkg_licenses;
	pkg_list_count;
	pkg_load_metadata;
	pkg_mkdirs;
@@ -129,6 +137,15 @@ global:
	pkg_rdeps;
	pkg_recompute;
	pkg_repo_cached_name;
+
	pkg_repo_create;
+
	pkg_repo_create_free;
+
	pkg_repo_create_new;
+
	pkg_repo_create_set_create_filelist;
+
	pkg_repo_create_set_hash;
+
	pkg_repo_create_set_hash_symlink;
+
	pkg_repo_create_set_metafile;
+
	pkg_repo_create_set_output_dir;
+
	pkg_repo_create_set_sign;
	pkg_repo_enabled;
	pkg_repo_fetch_remote_tmp;
	pkg_repo_find;
@@ -147,6 +164,8 @@ global:
	pkg_set_b;
	pkg_set_debug_level;
	pkg_set_i;
+
	pkg_set_invalid;
+
	pkg_set_ischrooted;
	pkg_set_rootdir;
	pkg_set_s;
	pkg_shutdown;
modified libpkg/pkg.h.in
@@ -1,5 +1,5 @@
/*-
-
 * 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) 2011 Will Andrews <will@FreeBSD.org>
 * Copyright (c) 2011 Philippe Pepiot <phil@philpep.org>
@@ -101,6 +101,7 @@ struct pkg_option;
struct pkg_license;
struct pkg_config_file;
struct pkg_create;
+
struct pkg_repo_create;

struct pkgdb;
struct pkgdb_it;
@@ -808,6 +809,15 @@ int pkg_create_repo(char *path, const char *output_dir, bool filelist,
int pkg_finish_repo(const char *output_dir, pkg_password_cb *cb, char **argv,
    int argc, bool filelist);

+
struct pkg_repo_create *pkg_repo_create_new(void);
+
void pkg_repo_create_free(struct pkg_repo_create *);
+
void pkg_repo_create_set_create_filelist(struct pkg_repo_create *prc, bool);
+
void pkg_repo_create_set_hash(struct pkg_repo_create *prc, bool);
+
void pkg_repo_create_set_hash_symlink(struct pkg_repo_create *prc, bool);
+
void pkg_repo_create_set_output_dir(struct pkg_repo_create *prc, const char *);
+
void pkg_repo_create_set_metafile(struct pkg_repo_create *prc, const char *);
+
void pkg_repo_create_set_sign(struct pkg_repo_create *prc, char **argv, int argc, pkg_password_cb *cb);
+
int pkg_repo_create(struct pkg_repo_create *, char *path);

/**
 * Test if the EUID has sufficient privilege to carry out some
modified libpkg/pkg_repo_create.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-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
 * Copyright (c) 2012-2013 Matthew Seaman <matthew@FreeBSD.org>
@@ -61,6 +61,9 @@ enum {
	MSG_PKG_READY,
};

+
static int pkg_repo_pack_db(const char *name, const char *archive, char *path,
+
    struct pkg_key *keyinfo, struct pkg_repo_create *prc);
+

static int
hash_file(struct pkg_repo_meta *meta, struct pkg *pkg, char *path)
{
@@ -393,21 +396,183 @@ fts_compare(FTSENTP *a, FTSENTP *b)
	return (strcmp((*a)->fts_name, (*b)->fts_name));
}

+
struct pkg_repo_create *
+
pkg_repo_create_new(void)
+
{
+
	struct pkg_repo_create *prc;
+

+
	prc = xcalloc(1, sizeof(*prc));
+
	prc->ofd = -1;
+

+
	return (prc);
+
}
+

+
void
+
pkg_repo_create_free(struct pkg_repo_create *prc)
+
{
+
	if (prc == NULL)
+
		return;
+
	pkg_repo_meta_free(prc->meta);
+
	if (prc->ofd != -1)
+
		close(prc->ofd);
+
	free(prc);
+
}
+

+
void
+
pkg_repo_create_set_create_filelist(struct pkg_repo_create *prc, bool val)
+
{
+
	prc->filelist = val;
+
}
+

+
void
+
pkg_repo_create_set_hash(struct pkg_repo_create *prc, bool val)
+
{
+
	prc->hash = val;
+
}
+

+
void
+
pkg_repo_create_set_hash_symlink(struct pkg_repo_create *prc, bool val)
+
{
+
	prc->hash_symlink = val;
+
}
+

+
void
+
pkg_repo_create_set_output_dir(struct pkg_repo_create *prc, const char *out)
+
{
+
	prc->outdir = out;
+
}
+

+
void
+
pkg_repo_create_set_metafile(struct pkg_repo_create *prc, const char *metafile)
+
{
+
	prc->metafile = metafile;
+
}
+

+
void
+
pkg_repo_create_set_sign(struct pkg_repo_create *prc, char **argv, int argc, pkg_password_cb *cb)
+
{
+
	prc->sign.argc = argc;
+
	prc->sign.argv = argv;
+
	prc->sign.cb = cb;
+
}
+

+
static int
+
pkg_repo_create_pack_and_sign(struct pkg_repo_create *prc)
+
{
+
	char repo_path[MAXPATHLEN];
+
	char repo_archive[MAXPATHLEN];
+
	char *key_file;
+
	const char *key_type;
+
	struct pkg_key *keyinfo = NULL;
+
	struct stat st;
+
	int ret = EPKG_OK, nfile = 0;
+
	const int files_to_pack = 4;
+

+
	if (prc->sign.argc == 1) {
+
		key_type = key_file = prc->sign.argv[0];
+
		if (strncmp(key_file, "rsa:", 4) == 0) {
+
			key_file += 4;
+
			*(key_file - 1) = '\0';
+
		} else {
+
			key_type = "rsa";
+
		}
+

+
		pkg_debug(1, "Loading %s key from '%s' for signing", key_type, key_file);
+
		rsa_new(&keyinfo, prc->sign.cb, key_file);
+
	}
+

+
	if (prc->sign.argc > 1 && strcmp(prc->sign.argv[0], "signing_command:") != 0)
+
		return (EPKG_FATAL);
+

+
	if (prc->sign.argc > 1) {
+
		prc->sign.argc--;
+
		prc->sign.argv++;
+
	}
+

+
	pkg_emit_progress_start("Packing files for repository");
+
	pkg_emit_progress_tick(nfile++, files_to_pack);
+

+
	snprintf(repo_path, sizeof(repo_path), "%s/%s", prc->outdir,
+
	    prc->meta->manifests);
+
	snprintf(repo_archive, sizeof(repo_archive), "%s/%s", prc->outdir,
+
		prc->meta->manifests_archive);
+
	if (pkg_repo_pack_db(prc->meta->manifests, repo_archive, repo_path, keyinfo, prc) != EPKG_OK) {
+
		ret = EPKG_FATAL;
+
		goto cleanup;
+
	}
+

+
	pkg_emit_progress_tick(nfile++, files_to_pack);
+

+
	if (prc->filelist) {
+
		snprintf(repo_path, sizeof(repo_path), "%s/%s", prc->outdir,
+
		    prc->meta->filesite);
+
		snprintf(repo_archive, sizeof(repo_archive), "%s/%s",
+
		    prc->outdir, prc->meta->filesite_archive);
+
		if (pkg_repo_pack_db(prc->meta->filesite, repo_archive, repo_path, keyinfo, prc) != EPKG_OK) {
+
			ret = EPKG_FATAL;
+
			goto cleanup;
+
		}
+
	}
+

+
	pkg_emit_progress_tick(nfile++, files_to_pack);
+
	snprintf(repo_path, sizeof(repo_path), "%s/%s", prc->outdir, prc->meta->data);
+
	snprintf(repo_archive, sizeof(repo_archive), "%s/%s", prc->outdir,
+
	    prc->meta->data_archive);
+
	if (pkg_repo_pack_db(prc->meta->data, repo_archive, repo_path, keyinfo, prc) != EPKG_OK) {
+
		ret = EPKG_FATAL;
+
		goto cleanup;
+
	}
+

+
	pkg_emit_progress_tick(nfile++, files_to_pack);
+

+
	if (fstatat(prc->ofd, "meta.conf", &st, 0) == 0) {
+
		struct timeval ftimes[2] = {
+
			{
+
			.tv_sec = st.st_mtime,
+
			.tv_usec = 0
+
			},
+
			{
+
			.tv_sec = st.st_mtime,
+
			.tv_usec = 0
+
			}
+
		};
+
		snprintf(repo_archive, sizeof(repo_archive), "%s.pkg",
+
		    prc->meta->manifests_archive);
+
		futimesat(prc->ofd, repo_archive, ftimes);
+
		if (prc->filelist) {
+
			snprintf(repo_archive, sizeof(repo_archive),
+
			    "%s.pkg", prc->meta->filesite_archive);
+
			futimesat(prc->ofd, repo_archive, ftimes);
+
		}
+
		snprintf(repo_archive, sizeof(repo_archive), "%s.pkg",
+
		    prc->meta->data_archive);
+
		futimesat(prc->ofd, repo_archive, ftimes);
+
	}
+

+
cleanup:
+
	pkg_emit_progress_tick(files_to_pack, files_to_pack);
+

+
	rsa_free(keyinfo);
+

+
	return (ret);
+
}
+

int
-
pkg_create_repo(char *path, const char *output_dir, bool filelist,
-
	const char *metafile, bool hash, bool hash_symlink)
+
pkg_repo_create(struct pkg_repo_create *prc, char *path)
{
	FTS *fts = NULL;
	int num_workers;
	pthread_t *threads;
	struct thr_env te = { 0 };
	size_t len;
-
	int fd, outputdir_fd;
-
	struct pkg_repo_meta *meta = NULL;
+
	int fd;
	int retcode = EPKG_FATAL;
	ucl_object_t *meta_dump;
	char *repopath[2];

+
	if (prc->outdir == NULL)
+
		prc->outdir = path;
+

	te.mfd = te.ffd = te.dfd = -1;

	if (!is_dir(path)) {
@@ -416,44 +581,44 @@ pkg_create_repo(char *path, const char *output_dir, bool filelist,
	}

	errno = 0;
-
	if (!is_dir(output_dir)) {
+
	if (!is_dir(prc->outdir)) {
		/* Try to create dir */
		if (errno == ENOENT) {
-
			if (mkdir(output_dir, 00755) == -1) {
+
			if (mkdir(prc->outdir, 00755) == -1) {
				pkg_fatal_errno("cannot create output directory %s",
-
					output_dir);
+
					prc->outdir);
			}
		}
		else {
-
			pkg_emit_error("%s is not a directory", output_dir);
+
			pkg_emit_error("%s is not a directory", prc->outdir);
			return (EPKG_FATAL);
		}
	}
-
	if ((outputdir_fd = open(output_dir, O_DIRECTORY)) == -1) {
-
		pkg_emit_error("Cannot open %s", output_dir);
+
	if ((prc->ofd = open(prc->outdir, O_DIRECTORY)) == -1) {
+
		pkg_emit_error("Cannot open %s", prc->outdir);
		return (EPKG_FATAL);
	}

-
	if (metafile != NULL) {
-
		fd = open(metafile, O_RDONLY);
+
	if (prc->metafile != NULL) {
+
		fd = open(prc->metafile, O_RDONLY);
		if (fd == -1) {
-
			pkg_emit_error("meta loading error while trying %s", metafile);
+
			pkg_emit_error("meta loading error while trying %s", prc->metafile);
			return (EPKG_FATAL);
		}
-
		if (pkg_repo_meta_load(fd, &meta) != EPKG_OK) {
-
			pkg_emit_error("meta loading error while trying %s", metafile);
+
		if (pkg_repo_meta_load(fd, &prc->meta) != EPKG_OK) {
+
			pkg_emit_error("meta loading error while trying %s", prc->metafile);
			close(fd);
			return (EPKG_FATAL);
		}
		close(fd);
	} else {
-
		meta = pkg_repo_meta_default();
+
		prc->meta = pkg_repo_meta_default();
	}
-
	meta->repopath = path;
-
	meta->hash = hash;
-
	meta->hash_symlink = hash_symlink;
+
	prc->meta->repopath = path;
+
	prc->meta->hash = prc->hash;
+
	prc->meta->hash_symlink = prc->hash_symlink;

-
	te.meta = meta;
+
	te.meta = prc->meta;

	repopath[0] = path;
	repopath[1] = NULL;
@@ -470,16 +635,16 @@ pkg_create_repo(char *path, const char *output_dir, bool filelist,
		goto cleanup;
	}

-
	if ((te.mfd = openat(outputdir_fd, meta->manifests,
+
	if ((te.mfd = openat(prc->ofd, prc->meta->manifests,
	     O_CREAT|O_TRUNC|O_WRONLY, 00644)) == -1) {
		goto cleanup;
	}
-
	if ((te.dfd = openat(outputdir_fd, meta->data,
+
	if ((te.dfd = openat(prc->ofd, prc->meta->data,
	    O_CREAT|O_TRUNC|O_WRONLY, 00644)) == -1) {
		goto cleanup;
	}
-
	if (filelist) {
-
		if ((te.ffd = openat(outputdir_fd, meta->filesite,
+
	if (prc->filelist) {
+
		if ((te.ffd = openat(prc->ofd, prc->meta->filesite,
		        O_CREAT|O_TRUNC|O_WRONLY, 00644)) == -1) {
			goto cleanup;
		}
@@ -487,7 +652,7 @@ pkg_create_repo(char *path, const char *output_dir, bool filelist,

	len = 0;

-
	pkg_create_repo_read_fts(&te.fts_items, fts, path, &len, meta);
+
	pkg_create_repo_read_fts(&te.fts_items, fts, path, &len, prc->meta);

	if (len == 0) {
		/* Nothing to do */
@@ -499,7 +664,7 @@ pkg_create_repo(char *path, const char *output_dir, bool filelist,
	num_workers = MIN(num_workers, len);

	/* Launch workers */
-
	pkg_emit_progress_start("Creating repository in %s", output_dir);
+
	pkg_emit_progress_start("Creating repository in %s", prc->outdir);

	threads = xcalloc(num_workers, sizeof(pthread_t));

@@ -535,13 +700,13 @@ pkg_create_repo(char *path, const char *output_dir, bool filelist,

	/* Write metafile */

-
	fd = openat(outputdir_fd, "meta", O_CREAT|O_TRUNC|O_CLOEXEC|O_WRONLY,
+
	fd = openat(prc->ofd, "meta", O_CREAT|O_TRUNC|O_CLOEXEC|O_WRONLY,
	    0644);
	if (fd != -1) {
-
		meta_dump = pkg_repo_meta_to_ucl(meta);
+
		meta_dump = pkg_repo_meta_to_ucl(prc->meta);
		ucl_object_emit_fd(meta_dump, UCL_EMIT_CONFIG, fd);
		close(fd);
-
		fd = openat(outputdir_fd, "meta.conf",
+
		fd = openat(prc->ofd, "meta.conf",
		    O_CREAT|O_TRUNC|O_CLOEXEC|O_WRONLY, 0644);
		if (fd != -1) {
			ucl_object_emit_fd(meta_dump, UCL_EMIT_CONFIG, fd);
@@ -556,8 +721,6 @@ pkg_create_repo(char *path, const char *output_dir, bool filelist,
	}
	retcode = EPKG_OK;
cleanup:
-
	if (outputdir_fd != -1)
-
		close(outputdir_fd);
	if (te.mfd != -1)
		close(te.mfd);
	if (te.ffd != -1)
@@ -569,9 +732,10 @@ cleanup:

	tll_free_and_free(te.fts_items, pkg_create_repo_fts_free);

-
	pkg_repo_meta_free(meta);
+
	if (retcode != EPKG_OK)
+
		return (retcode);

-
	return (retcode);
+
	return (pkg_repo_create_pack_and_sign(prc));
}

static int
@@ -707,19 +871,18 @@ pack_command_sign(struct packing *pack, const char *path, char **argv, int argc,

static int
pkg_repo_pack_db(const char *name, const char *archive, char *path,
-
		struct pkg_key *keyinfo, struct pkg_repo_meta *meta,
-
		char **argv, int argc)
+
    struct pkg_key *keyinfo, struct pkg_repo_create *prc)
{
	struct packing *pack;
	int ret = EPKG_OK;

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

	if (keyinfo != NULL) {
		ret = pack_rsa_sign(pack, keyinfo, path, "signature");
-
	} else if (argc >= 1) {
-
		ret = pack_command_sign(pack, path, argv, argc, name);
+
	} else if (prc->sign.argc >= 1) {
+
		ret = pack_command_sign(pack, path, prc->sign.argv, prc->sign.argc, name);
	}
	packing_append_file_attr(pack, path, name, "root", "wheel", 0644, 0);

@@ -728,152 +891,3 @@ pkg_repo_pack_db(const char *name, const char *archive, char *path,

	return (ret);
}
-

-
int
-
pkg_finish_repo(const char *output_dir, pkg_password_cb *password_cb,
-
    char **argv, int argc, bool filelist)
-
{
-
	char repo_path[MAXPATHLEN];
-
	char repo_archive[MAXPATHLEN];
-
	char *key_file;
-
	const char *key_type;
-
	struct pkg_key *keyinfo = NULL;
-
	struct pkg_repo_meta *meta;
-
	struct stat st;
-
	int ret = EPKG_OK, nfile = 0, fd;
-
	const int files_to_pack = 4;
-

-
	if (!is_dir(output_dir)) {
-
		pkg_emit_error("%s is not a directory", output_dir);
-
		return (EPKG_FATAL);
-
	}
-

-
	if (argc == 1) {
-
		key_type = key_file = argv[0];
-
		if (strncmp(key_file, "rsa:", 4) == 0) {
-
			key_file += 4;
-
			*(key_file - 1) = '\0';
-
		} else {
-
			key_type = "rsa";
-
		}
-

-
		pkg_debug(1, "Loading %s key from '%s' for signing", key_type, key_file);
-
		rsa_new(&keyinfo, password_cb, key_file);
-
	}
-

-
	if (argc > 1 && strcmp(argv[0], "signing_command:") != 0)
-
		return (EPKG_FATAL);
-

-
	if (argc > 1) {
-
		argc--;
-
		argv++;
-
	}
-

-
	pkg_emit_progress_start("Packing files for repository");
-
	pkg_emit_progress_tick(nfile++, files_to_pack);
-

-
	snprintf(repo_path, sizeof(repo_path), "%s/%s", output_dir,
-
		repo_meta_file);
-
	if ((fd = open(repo_path, O_RDONLY)) != -1) {
-
		if (pkg_repo_meta_load(fd, &meta) != EPKG_OK) {
-
			pkg_emit_error("meta loading error while trying %s", repo_path);
-
			rsa_free(keyinfo);
-
			close(fd);
-
			return (EPKG_FATAL);
-
		}
-
		if (pkg_repo_pack_db(repo_meta_file, repo_path, repo_path, keyinfo,
-
		    meta, argv, argc) != EPKG_OK) {
-
			ret = EPKG_FATAL;
-
			goto cleanup;
-
		}
-
	}
-
	else {
-
		meta = pkg_repo_meta_default();
-
	}
-

-
	snprintf(repo_path, sizeof(repo_path), "%s/%s", output_dir,
-
	    meta->manifests);
-
	snprintf(repo_archive, sizeof(repo_archive), "%s/%s", output_dir,
-
		meta->manifests_archive);
-
	if (pkg_repo_pack_db(meta->manifests, repo_archive, repo_path, keyinfo,
-
	    meta, argv, argc) != EPKG_OK) {
-
		ret = EPKG_FATAL;
-
		goto cleanup;
-
	}
-

-
	pkg_emit_progress_tick(nfile++, files_to_pack);
-

-
	if (filelist) {
-
		snprintf(repo_path, sizeof(repo_path), "%s/%s", output_dir,
-
		    meta->filesite);
-
		snprintf(repo_archive, sizeof(repo_archive), "%s/%s",
-
		    output_dir, meta->filesite_archive);
-
		if (pkg_repo_pack_db(meta->filesite, repo_archive, repo_path, keyinfo,
-
		    meta, argv, argc) != EPKG_OK) {
-
			ret = EPKG_FATAL;
-
			goto cleanup;
-
		}
-
	}
-

-
	pkg_emit_progress_tick(nfile++, files_to_pack);
-
	snprintf(repo_path, sizeof(repo_path), "%s/%s", output_dir, meta->data);
-
	snprintf(repo_archive, sizeof(repo_archive), "%s/%s", output_dir,
-
	    meta->data_archive);
-
	if (pkg_repo_pack_db(meta->data, repo_archive, repo_path, keyinfo,
-
	    meta, argv, argc) != EPKG_OK) {
-
		ret = EPKG_FATAL;
-
		goto cleanup;
-
	}
-

-
	pkg_emit_progress_tick(nfile++, files_to_pack);
-

-
#if 0
-
	snprintf(repo_path, sizeof(repo_path), "%s/%s", output_dir,
-
		meta->conflicts);
-
	snprintf(repo_archive, sizeof(repo_archive), "%s/%s", output_dir,
-
		meta->conflicts_archive);
-
	if (pkg_repo_pack_db(meta->conflicts, repo_archive, repo_path, keyinfo,
-
	    meta, argv, argc) != EPKG_OK) {
-
		ret = EPKG_FATAL;
-
		goto cleanup;
-
	}
-
#endif
-

-
	/* Now we need to set the equal mtime for all archives in the repo */
-
	snprintf(repo_archive, sizeof(repo_archive), "%s/%s.pkg",
-
	    output_dir, repo_meta_file);
-
	if (stat(repo_archive, &st) == 0) {
-
		struct timeval ftimes[2] = {
-
			{
-
			.tv_sec = st.st_mtime,
-
			.tv_usec = 0
-
			},
-
			{
-
			.tv_sec = st.st_mtime,
-
			.tv_usec = 0
-
			}
-
		};
-
		snprintf(repo_archive, sizeof(repo_archive), "%s/%s.pkg",
-
		    output_dir, meta->manifests_archive);
-
		utimes(repo_archive, ftimes);
-
		if (filelist) {
-
			snprintf(repo_archive, sizeof(repo_archive),
-
			    "%s/%s.pkg", output_dir, meta->filesite_archive);
-
			utimes(repo_archive, ftimes);
-
		}
-
		snprintf(repo_archive, sizeof(repo_archive),
-
			"%s/%s.pkg", output_dir, meta->data_archive);
-
		utimes(repo_archive, ftimes);
-
		snprintf(repo_archive, sizeof(repo_archive),
-
			"%s/%s.pkg", output_dir, repo_meta_file);
-
		utimes(repo_archive, ftimes);
-
	}
-

-
cleanup:
-
	pkg_emit_progress_tick(files_to_pack, files_to_pack);
-
	pkg_repo_meta_free(meta);
-

-
	rsa_free(keyinfo);
-

-
	return (ret);
-
}
modified libpkg/private/pkg.h
@@ -300,6 +300,21 @@ struct pkg_create {
	const char *outdir;
};

+
struct pkg_repo_create {
+
	bool filelist;
+
	bool hash;
+
	bool hash_symlink;
+
	const char *outdir;
+
	int ofd;
+
	const char *metafile;
+
	struct pkg_repo_meta *meta;
+
	struct {
+
		char **argv;
+
		int argc;
+
		pkg_password_cb *cb;
+
	} sign;
+
};
+

struct pkg_dep {
	char		*origin;
	char		*name;
modified src/clean.c
@@ -132,9 +132,7 @@ delete_dellist(int fd, const char *cachedir, dl_list *dl, int total)
	progressbar_tick(processed, total);

	if (!quiet) {
-
		if (retcode == EXIT_SUCCESS)
-
			printf("All done\n");
-
		else
+
		if (retcode != EXIT_SUCCESS)
			printf("%d package%s could not be deleted\n",
			      count, count > 1 ? "s" : "");
	}
modified src/repo.c
@@ -90,13 +90,10 @@ password_cb(char *buf, int size, int rwflag, void *key)
int
exec_repo(int argc, char **argv)
{
-
	int	 ret;
	int	 ch;
-
	bool	 filelist = false;
-
	const char *output_dir = NULL;
-
	const char *meta_file = NULL;
	bool	 hash = false;
	bool	 hash_symlink = false;
+
	struct pkg_repo_create *prc = pkg_repo_create_new();

	hash = (getenv("PKG_REPO_HASH") != NULL);
	hash_symlink = (getenv("PKG_REPO_SYMLINK") != NULL);
@@ -117,16 +114,16 @@ exec_repo(int argc, char **argv)
			hash = true;
			break;
		case 'l':
-
			filelist = true;
+
			pkg_repo_create_set_create_filelist(prc, true);
			break;
		case 'o':
-
			output_dir = optarg;
+
			pkg_repo_create_set_output_dir(prc, optarg);
			break;
		case 'q':
			quiet = true;
			break;
		case 'm':
-
			meta_file = optarg;
+
			pkg_repo_create_set_metafile(prc, optarg);
			break;
		case 's':
			hash_symlink = true;
@@ -139,6 +136,10 @@ exec_repo(int argc, char **argv)
	argc -= optind;
	argv += optind;

+
	pkg_repo_create_set_hash(prc, hash);
+
	pkg_repo_create_set_hash_symlink(prc, hash_symlink);
+
	pkg_repo_create_set_sign(prc, argv + 1, argc - 1, password_cb);
+

	if (argc < 1) {
		usage_repo();
		return (EXIT_FAILURE);
@@ -149,20 +150,10 @@ exec_repo(int argc, char **argv)
		return (EXIT_FAILURE);
	}

-
	if (output_dir == NULL)
-
		output_dir = argv[0];
-

-
	ret = pkg_create_repo(argv[0], output_dir, filelist, meta_file, hash,
-
	    hash_symlink);
-

-
	if (ret != EPKG_OK) {
+
	if (pkg_repo_create(prc, argv[0]) != EPKG_OK) {
		printf("Cannot create repository catalogue\n");
		return (EXIT_FAILURE);
	}

-
	if (pkg_finish_repo(output_dir, password_cb, argv + 1, argc - 1,
-
	    filelist) != EPKG_OK)
-
		return (EXIT_FAILURE);
-

	return (EXIT_SUCCESS);
}