Radish alpha
H
HardenedBSD Package Manager
Radicle
Git (anonymous pull)
Log in to clone via SSH
Initial cut at adding in events, starting with errors.
Will Andrews committed 15 years ago
commit 653e68cf7d86ffdf83a34ef3f67a0a990138d103
parent e27b4cad422a04c6d3a4483ec0633fe3bbda26c3
16 files changed +307 -165
modified libpkg/Makefile
@@ -13,6 +13,7 @@ SRCS= pkg.c \
		pkg_create.c \
		pkg_delete.c \
		pkg_elf.c \
+
		pkg_event.c \
		pkg_error.c \
		pkg_handle.c \
		pkg_manifest.c \
modified libpkg/fetch.c
@@ -29,8 +29,9 @@ pkg_fetch_file(const char *url, const char *dest, void *data, fetch_cb cb)
	int retcode = EPKG_OK;

	if ((fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
-
		retcode = pkg_error_set(EPKG_FATAL, "open(%s): %s", dest,
-
								strerror(errno));
+
		pkg_emit_event(PKG_EVENT_OPEN_FAILED, /*argc*/2, dest,
+
		    strerror(errno));
+
		retcode = EPKG_FATAL;
		goto cleanup;
	}

@@ -39,7 +40,9 @@ pkg_fetch_file(const char *url, const char *dest, void *data, fetch_cb cb)
		if (remote == NULL) {
			--retry;
			if (retry == 0) {
-
				retcode = pkg_error_set(EPKG_FATAL, "%s", fetchLastErrString);
+
				pkg_emit_event(PKG_EVENT_FETCH_FAILED,
+
				    /*argc*/1, fetchLastErrString);
+
				retcode = EPKG_FATAL;
				goto cleanup;
			}
			sleep(1);
@@ -52,8 +55,9 @@ pkg_fetch_file(const char *url, const char *dest, void *data, fetch_cb cb)
			break;

		if (write(fd, buf, r) != r) {
-
			retcode = pkg_error_set(EPKG_FATAL, "write(%s): %s", dest,
-
									strerror(errno));
+
			pkg_emit_event(PKG_EVENT_WRITE_FAILED, /*argc*/2,
+
			    dest, strerror(errno));
+
			retcode = EPKG_FATAL;
			goto cleanup;
		}

@@ -67,7 +71,9 @@ pkg_fetch_file(const char *url, const char *dest, void *data, fetch_cb cb)
	}

	if (ferror(remote)) {
-
		retcode = pkg_error_set(EPKG_FATAL, "%s", fetchLastErrString);
+
		pkg_emit_event(PKG_EVENT_FETCH_FAILED, /*argc*/1,
+
		    fetchLastErrString);
+
		retcode = EPKG_FATAL;
		goto cleanup;
	}

@@ -104,7 +110,9 @@ pkg_fetch_buffer(const char *url, char **buffer, void *data, fetch_cb cb)
		if (remote == NULL) {
			--retry;
			if (retry == 0) {
-
				pkg_error_set(EPKG_FATAL, "%s", fetchLastErrString);
+
				pkg_emit_event(PKG_EVENT_FETCH_FAILED,
+
				    /*argc*/1, fetchLastErrString);
+
				retcode = EPKG_FATAL;
				goto cleanup;
			}
			sleep(1);
@@ -130,7 +138,8 @@ pkg_fetch_buffer(const char *url, char **buffer, void *data, fetch_cb cb)
	}

	if (ferror(remote)) {
-
		retcode = pkg_error_set(EPKG_FATAL, "%s", fetchLastErrString);
+
		pkg_emit_event(PKG_EVENT_FETCH_FAILED, /*argc*/1,
+
		    fetchLastErrString);
		goto cleanup;
	}

modified libpkg/packing.c
@@ -15,7 +15,6 @@
#include <stdlib.h>

#include <pkg.h>
-
#include <pkg_error.h>
#include <pkg_private.h>

static const char *packing_set_format(struct archive *a, pkg_formats format);
@@ -32,8 +31,10 @@ packing_init(struct packing **pack, const char *path, pkg_formats format)
	char archive_path[MAXPATHLEN];
	const char *ext;

-
	if ((*pack = calloc(1, sizeof(struct packing))) == NULL)
-
		return(pkg_error_set(EPKG_FATAL, "%s", strerror(errno)));
+
	if ((*pack = calloc(1, sizeof(struct packing))) == NULL) {
+
		pkg_emit_event(PKG_EVENT_MALLOC_FAILED, /*argc*/1,
+
		    strerror(errno));
+
	}

	(*pack)->aread = archive_read_disk_new();
	archive_read_disk_set_standard_lookup((*pack)->aread);
@@ -48,7 +49,7 @@ packing_init(struct packing **pack, const char *path, pkg_formats format)
			archive_read_finish((*pack)->aread);
			archive_write_finish((*pack)->awrite);
			archive_entry_free((*pack)->entry);
-
			return (pkg_error_set(EPKG_FATAL, "Unsupported format"));
+
			return EPKG_FATAL; /* error set by _set_format() */
		}
		snprintf(archive_path, sizeof(archive_path), "%s.%s", path, ext);

@@ -93,10 +94,9 @@ packing_append_file(struct packing *pack, const char *filepath, const char *newp

	retcode = archive_read_disk_entry_from_file(pack->aread, pack->entry, -1, NULL);
	if (retcode != ARCHIVE_OK) {
-
		pkg_emit_event(PKG_EVENT_ARCHIVE_ERROR, 2, filepath, pack->aread);
-
		retcode = pkg_error_set(EPKG_FATAL,
-
								"archive_read_disk_entry_from_file(%s): %s",
-
								filepath, archive_error_string(pack->aread));
+
		pkg_emit_event(PKG_EVENT_ARCHIVE_ERROR, /*argc*/2,
+
		    filepath, pack->aread);
+
		retcode = EPKG_FATAL;
		goto cleanup;
	}
	retcode = EPKG_OK;
@@ -121,8 +121,9 @@ packing_append_file(struct packing *pack, const char *filepath, const char *newp

	if (archive_entry_size(pack->entry) > 0) {
		if ((fd = open(filepath, O_RDONLY)) < 0) {
-
			retcode = pkg_error_set(EPKG_FATAL, "open(%s): %s", filepath,
-
									 strerror(errno));
+
			pkg_emit_event(PKG_EVENT_OPEN_FAILED, /*argc*/2,
+
			    filepath, strerror(errno));
+
			retcode = EPKG_FATAL;
			goto cleanup;
		}

@@ -202,19 +203,22 @@ packing_set_format(struct archive *a, pkg_formats format)
			if (archive_write_set_compression_xz(a) == ARCHIVE_OK) {
				return ("txz");
			} else {
-
				warnx("xz compression is not supported, trying bzip2");
+
				pkg_emit_event(PKG_EVENT_ARCHIVE_COMP_UNSUP,
+
				    /*argc*/2, "xz", "bzip2");
			}
		case TBZ:
			if (archive_write_set_compression_bzip2(a) == ARCHIVE_OK) {
				return ("tbz");
			} else {
-
				warnx("bzip2 compression is not supported, trying gzip");
+
				pkg_emit_event(PKG_EVENT_ARCHIVE_COMP_UNSUP,
+
				    /*argc*/2, "bzip2", "gzip");
			}
		case TGZ:
			if (archive_write_set_compression_gzip(a) == ARCHIVE_OK) {
				return ("tgz");
			} else {
-
				warnx("gzip compression is not supported, trying plain tar");
+
				pkg_emit_event(PKG_EVENT_ARCHIVE_COMP_UNSUP,
+
				    /*argc*/2, "gzip", "plain tar");
			}
		case TAR:
			archive_write_set_compression_none(a);
modified libpkg/pkg.c
@@ -14,8 +14,11 @@
int
pkg_new(struct pkg **pkg, pkg_t type)
{
-
	if ((*pkg = calloc(1, sizeof(struct pkg))) == NULL)
-
		return(pkg_error_set(EPKG_FATAL, "%s", strerror(errno)));
+
	if ((*pkg = calloc(1, sizeof(struct pkg))) == NULL) {
+
		pkg_emit_event(PKG_EVENT_MALLOC_FAILED, /*argc*/1,
+
		    strerror(errno));
+
		return EPKG_FATAL;
+
	}

	struct _fields {
		int id;
@@ -566,7 +569,8 @@ pkg_addscript_file(struct pkg *pkg, const char *path)
			strcmp(filename, "+UPGRADE") == 0) {
		type = PKG_SCRIPT_UPGRADE;
	} else {
-
		return (pkg_error_set(EPKG_FATAL, "unknown script"));
+
		pkg_emit_event(PKG_EVENT_UNKNOWN_SCRIPT, /*argc*/1, filename);
+
		return EPKG_FATAL;
	}

	ret = pkg_addscript(pkg, data, type);
@@ -778,7 +782,9 @@ pkg_open2(struct pkg **pkg_p, struct archive **a, struct archive_entry **ae, con
	archive_read_support_format_tar(*a);

	if (archive_read_open_filename(*a, path, 4096) != ARCHIVE_OK) {
-
		retcode = pkg_error_set(EPKG_FATAL, "%s", archive_error_string(*a));
+
		pkg_emit_event(PKG_EVENT_ARCHIVE_ERROR, /*argc*/2,
+
		    archive_entry_pathname(*ae), *a);
+
		retcode = EPKG_FATAL;
		goto cleanup;
	}

@@ -838,8 +844,11 @@ pkg_open2(struct pkg **pkg_p, struct archive **a, struct archive_entry **ae, con
		}
	}

-
	if (ret != ARCHIVE_OK && ret != ARCHIVE_EOF)
-
		retcode = pkg_error_set(EPKG_FATAL, "%s", archive_error_string(*a));
+
	if (ret != ARCHIVE_OK && ret != ARCHIVE_EOF) {
+
		pkg_emit_event(PKG_EVENT_ARCHIVE_ERROR, /*argc*/2,
+
		    archive_entry_pathname(*ae), *a);
+
		retcode = EPKG_FATAL;
+
	}

	if (ret == ARCHIVE_EOF)
		retcode = EPKG_END;
@@ -865,7 +874,7 @@ pkg_copy_tree(struct pkg *pkg, const char *src, const char *dest)

	if (packing_init(&pack, dest, 0) != EPKG_OK) {
		/* TODO */
-
		return (pkg_error_set(EPKG_FATAL, "unable to create archive"));
+
		return EPKG_FATAL;
	}

	while (pkg_files(pkg, &file) == EPKG_OK) {
modified libpkg/pkg.h
@@ -581,7 +581,33 @@ typedef enum {
	PKG_EVENT_INSTALL_BEGIN = 0,

	/* errors */
-
	PKG_EVENT_ARCHIVE_ERROR = 65536,
+
	PKG_EVENT_ARCHIVE_COMP_UNSUP = 65536,
+
	PKG_EVENT_ARCHIVE_ERROR,
+
	PKG_EVENT_ACCESS_ERROR,
+
	PKG_EVENT_ALREADY_INSTALLED,
+
	PKG_EVENT_CKSUM_FAILED,
+
	PKG_EVENT_CONFIG_KEY_NOTFOUND,
+
	PKG_EVENT_CREATEDB_FAILED,
+
	PKG_EVENT_CREATEDB_FAILED_ERRNO,
+
	PKG_EVENT_DB_OPEN_FAILED,
+
	PKG_EVENT_DELETE_DEP_EXISTS,
+
	PKG_EVENT_ERROR_INSTALLING_DEP,
+
	PKG_EVENT_FETCH_FAILED,
+
	PKG_EVENT_FSTAT_ERROR,
+
	PKG_EVENT_INVALID_DB_STATE,
+
	PKG_EVENT_MALLOC_FAILED,
+
	PKG_EVENT_MISSING_DEP,
+
	PKG_EVENT_OPEN_DB_FAILED,
+
	PKG_EVENT_OPEN_ERROR,
+
	PKG_EVENT_OPEN_FAILED,
+
	PKG_EVENT_PARSE_ERROR,
+
	PKG_EVENT_READ_ERROR,
+
	PKG_EVENT_REPO_KEY_UNAVAIL,
+
	PKG_EVENT_REPO_KEY_UNUSABLE,
+
	PKG_EVENT_SQLITE_CONSTRAINT,
+
	PKG_EVENT_SQLITE_ERROR,
+
	PKG_EVENT_UNKNOWN_SCRIPT,
+
	PKG_EVENT_WRITE_FAILED,
} pkg_event_t;

/**
modified libpkg/pkg_add.c
@@ -41,7 +41,9 @@ do_extract(struct archive *a, struct archive_entry *ae)

	do {
		if (archive_read_extract(a, ae, EXTRACT_ARCHIVE_FLAGS) != ARCHIVE_OK) {
-
			retcode = pkg_error_set(EPKG_FATAL, "%s", archive_error_string(a));
+
			pkg_emit_event(PKG_EVENT_ARCHIVE_ERROR, /*argc*/2,
+
			    archive_entry_pathname(ae), a);
+
			retcode = EPKG_FATAL;
			break;
		}

@@ -57,14 +59,19 @@ do_extract(struct archive *a, struct archive_entry *ae)
		    && lstat(path, &st) == ENOENT) {
			archive_entry_set_pathname(ae, path);
			if (archive_read_extract(a, ae, EXTRACT_ARCHIVE_FLAGS) != ARCHIVE_OK) {
-
				retcode = pkg_error_set(EPKG_FATAL, "%s", archive_error_string(a));
+
				pkg_emit_event(PKG_EVENT_ARCHIVE_ERROR, /*argc*/2,
+
				    archive_entry_pathname(ae), a);
+
				retcode = EPKG_FATAL;
				break;
			}
		}
	} while ((ret = archive_read_next_header(a, &ae)) == ARCHIVE_OK);

-
	if (ret != ARCHIVE_EOF)
-
		retcode = pkg_error_set(EPKG_FATAL, "%s", archive_error_string(a));
+
	if (ret != ARCHIVE_EOF) {
+
		pkg_emit_event(PKG_EVENT_ARCHIVE_ERROR, /*argc*/2,
+
		    archive_entry_pathname(ae), a);
+
		retcode = EPKG_FATAL;
+
	}

	return (retcode);
}
@@ -112,15 +119,17 @@ pkg_add(struct pkgdb *db, const char *path, struct pkg **pkg_p)

	ret = pkgdb_it_next(it, &p, PKG_LOAD_BASIC);
	pkgdb_it_free(it);
-
	pkg_free(p);

	if (ret == EPKG_OK) {
-
		retcode = pkg_error_set(EPKG_INSTALLED, "package already installed");
+
		pkg_emit_event(PKG_EVENT_ALREADY_INSTALLED, /*argc*/1, p);
+
		retcode = EPKG_INSTALLED;
		goto cleanup;
	} else if (ret != EPKG_END) {
		retcode = ret;
		goto cleanup;
	}
+
	pkg_free(p);
+
	p = NULL;

	/*
	 * Check for dependencies
@@ -140,16 +149,18 @@ pkg_add(struct pkgdb *db, const char *path, struct pkg **pkg_p)

			if (access(dpath, F_OK) == 0) {
				if (pkg_add(db, dpath, NULL) != EPKG_OK) {
-
					retcode = pkg_error_set(EPKG_FATAL, "error while "
-
											"installing %s (dependency): %s",
-
											dpath,
-
											pkg_error_string());
+
					/* XXX: maybe the pkg_error_string()
+
					 * should be handled in the event
+
					 * handler */
+
					pkg_emit_event(PKG_EVENT_ERROR_INSTALLING_DEP,
+
					    /*argc*/2, dpath, pkg_error_string());
+
					retcode = EPKG_FATAL;
					goto cleanup;
				}
			} else {
-
				retcode = pkg_error_set(EPKG_DEPENDENCY, "missing %s-%s dependency",
-
										pkg_dep_name(dep),
-
										pkg_dep_version(dep));
+
				retcode = EPKG_FATAL;
+
				pkg_emit_event(PKG_EVENT_MISSING_DEP, /*argc*/2,
+
				    pkg_dep_name(dep), pkg_dep_version(dep));
				goto cleanup;
			}
		}
@@ -161,7 +172,7 @@ pkg_add(struct pkgdb *db, const char *path, struct pkg **pkg_p)
	if (retcode != EPKG_OK || pkgdb_has_flag(db, PKGDB_FLAG_IN_FLIGHT) == 0)
		goto cleanup_reg;

-
	pkg_emit_event(PKG_EVENT_INSTALL_BEGIN, 1, pkg);
+
	pkg_emit_event(PKG_EVENT_INSTALL_BEGIN, /*argc*/1, pkg);

	/*
	 * Execute pre-install scripts
@@ -190,6 +201,9 @@ pkg_add(struct pkgdb *db, const char *path, struct pkg **pkg_p)
	if (a != NULL)
		archive_read_finish(a);

+
	if (p != NULL)
+
		pkg_free(p);
+

	if (pkg_p != NULL)
		*pkg_p = (retcode == EPKG_OK) ? pkg : NULL;
	else
modified libpkg/pkg_config.c
@@ -71,6 +71,6 @@ pkg_config(const char *key)
		}
	}

-
	pkg_error_set(EPKG_FATAL, "unknown configuration key `%s'", key);
+
	pkg_emit_event(PKG_EVENT_CONFIG_KEY_NOTFOUND, /*argc*/1, key);
	return (NULL);
}
modified libpkg/pkg_create_repo.c
@@ -76,8 +76,11 @@ pkg_create_repo(char *path, void (progress)(struct pkg *pkg, void *data), void *
		"INSERT INTO deps (origin, name, version, package_id) "
		"VALUES (?1, ?2, ?3, ?4);";

-
	if (!is_dir(path))
-
		return (pkg_error_set(EPKG_FATAL, "%s is not a directory", path));
+
	if (!is_dir(path)) {
+
		pkg_emit_event(PKG_EVENT_CREATEDB_FAILED, /*argc*/2,
+
		    path, "not a directory");
+
		return EPKG_FATAL;
+
	}

	repopath[0] = path;
	repopath[1] = NULL;
@@ -85,21 +88,25 @@ pkg_create_repo(char *path, void (progress)(struct pkg *pkg, void *data), void *
	snprintf(repodb, MAXPATHLEN, "%s/repo.sqlite", path);

	if (stat(repodb, &st) != -1)
-
		if (unlink(repodb) != 0)
-
			return (pkg_error_set(EPKG_FATAL, "can not unlink %s: %s", repodb,
-
								  strerror(errno)));
+
		if (unlink(repodb) != 0) {
+
			pkg_emit_event(PKG_EVENT_CREATEDB_FAILED_ERRNO,
+
			    /*argc*/3, path, repodb, strerror(errno));
+
			return EPKG_FATAL;
+
		}

	if (sqlite3_open(repodb, &sqlite) != SQLITE_OK)
		return (EPKG_FATAL);

	if (sqlite3_exec(sqlite, initsql, NULL, NULL, &errmsg) != SQLITE_OK) {
-
		retcode = pkg_error_set(EPKG_FATAL, "%s", errmsg);
+
		pkg_emit_event(PKG_EVENT_SQLITE_ERROR, /*argc*/1, errmsg);
+
		retcode = EPKG_FATAL;
		goto cleanup;
	}

	if (sqlite3_exec(sqlite, "BEGIN TRANSACTION;", NULL, NULL, &errmsg) !=
		SQLITE_OK) {
-
		retcode = pkg_error_set(EPKG_FATAL, "%s", errmsg);
+
		pkg_emit_event(PKG_EVENT_SQLITE_ERROR, /*argc*/1, errmsg);
+
		retcode = EPKG_FATAL;
		goto cleanup;
	}

@@ -114,8 +121,9 @@ pkg_create_repo(char *path, void (progress)(struct pkg *pkg, void *data), void *
	}

	if ((fts = fts_open(repopath, FTS_PHYSICAL, NULL)) == NULL) {
-
		retcode = pkg_error_set(EPKG_FATAL, "can not open %s: %s", repopath,
-
								strerror(errno));
+
		pkg_emit_event(PKG_EVENT_OPEN_DB_FAILED, /*argc*/2,
+
		    repopath, strerror(errno));
+
		retcode = EPKG_FATAL;
		goto cleanup;
	}

@@ -143,8 +151,10 @@ pkg_create_repo(char *path, void (progress)(struct pkg *pkg, void *data), void *

		if (pkg_open(&pkg, ent->fts_accpath) != EPKG_OK) {
			if (progress != NULL) {
-
				pkg_error_set(EPKG_WARN, "can not open %s: %s", ent->fts_name,
-
							  pkg_error_string());
+
				pkg_emit_event(PKG_EVENT_DB_OPEN_FAILED,
+
				    /*argc*/2, ent->fts_name,
+
				    pkg_error_string());
+
				retcode = EPKG_WARN;
				progress(NULL, data);
			}
			continue;
@@ -191,8 +201,10 @@ pkg_create_repo(char *path, void (progress)(struct pkg *pkg, void *data), void *

	}

-
	if (sqlite3_exec(sqlite, "COMMIT;", NULL, NULL, &errmsg) != SQLITE_OK)
-
		retcode = pkg_error_set(EPKG_FATAL, "%s", errmsg);
+
	if (sqlite3_exec(sqlite, "COMMIT;", NULL, NULL, &errmsg) != SQLITE_OK) {
+
		pkg_emit_event(PKG_EVENT_SQLITE_ERROR, /*argc*/1, errmsg);
+
		retcode = EPKG_FATAL;
+
	}

	cleanup:
	if (fts != NULL)
@@ -256,8 +268,11 @@ pkg_finish_repo(char *path, pem_password_cb *password_cb, char *rsa_key_path)

	packing_init(&pack, repo_archive, TXZ);
	if (rsa_key_path != NULL) {
-
		if (access(rsa_key_path, R_OK) == -1)
-
			return pkg_error_set(EPKG_FATAL, "RSA key invalid: %s", strerror(errno));
+
		if (access(rsa_key_path, R_OK) == -1) {
+
			pkg_emit_event(PKG_EVENT_REPO_KEY_UNAVAIL, /*argc*/2,
+
			    rsa_key_path, strerror(errno));
+
			return EPKG_FATAL;
+
		}

		SSL_load_error_strings();

@@ -271,8 +286,11 @@ pkg_finish_repo(char *path, pem_password_cb *password_cb, char *rsa_key_path)

		sha256_file(repo_path, sha256);

-
		if (RSA_sign(NID_sha1, sha256, 65, sigret, &siglen, rsa) == 0)
-
			return pkg_error_set(EPKG_FATAL, "Unable to sign the repository");
+
		if (RSA_sign(NID_sha1, sha256, 65, sigret, &siglen, rsa) == 0) {
+
			pkg_emit_event(PKG_EVENT_REPO_KEY_UNUSABLE, /*argc*/2,
+
			    rsa_key_path, ERR_get_error()); /* XXX pass back RSA errors correctly */
+
			return EPKG_FATAL;
+
		}

		packing_append_buffer(pack, sigret, "signature", max_len);

modified libpkg/pkg_delete.c
@@ -50,7 +50,9 @@ pkg_delete(struct pkg *pkg, struct pkgdb *db, int force)
	if (rdep_msg != NULL) {
		if (!force) {
			sbuf_finish(rdep_msg);
-
			ret = pkg_error_set(EPKG_REQUIRED, "%s", sbuf_get(rdep_msg));
+
			pkg_emit_event(PKG_EVENT_DELETE_DEP_EXISTS, /*argc*/1,
+
			    sbuf_get(rdep_msg));
+
			ret = EPKG_REQUIRED;
			sbuf_free(rdep_msg);
			return ret;
		}
added libpkg/pkg_event.c
@@ -0,0 +1,65 @@
+
#include <assert.h>
+
#include <archive.h>
+
#include "pkg.h"
+
#include "pkg_error.h"
+

+
/* Guard-rail against incorrect number of arguments */
+
static void
+
pkg_event_argument_check(pkg_event_t ev, int argc)
+
{
+

+
	switch(ev) {
+
	case PKG_EVENT_INSTALL_BEGIN:
+
		assert(argc == 1);
+
		break;
+
	case PKG_EVENT_ARCHIVE_ERROR:
+
		assert(argc == 2);
+
		break;
+
	default:
+
		break;
+
	}
+
}
+

+
/**
+
 * This function's purpose is to perform global event handling.
+
 */
+
static void
+
libpkg_handle_event(pkg_event_t ev, void **argv)
+
{
+
	switch(ev) {
+
	case PKG_EVENT_ARCHIVE_ERROR:
+
		pkg_error_set(EPKG_FATAL, "archive_read_disk_entry_from_file(%s): %s",
+
		    argv[0], archive_error_string(argv[1]));
+
		break;
+
	case PKG_EVENT_OPEN_FAILED:
+
		pkg_error_set(EPKG_FATAL, "open of %s failed: %s", argv[0], argv[1]);
+
		break;
+
	default:
+
		break;
+
	}
+
}
+

+
void
+
__pkg_emit_event(struct pkg_handle *hdl, pkg_event_t ev, int argc, ...)
+
{
+
	va_list ap;
+
	void **argv;
+
	int i;
+

+
	if (hdl == NULL || hdl->event_cb == NULL)
+
		return;
+

+
	pkg_event_argument_check(ev, argc);
+

+
	/* Generate the argument vector to pass in. */
+
	argv = calloc(argc, sizeof(void *));
+
	va_start(ap, argc);
+
	for (i = 0;i < argc; i++)
+
		argv[i] = va_arg(ap, void *);
+
	va_end(ap);
+

+
	libpkg_handle_event(ev, argv);
+

+
	if (hdl->event_cb != NULL)
+
		hdl->event_cb(ev, argv);
+
}
modified libpkg/pkg_handle.c
@@ -1,4 +1,3 @@
-
#include <assert.h>
#include "pkg.h"

struct pkg_handle __pkg_handle_singleton;
@@ -20,42 +19,3 @@ pkg_handle_get_event_callback(struct pkg_handle *hdl)
{
	return hdl->event_cb;
}
-

-
/* Guard-rail against incorrect number of arguments */
-
static void
-
pkg_event_argument_check(pkg_event_t ev, int argc)
-
{
-

-
	switch(ev) {
-
	case PKG_EVENT_INSTALL_BEGIN:
-
		assert(argc == 1);
-
		break;
-
	case PKG_EVENT_ARCHIVE_ERROR:
-
		assert(argc == 2);
-
		break;
-
	default:
-
		break;
-
	}
-
}
-

-
void
-
__pkg_emit_event(struct pkg_handle *hdl, pkg_event_t ev, int argc, ...)
-
{
-
	va_list ap;
-
	void **argv;
-
	int i;
-

-
	if (hdl == NULL || hdl->event_cb == NULL)
-
		return;
-

-
	pkg_event_argument_check(ev, argc);
-

-
	/* Generate the argument vector to pass in. */
-
	argv = calloc(argc, sizeof(void *));
-
	va_start(ap, argc);
-
	for (i = 0;i < argc; i++)
-
		argv[i] = va_arg(ap, void *);
-
	va_end(ap);
-

-
	hdl->event_cb(ev, argv);
-
}
modified libpkg/pkg_manifest.c
@@ -133,9 +133,11 @@ m_parse_flatsize(struct pkg *pkg, char *buf)
	errno = 0;
	size = strtoimax(buf, NULL, 10);

-
	if (errno == EINVAL || errno == ERANGE)
-
		return (pkg_error_set(EPKG_FATAL, "m_parse_flatsize(): %s",
-
				strerror(errno)));
+
	if (errno == EINVAL || errno == ERANGE) {
+
		pkg_emit_event(PKG_EVENT_PARSE_ERROR, /*argc*/2,
+
		    "flatsize", strerror(errno));
+
		return EPKG_FATAL;
+
	}

	pkg_setflatsize(pkg, size);
	return (EPKG_OK);
modified libpkg/pkg_repo.c
@@ -31,8 +31,10 @@ pkg_repo_fetch(struct pkg *pkg, void *data, fetch_cb cb)
	checksum:
	retcode = sha256_file(dest, cksum);
	if (retcode == EPKG_OK)
-
		if (strcmp(cksum, pkg_get(pkg, PKG_CKSUM)))
-
			retcode = pkg_error_set(EPKG_FATAL, "failed checksum");
+
		if (strcmp(cksum, pkg_get(pkg, PKG_CKSUM))) {
+
			pkg_emit_event(PKG_EVENT_CKSUM_FAILED, /*argc*/1, pkg);
+
			retcode = EPKG_FATAL;
+
		}

	return (retcode);
}
modified libpkg/pkg_util.c
@@ -70,23 +70,30 @@ file_to_buffer(const char *path, char **buffer, off_t *sz)
		return (ERROR_BAD_ARG("buffer"));

	if ((fd = open(path, O_RDONLY)) == -1) {
-
		return (pkg_error_set(EPKG_FATAL, "can not open %s: %s", path,
-
				strerror(errno)));
+
		pkg_emit_event(PKG_EVENT_OPEN_ERROR, /*argc*/2, path,
+
		    strerror(errno));
+
		return EPKG_FATAL;
	}

	if (fstat(fd, &st) == -1) {
		close(fd);
-
		return (pkg_error_set(EPKG_FATAL, "fstat(): %s", strerror(errno)));
+
		pkg_emit_event(PKG_EVENT_FSTAT_ERROR, /*argc*/2, path,
+
		    strerror(errno));
+
		return EPKG_FATAL;
	}

	if ((*buffer = malloc(st.st_size + 1)) == NULL) {
		close(fd);
-
		return (pkg_error_set(EPKG_FATAL, "malloc(): %s", strerror(errno)));
+
		pkg_emit_event(PKG_EVENT_MALLOC_FAILED, /*argc*/1,
+
		    strerror(errno));
+
		return EPKG_FATAL;
	}

	if (read(fd, *buffer, st.st_size) == -1) {
		close(fd);
-
		return (pkg_error_set(EPKG_FATAL, "read(%s): %s", path, strerror(errno)));
+
		pkg_emit_event(PKG_EVENT_READ_ERROR, /*argc*/2,
+
		    path, strerror(errno));
+
		return EPKG_FATAL;
	}

	close(fd);
@@ -206,9 +213,11 @@ sha256_file(const char *path, char out[65])
	size_t r = 0;
	SHA256_CTX sha256;

-
	if ((fp = fopen(path, "rb")) == NULL)
-
		return (pkg_error_set(EPKG_FATAL, "fopen(%s): %s", path,
-
							  strerror(errno)));
+
	if ((fp = fopen(path, "rb")) == NULL) {
+
		pkg_emit_event(PKG_EVENT_OPEN_FAILED, /*argc*/2,
+
		    path, strerror(errno));
+
		return EPKG_FATAL;
+
	}

	SHA256_Init(&sha256);

@@ -218,9 +227,9 @@ sha256_file(const char *path, char out[65])
	if (ferror(fp) != 0) {
		fclose(fp);
		out[0] = '\0';
-
		return (pkg_error_set(EPKG_FATAL, "fread(%s): %s", path,
-
							  strerror(errno)));
-

+
		pkg_emit_event(PKG_EVENT_READ_ERROR, /*argc*/2,
+
		    path, strerror(errno));
+
		return EPKG_FATAL;
	}

	fclose(fp);
modified libpkg/pkgdb.c
@@ -231,7 +231,7 @@ pkgdb_init(sqlite3 *sdb)
	;

	if (sqlite3_exec(sdb, sql, NULL, NULL, &errmsg) != SQLITE_OK) {
-
		pkg_error_set(EPKG_FATAL, "sqlite: %s", errmsg);
+
		pkg_emit_event(PKG_EVENT_SQLITE_ERROR, /*argc*/1, errmsg);
		sqlite3_free(errmsg);
		return (EPKG_FATAL);
	}
@@ -251,20 +251,27 @@ pkgdb_open(struct pkgdb **db, pkgdb_t type)

	dbdir = pkg_config("PKG_DBDIR");

-
	if ((*db = calloc(1, sizeof(struct pkgdb))) == NULL)
-
		return (pkg_error_set(EPKG_FATAL, "calloc(): %s", strerror(errno)));
+
	if ((*db = calloc(1, sizeof(struct pkgdb))) == NULL) {
+
		pkg_emit_event(PKG_EVENT_MALLOC_FAILED, /*argc*/1,
+
		    strerror(errno));
+
		return EPKG_FATAL;
+
	}

	(*db)->type = type;

	snprintf(localpath, sizeof(localpath), "%s/local.sqlite", dbdir);
	retcode = access(localpath, R_OK);
	if (retcode == -1) {
-
		if (errno != ENOENT)
-
			return (pkg_error_set(EPKG_FATAL, "%s: %s", localpath,
-
								  strerror(errno)));
-
		else if (eaccess(dbdir, W_OK) != 0)
-
			return (pkg_error_set(EPKG_FATAL, "can not initialize database in "
-
								 "%s: %s", dbdir, strerror(errno)));
+
		if (errno != ENOENT) {
+
			pkg_emit_event(PKG_EVENT_ACCESS_ERROR, /*argc*/2,
+
			    localpath, strerror(errno));
+
			return EPKG_FATAL;
+
		}
+
		else if (eaccess(dbdir, W_OK) != 0) {
+
			pkg_emit_event(PKG_EVENT_ACCESS_ERROR, /*argc*/2,
+
			    dbdir, strerror(errno));
+
			return EPKG_FATAL;
+
		}
	}

	if (sqlite3_open(localpath, &(*db)->sqlite) != SQLITE_OK)
@@ -273,14 +280,16 @@ pkgdb_open(struct pkgdb **db, pkgdb_t type)
	if (type == PKGDB_REMOTE) {
		snprintf(remotepath, sizeof(remotepath), "%s/repo.sqlite", dbdir);

-
		if (access(remotepath, R_OK) != 0)
-
			return (pkg_error_set(EPKG_FATAL, "repo.sqlite: %s",
-
								  strerror(errno)));
+
		if (access(remotepath, R_OK) != 0) {
+
			pkg_emit_event(PKG_EVENT_ACCESS_ERROR, /*argc*/2,
+
			    remotepath, strerror(errno));
+
			return EPKG_FATAL;
+
		}

		sqlite3_snprintf(sizeof(sql), sql, "ATTACH \"%s\" as remote;", remotepath);

		if (sqlite3_exec((*db)->sqlite, sql, NULL, NULL, &errmsg) != SQLITE_OK) {
-
			pkg_error_set(EPKG_FATAL, "%s", errmsg);
+
			pkg_emit_event(PKG_EVENT_SQLITE_ERROR, /*argc*/1, errmsg);
			sqlite3_free(errmsg);
			return (EPKG_FATAL);
		}
@@ -306,7 +315,7 @@ pkgdb_open(struct pkgdb **db, pkgdb_t type)
	 */
	if (sqlite3_exec((*db)->sqlite, "PRAGMA foreign_keys = ON;", NULL, NULL,
		&errmsg) != SQLITE_OK) {
-
		pkg_error_set(EPKG_FATAL, "sqlite: %s", errmsg);
+
		pkg_emit_event(PKG_EVENT_SQLITE_ERROR, /*argc*/1, errmsg);
		sqlite3_free(errmsg);
		return (EPKG_FATAL);
	}
@@ -336,7 +345,8 @@ pkgdb_it_new(struct pkgdb *db, sqlite3_stmt *s, int type)
	struct pkgdb_it *it;

	if ((it = malloc(sizeof(struct pkgdb_it))) == NULL) {
-
		pkg_error_set(EPKG_FATAL, "malloc(): %s", strerror(errno));
+
		pkg_emit_event(PKG_EVENT_MALLOC_FAILED, /*argc*/1,
+
		    strerror(errno));
		sqlite3_finalize(s);
		return (NULL);
	}
@@ -880,14 +890,15 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
		"VALUES (?1, ?2);";

	if (pkgdb_has_flag(db, PKGDB_FLAG_IN_FLIGHT)) {
-
		pkg_error_set(EPKG_FATAL, "tried to register a package with an in-flight SQL command");
+
		pkg_emit_event(PKG_EVENT_INVALID_DB_STATE, /*argc*/1,
+
		    "tried to register a package with an in-flight SQL command");
		return (EPKG_FATAL);
	}

	s = db->sqlite;

	if (sqlite3_exec(s, sql_begin, NULL, NULL, &errmsg) != SQLITE_OK) {
-
		pkg_error_set(EPKG_FATAL, "sqlite: %s", errmsg);
+
		pkg_emit_event(PKG_EVENT_SQLITE_ERROR, /*argc*/1, errmsg);
		sqlite3_free(errmsg);
		return (EPKG_FATAL);
	}
@@ -916,10 +927,10 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
	sqlite3_bind_int(stmt_pkg, 14, pkg_isautomatic(pkg));

	if ((ret = sqlite3_step(stmt_pkg)) != SQLITE_DONE) {
-
		if ( ret == SQLITE_CONSTRAINT)
-
			retcode = pkg_error_set(EPKG_FATAL, "constraint violation on "
-
					"pkg with %s", pkg_get(pkg, PKG_ORIGIN));
-
		else
+
		if ( ret == SQLITE_CONSTRAINT) {
+
			pkg_emit_event(PKG_EVENT_SQLITE_CONSTRAINT, /*argc*/1, pkg);
+
			retcode = EPKG_FATAL;
+
		} else
			retcode = ERROR_SQLITE(s);
		goto cleanup;
	}
@@ -959,10 +970,10 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
		sqlite3_bind_int64(stmt_dep, 4, package_id);

		if ((ret = sqlite3_step(stmt_dep)) != SQLITE_DONE) {
-
			if ( ret == SQLITE_CONSTRAINT)
-
				retcode = pkg_error_set(EPKG_FATAL, "constraint violation on "
-
						"deps with %s", pkg_dep_origin(dep));
-
			else
+
			if ( ret == SQLITE_CONSTRAINT) {
+
				pkg_emit_event(PKG_EVENT_SQLITE_CONSTRAINT, /*argc*/1,dep);
+
				retcode = EPKG_FATAL;
+
			} else
				retcode = ERROR_SQLITE(s);
			goto cleanup;
		}
@@ -984,10 +995,10 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
		sqlite3_bind_int64(stmt_conflict, 2, package_id);

		if ((ret = sqlite3_step(stmt_conflict)) != SQLITE_DONE) {
-
			if ( ret == SQLITE_CONSTRAINT)
-
				retcode = pkg_error_set(EPKG_FATAL, "constraint violation on "
-
						"conflicts with %s", pkg_conflict_glob(conflict));
-
			else
+
			if ( ret == SQLITE_CONSTRAINT) {
+
				pkg_emit_event(PKG_EVENT_SQLITE_CONSTRAINT, /*argc*/1, conflict);
+
				retcode = EPKG_FATAL;
+
			} else
				retcode = ERROR_SQLITE(s);
			goto cleanup;
		}
@@ -1011,10 +1022,10 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
		sqlite3_bind_int64(stmt_file, 3, package_id);

		if ((ret = sqlite3_step(stmt_file)) != SQLITE_DONE) {
-
			if (ret == SQLITE_CONSTRAINT)
-
				retcode = pkg_error_set(EPKG_FATAL, "constraint violation on "
-
						"path with %s", pkg_file_path(file));
-
			else
+
			if (ret == SQLITE_CONSTRAINT) {
+
				pkg_emit_event(PKG_EVENT_SQLITE_CONSTRAINT, /*argc*/1, file);
+
				retcode = EPKG_FATAL;
+
			} else
				retcode = ERROR_SQLITE(s);
			goto cleanup;
		}
@@ -1035,10 +1046,10 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
		sqlite3_bind_text(stmt_dirs, 2, pkg_dir_path(dir), -1, SQLITE_STATIC);
			
		if ((ret = sqlite3_step(stmt_dirs)) != SQLITE_DONE) {
-
			if ( ret == SQLITE_CONSTRAINT)
-
				retcode = pkg_error_set(EPKG_FATAL, "constraint violation on "
-
						"dirs with %s", pkg_dir_path(dir));
-
			else
+
			if ( ret == SQLITE_CONSTRAINT) {
+
				pkg_emit_event(PKG_EVENT_SQLITE_CONSTRAINT, /*argc*/1, dir);
+
				retcode = EPKG_FATAL;
+
			} else
				retcode = ERROR_SQLITE(s);
			goto cleanup;
		}
@@ -1060,10 +1071,10 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
		sqlite3_bind_int64(stmt_script, 3, package_id);

		if (sqlite3_step(stmt_script) != SQLITE_DONE) {
-
			if ( ret == SQLITE_CONSTRAINT)
-
				retcode = pkg_error_set(EPKG_FATAL, "constraint violation on "
-
						"scripts with %s", pkg_script_data(script));
-
			else
+
			if ( ret == SQLITE_CONSTRAINT) {
+
				pkg_emit_event(PKG_EVENT_SQLITE_CONSTRAINT, /*argc*/1, script);
+
				retcode = EPKG_FATAL;
+
			} else
				retcode = ERROR_SQLITE(s);
			goto cleanup;
		}
@@ -1131,13 +1142,15 @@ pkgdb_register_finale(struct pkgdb *db, int retcode)
	char *errmsg;

	if (!pkgdb_has_flag(db, PKGDB_FLAG_IN_FLIGHT)) {
-
		ret = pkg_error_set(EPKG_FATAL, "database command not in flight");
-
		return ret;
+
		pkg_emit_event(PKG_EVENT_INVALID_DB_STATE, /*argc*/1,
+
		    "database command not in flight");
+
		return EPKG_FATAL;
	}

	command = (retcode == EPKG_OK) ? commands[0] : commands[1];
	if (sqlite3_exec(db->sqlite, command, NULL, NULL, &errmsg) != SQLITE_OK) {
-
		ret = pkg_error_set(EPKG_FATAL, "sqlite: %s", errmsg);
+
		pkg_emit_event(PKG_EVENT_SQLITE_ERROR, /*argc*/1, errmsg);
+
		ret = EPKG_FATAL;
		sqlite3_free(errmsg);
	}
	PKGDB_UNSET_FLAG(db, PKGDB_FLAG_IN_FLIGHT);
@@ -1217,7 +1230,8 @@ pkgdb_compact(struct pkgdb *db)
		return (EPKG_OK);

	if (sqlite3_exec(db->sqlite, "VACUUM;", NULL, NULL, &errmsg) != SQLITE_OK){
-
		retcode = pkg_error_set(EPKG_FATAL, "%s", errmsg);
+
		pkg_emit_event(PKG_EVENT_SQLITE_ERROR, /*argc*/1, errmsg);
+
		retcode = EPKG_FATAL;
		sqlite3_free(errmsg);
	}

@@ -1230,7 +1244,8 @@ pkgdb_query_upgrades(struct pkgdb *db)
	sqlite3_stmt *stmt;

	if (db->type != PKGDB_REMOTE) {
-
		pkg_error_set(EPKG_FATAL, "remote database not attached");
+
		pkg_emit_event(PKG_EVENT_INVALID_DB_STATE, /*argc*/1,
+
		    "remote database not attached");
		return (NULL);
	}

@@ -1258,7 +1273,8 @@ pkgdb_query_downgrades(struct pkgdb *db)
	sqlite3_stmt *stmt;

	if (db->type != PKGDB_REMOTE) {
-
		pkg_error_set(EPKG_FATAL, "remote database not attached");
+
		pkg_emit_event(PKG_EVENT_INVALID_DB_STATE, /*argc*/1,
+
		    "remote database not attached");
		return (NULL);
	}

modified pkg/event.c
@@ -1,4 +1,5 @@
#include <archive.h>
+
#include <err.h>

#include "pkg.h"
#include "event.h"
@@ -15,6 +16,10 @@ event_callback(pkg_event_t ev, void **argv)
		fprintf(stderr, "archive error on %s: %s\n",
		    (const char *)argv[0], archive_error_string(argv[1]));
		break;
+
	case PKG_EVENT_ARCHIVE_COMP_UNSUP:
+
		warnx("%s is not supported, trying %s",
+
		    (const char *)argv[0], (const char *)argv[1]);
+
		break;
	default:
		break;
	}