Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Implement the concept of in-flight package registration.
Will Andrews committed 14 years ago
commit 07f52a3c8a8a39a360bef0aff196eacc6deda393
parent dec3653
5 files changed +183 -53
modified libpkg/pkg.h
@@ -401,12 +401,26 @@ int pkgdb_open(struct pkgdb **db, pkgdb_t remote, int mode);
void pkgdb_close(struct pkgdb *db);

/**
+
 * Whether a package database instance has a particular flag.
+
 * @return 0 if false, true otherwise
+
 */
+
int pkgdb_has_flag(struct pkgdb *db, int flag);
+

+
/* The flags used in pkgdb_has_flag() */
+
#define	PKGDB_FLAG_IN_FLIGHT	(1 << 0)
+

+
/**
 * Register a package to the database.
 * @return An error code.
 */
int pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg);

/**
+
 * Complete an in-flight package registration command.
+
 */
+
int pkgdb_register_finale(struct pkgdb *db, int retcode);
+

+
/**
 * Unregister a package from the database.
 * @return An error code.
 */
@@ -503,6 +517,16 @@ int pkg_create_fakeroot(const char *, pkg_formats, const char *, const char *);
int pkg_delete(struct pkg *pkg, struct pkgdb *db, int force);

/**
+
 * These functions are helpers for specific parts of pkg_delete().
+
 * Generally speaking, external consumers should not use these.
+
 * @return An error code on failure, or EPKG_OK.
+
 */
+
int pkg_pre_deinstall(struct pkg *pkg);
+
int pkg_delete_files(struct pkg *pkg, int force);
+
int pkg_post_deinstall(struct pkg *pkg);
+
int pkg_run_unexecs(struct pkg *pkg);
+

+
/**
 * Get the value of a configuration key
 */
const char * pkg_config(const char *key);
modified libpkg/pkg_add.c
@@ -65,7 +65,6 @@ pkg_add(struct pkgdb *db, const char *path, struct pkg **pkg_p)
	char dpath[MAXPATHLEN];
	const char *basedir;
	const char *ext;
-
	int registered = 0;
	int retcode = EPKG_OK;
	int ret;
	int i;
@@ -151,8 +150,7 @@ pkg_add(struct pkgdb *db, const char *path, struct pkg **pkg_p)
	/* Register the package before installing it in case there are
	 * problems that could be caught here. */
	retcode = pkgdb_register_pkg(db, pkg);
-
	registered = 1;
-
	if (retcode != EPKG_OK)
+
	if (retcode != EPKG_OK || pkgdb_has_flag(db, PKGDB_FLAG_IN_FLIGHT) == 0)
		goto cleanup;

	/*
@@ -223,8 +221,10 @@ pkg_add(struct pkgdb *db, const char *path, struct pkg **pkg_p)

	cleanup:

-
	if (registered && retcode != EPKG_OK)
-
		pkgdb_unregister_pkg(db, pkg_get(pkg, PKG_ORIGIN));
+
	pkgdb_register_finale(db, retcode);
+
	/* If the add failed, clean up */
+
	if (retcode != EPKG_OK)
+
		(void) pkg_delete_files(pkg, 1);

	if (a != NULL)
		archive_read_finish(a);
modified libpkg/pkg_delete.c
@@ -2,6 +2,9 @@
#include <err.h>
#include <unistd.h>
#include <stdlib.h>
+
#include <errno.h>
+
#include <sys/types.h>
+
#include <sys/stat.h>

#include "pkg.h"
#include "pkg_error.h"
@@ -11,12 +14,7 @@ int
pkg_delete(struct pkg *pkg, struct pkgdb *db, int force)
{
	struct pkg **rdeps;
-
	struct pkg_file **files;
-
	struct pkg_exec **execs;
-
	struct pkg_script **scripts;
-
	char sha256[65];
-
	struct sbuf *script_cmd;
-
	int ret, i;
+
	int ret;

	if (pkg == NULL)
		return (ERROR_BAD_ARG("pkg"));
@@ -29,25 +27,114 @@ pkg_delete(struct pkg *pkg, struct pkgdb *db, int force)
	 */
	if ((ret = pkgdb_loadrdeps(db, pkg)) != EPKG_OK)
		return (ret);
-
	if ((ret = pkgdb_loadfiles(db, pkg)) != EPKG_OK)
-
		return (ret);
	if ((ret = pkgdb_loadscripts(db, pkg)) != EPKG_OK)
		return (ret);
+
	if ((ret = pkgdb_loadmtree(db, pkg)) != EPKG_OK)
+
		return (ret);
	if ((ret = pkgdb_loadexecs(db, pkg)) != EPKG_OK)
		return (ret);
-
	if ((ret = pkgdb_loadmtree(db, pkg)) != EPKG_OK)
+
	if ((ret = pkgdb_loadfiles(db, pkg)) != EPKG_OK)
		return (ret);

+

	rdeps = pkg_rdeps(pkg);
-
	files = pkg_files(pkg);
-
	scripts = pkg_scripts(pkg);
-
	execs = pkg_execs(pkg);

	if (rdeps[0] != NULL && force == 0)
		return (pkg_error_set(EPKG_REQUIRED, "this package is required by "
							  "other packages"));

+
	if ((ret = pkg_pre_deinstall(pkg)) != EPKG_OK)
+
		return (ret);
+

+
	if ((ret = pkg_delete_files(pkg, force)) != EPKG_OK)
+
		return (ret);
+

+
	if ((ret = pkg_post_deinstall(pkg)) != EPKG_OK)
+
		return (ret);
+

+
	if ((ret = pkg_run_unexecs(pkg)) != EPKG_OK)
+
		return (ret);
+

+
	return (pkgdb_unregister_pkg(db, pkg_get(pkg, PKG_ORIGIN)));
+
}
+

+
int
+
pkg_run_unexecs(struct pkg *pkg)
+
{
+
	int ret = EPKG_OK;
+
	int i;
+
	struct pkg_exec **execs;
+

+
	execs = pkg_execs(pkg);
+

+
	/* run the @unexec */
+
	for (i = 0; execs[i] != NULL; i++)
+
		if (pkg_exec_type(execs[i]) == PKG_UNEXEC)
+
			system(pkg_exec_cmd(execs[i]));
+

+
	return (ret);
+
}
+

+
int
+
pkg_delete_files(struct pkg *pkg, int force)
+
{
+
	int do_remove, i;
+
	int ret = EPKG_OK;
+
	struct pkg_file **files;
+
	char sha256[65];
+
	const char *path;
+
	struct stat st;
+

+
	files = pkg_files(pkg);
+
	for (i = 0; files[i] != NULL; i++) {
+
		path = pkg_file_path(files[i]);
+
		/* check to make sure the file exists */
+
		if (stat(path, &st) == -1) {
+
			/* don't print ENOENT errors on force */
+
			if (!force && errno != ENOENT)
+
				warn("%s", path);
+
			continue;
+
		}
+
		/* check sha256 */
+
		do_remove = 1;
+
		if (pkg_file_sha256(files[i])[0] != '\0') {
+
			if (sha256_file(path, sha256) == -1) {
+
				warnx("sha256 calculation failed for '%s'",
+
				    pkg_file_path(files[i]));
+
			} else {
+
				if (strcmp(sha256, pkg_file_sha256(files[i])) != 0) {
+
					if (force)
+
						warnx("%s fails original SHA256 checksum", path);
+
					else {
+
						do_remove = 0;
+
						warnx("%s fails original SHA256 checksum, not removing", path);
+
					}
+
				}
+
			}
+
		}
+
		if (do_remove && unlink(pkg_file_path(files[i])) == -1) {
+
			if (is_dir(pkg_file_path(files[i]))) {
+
				rmdir(pkg_file_path(files[i]));
+
			} else {
+
				warn("unlink(%s)", pkg_file_path(files[i]));
+
				continue;
+
			}
+
		}
+
	}
+

+
	return (ret);
+
}
+

+
int
+
pkg_pre_deinstall(struct pkg *pkg)
+
{
+
	int ret = EPKG_OK;
+
	int i;
+
	struct sbuf *script_cmd;
+
	struct pkg_script **scripts;
+

	script_cmd = sbuf_new_auto();
+
	scripts = pkg_scripts(pkg);
	/* execute PRE_DEINSTALL */
	for (i = 0; scripts[i] != NULL; i++) {
		switch (pkg_script_type(scripts[i])) {
@@ -68,24 +155,21 @@ pkg_delete(struct pkg *pkg, struct pkgdb *db, int force)
				break;
		}
	}
+
	sbuf_free(script_cmd);

-
	for (i = 0; files[i] != NULL; i++) {
-
		/* check sha256 */
-
		if (pkg_file_sha256(files[i])[0] != '\0' &&
-
			(sha256_file(pkg_file_path(files[i]), sha256) == -1 ||
-
			strcmp(sha256, pkg_file_sha256(files[i])) != 0))
-
			warnx("%s fails original SHA256 checksum, not removed",
-
					pkg_file_path(files[i]));
+
	return (ret);
+
}

-
		else if (unlink(pkg_file_path(files[i])) == -1) {
-
			if (is_dir(pkg_file_path(files[i]))) {
-
				rmdir(pkg_file_path(files[i]));
-
			} else {
-
				warn("unlink(%s)", pkg_file_path(files[i]));
-
				continue;
-
			}
-
		}
-
	}
+
int
+
pkg_post_deinstall(struct pkg *pkg)
+
{
+
	int i;
+
	int ret = EPKG_OK;
+
	struct sbuf *script_cmd;
+
	struct pkg_script **scripts;
+

+
	script_cmd = sbuf_new_auto();
+
	scripts = pkg_scripts(pkg);

	for (i = 0; scripts[i] != NULL; i++) {
		switch (pkg_script_type(scripts[i])) {
@@ -106,13 +190,7 @@ pkg_delete(struct pkg *pkg, struct pkgdb *db, int force)
				break;
		}
	}
-

	sbuf_free(script_cmd);

-
	/* run the @unexec */
-
	for (i = 0; execs[i] != NULL; i++)
-
		if (pkg_exec_type(execs[i]) == PKG_UNEXEC)
-
			system(pkg_exec_cmd(execs[i]));
-

-
	return (pkgdb_unregister_pkg(db, pkg_get(pkg, PKG_ORIGIN)));
+
	return (ret);
}
modified libpkg/pkgdb.c
@@ -838,6 +838,17 @@ pkgdb_loadmtree(struct pkgdb *db, struct pkg *pkg)
}

int
+
pkgdb_has_flag(struct pkgdb *db, int flag)
+
{
+
	return (db->flags & flag);
+
}
+

+
#define	PKGDB_SET_FLAG(db, flag) \
+
	(db)->flags |= (flag)
+
#define	PKGDB_UNSET_FLAG(db, flag) \
+
	(db)->flags &= ~(flag)
+

+
int
pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
{
	struct pkg **deps;
@@ -899,14 +910,19 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
		"INSERT INTO options (option, value, package_id) "
		"VALUES (?1, ?2, ?3);";

-
	s = db->sqlite;
+
	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");
+
		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);
		sqlite3_free(errmsg);
		return (EPKG_FATAL);
	}
+
	PKGDB_SET_FLAG(db, PKGDB_FLAG_IN_FLIGHT);

	/*
	 * If this package has a mtree, insert it in the database.
@@ -1139,14 +1155,6 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
		sqlite3_reset(stmt_option);
	}

-
	/*
-
	 * Register the package for real
-
	 */
-
	if (sqlite3_exec(s, "COMMIT;", NULL, NULL, &errmsg) != SQLITE_OK) {
-
		retcode = pkg_error_set(EPKG_FATAL, "sqlite: %s", errmsg);
-
		sqlite3_free(errmsg);
-
	}
-

	cleanup:

	if (stmt_sel_mtree != NULL)
@@ -1176,14 +1184,33 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
	if (stmt_option != NULL)
		sqlite3_finalize(stmt_option);

-
	if (retcode != EPKG_OK && sqlite3_exec(db->sqlite, "ROLLBACK;", NULL, NULL, &errmsg) !=
-
		SQLITE_OK)
-
		err(1, "Can not rollback: %s", errmsg);
-

	return (retcode);
}

int
+
pkgdb_register_finale(struct pkgdb *db, int retcode)
+
{
+
	int ret = EPKG_OK;
+
	const char *commands[] = { "COMMIT;", "ROLLBACK;", NULL };
+
	const char *command;
+
	char *errmsg;
+

+
	if (!pkgdb_has_flag(db, PKGDB_FLAG_IN_FLIGHT)) {
+
		ret = pkg_error_set(EPKG_FATAL, "database command not in flight");
+
		return ret;
+
	}
+

+
	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);
+
		sqlite3_free(errmsg);
+
	}
+
	PKGDB_UNSET_FLAG(db, PKGDB_FLAG_IN_FLIGHT);
+

+
	return ret;
+
}
+

+
int
pkgdb_unregister_pkg(struct pkgdb *db, const char *origin)
{
	sqlite3_stmt *stmt_del;
modified libpkg/pkgdb.h
@@ -6,6 +6,7 @@
#include "sqlite3.h"

struct pkgdb {
+
	uint64_t flags;
	sqlite3 *sqlite;
	pkgdb_t remote;
};