Radish alpha
H
HardenedBSD Package Manager
Radicle
Git (anonymous pull)
Log in to clone via SSH
First step toward real safe upgrade.
Baptiste Daroussin committed 14 years ago
commit 1cd01f26b545f9b4ac384ddab8e62a174919a749
parent bad204df7a464c6cfee26f32b127c23d36d66f8e
11 files changed +167 -53
modified libpkg/backup.c
@@ -76,7 +76,7 @@ pkgdb_load(struct pkgdb *db, char *dest)
			if (pkg == NULL) {
				pkg_new(&pkg, PKG_FILE);
			} else {
-
				pkgdb_register_finale(db, pkgdb_register_pkg(db, pkg ));
+
				pkgdb_register_finale(db, pkgdb_register_pkg(db, pkg, 0));
				pkg_reset(pkg, PKG_FILE);
			}
			size = archive_entry_size(ae);
@@ -93,7 +93,7 @@ pkgdb_load(struct pkgdb *db, char *dest)
		} else 
			continue;
	}
-
	pkgdb_register_finale(db, pkgdb_register_pkg(db, pkg ));
+
	pkgdb_register_pkg(db, pkg, 1);

cleanup:
	if (a != NULL)
modified libpkg/pkg.h
@@ -558,7 +558,7 @@ int pkgdb_has_flag(struct pkgdb *db, int flag);
 * register a package to the database.
 * @return An error code.
 */
-
int pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg);
+
int pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int complete);

/**
 * Complete an in-flight package registration command.
modified libpkg/pkg_add.c
@@ -192,17 +192,17 @@ pkg_add2(struct pkgdb *db, const char *path, int upgrade, int automatic)

	/* register the package before installing it in case there are
	 * problems that could be caught here. */
-
	retcode = pkgdb_register_pkg(db, pkg);
+
	if (upgrade == 0)
+
		retcode = pkgdb_register_pkg(db, pkg, 0);
+
	else
+
		retcode = pkgdb_register_pkg(db, pkg, 1);
	if (retcode != EPKG_OK || pkgdb_has_flag(db, PKGDB_FLAG_IN_FLIGHT) == 0)
		goto cleanup_reg;

-
	if (!upgrade)
-
		pkg_emit_install_begin(pkg);
-

	/*
	 * Execute pre-install scripts
	 */
-
	if (!upgrade)
+
	if (upgrade != 2)
		pkg_script_run(pkg, PKG_SCRIPT_PRE_INSTALL);

	/*
@@ -218,18 +218,14 @@ pkg_add2(struct pkgdb *db, const char *path, int upgrade, int automatic)
	/*
	 * Execute post install scripts
	 */
-
	if (upgrade)
+
	if (upgrade == 2)
		pkg_script_run(pkg, PKG_SCRIPT_POST_UPGRADE);
	else
		pkg_script_run(pkg, PKG_SCRIPT_POST_INSTALL);

-
	if (upgrade)
-
		pkg_emit_upgrade_finished(pkg);
-
	else
-
		pkg_emit_install_finished(pkg);
-

	cleanup_reg:
-
	pkgdb_register_finale(db, retcode);
+
	if (upgrade == 0)
+
		pkgdb_register_finale(db, retcode);

	cleanup:
	if (a != NULL)
modified libpkg/pkg_attributes.c
@@ -53,6 +53,9 @@ pkg_file_new(struct pkg_file **file)
	if ((*file = calloc(1, sizeof(struct pkg_file))) == NULL)
		return (EPKG_FATAL);

+
	(*file)->perm = 0;
+
	(*file)->keep = 0;
+

	return (EPKG_OK);
}

@@ -85,6 +88,7 @@ pkg_dir_new(struct pkg_dir **d)
		return (EPKG_FATAL);

	(*d)->perm = 0;
+
	(*d)->keep = 0;
	(*d)->try = 0;

	return (EPKG_OK);
modified libpkg/pkg_delete.c
@@ -91,6 +91,9 @@ pkg_delete_files(struct pkg *pkg, int force)
	const char *path;

	while (pkg_files(pkg, &file) == EPKG_OK) {
+
		if (file->keep == 1)
+
			continue;
+

		path = pkg_file_path(file);

		/* Regular files and links */
@@ -122,6 +125,9 @@ pkg_delete_dirs(struct pkgdb *db, struct pkg *pkg, int force)
	int64_t nbpackage;

	while (pkg_dirs(pkg, &dir) == EPKG_OK) {
+
		if (dir->keep == 1)
+
			continue;
+

		nbpackage = 0;

		if (pkgdb_is_dir_used(db, pkg_dir_path(dir), &nbpackage) != EPKG_OK)
modified libpkg/pkg_jobs.c
@@ -20,7 +20,6 @@ pkg_jobs_new(struct pkg_jobs **j, pkg_jobs_t t, struct pkgdb *db)
	}

	STAILQ_INIT(&(*j)->jobs);
-
	LIST_INIT(&(*j)->nodes);
	(*j)->db = db;
	(*j)->type = t;

@@ -79,15 +78,55 @@ pkg_jobs(struct pkg_jobs *j, struct pkg **pkg)
}

static int
+
pkg_jobs_keep_files_to_del(struct pkg *p1, struct pkg *p2)
+
{
+
	struct pkg_file *f1 = NULL, *f2 = NULL;
+
	struct pkg_dir *d1 = NULL, *d2 = NULL;
+

+
	while (pkg_files(p1, &f1) == EPKG_OK) {
+
		if (f1->keep == 1)
+
			continue;
+

+
		f2 = NULL;
+
		while (pkg_files(p2, &f2)) {
+
			if (strcmp(pkg_file_path(f1), pkg_file_path(f2)) == 0) {
+
				f1->keep = 1;
+
				break;
+
			}
+
		}
+
	}
+

+
	while (pkg_dirs(p1, &d1) == EPKG_OK) {
+
		if (d1->keep == 1)
+
			continue;
+
		d2 = NULL;
+
		while (pkg_dirs(p2, &d2)) {
+
			if (strcmp(pkg_dir_path(d1), pkg_dir_path(d2)) == 0) {
+
				d1->keep = 1;
+
				break;
+
			}
+
		}
+
	}
+

+
	return (EPKG_OK);
+
}
+

+
static int
pkg_jobs_install(struct pkg_jobs *j)
{
	struct pkg *p = NULL;
	struct pkg *pkg = NULL;
+
	struct pkg *newpkg = NULL;
+
	struct pkg *pkg_temp = NULL;
+
	struct pkgdb_it *it = NULL;
	struct sbuf *buf = sbuf_new_auto();
+
	STAILQ_HEAD(,pkg) pkg_queue;
	const char *cachedir;
	char path[MAXPATHLEN + 1];
	int ret = EPKG_OK;

+
	STAILQ_INIT(&pkg_queue);
+

	/* Fetch */
	while (pkg_jobs(j, &p) == EPKG_OK) {
		if (pkg_repo_fetch(p) != EPKG_OK)
@@ -105,7 +144,8 @@ pkg_jobs_install(struct pkg_jobs *j)
		if (pkg_open(&pkg, path, buf) != EPKG_OK)
			return (EPKG_FATAL);

-
		ret = pkgdb_integrity_append(j->db, pkg);
+
		if (pkgdb_integrity_append(j->db, pkg) != EPKG_OK)
+
			ret = EPKG_FATAL;
	}

	pkg_free(pkg);
@@ -117,19 +157,61 @@ pkg_jobs_install(struct pkg_jobs *j)
	pkg_emit_integritycheck_finished();
	p = NULL;
	/* Install */
+
	sql_exec(j->db->sqlite, "SAVEPOINT upgrade;");
	while (pkg_jobs(j, &p) == EPKG_OK) {
+
		it = pkgdb_integrity_conflict_local(j->db, pkg_get(p, PKG_ORIGIN));
+

+
		if (it != NULL) {
+
			pkg = NULL;
+
			while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC|PKG_LOAD_FILES|PKG_LOAD_SCRIPTS|PKG_LOAD_DIRS) == EPKG_OK) {
+
				STAILQ_INSERT_TAIL(&pkg_queue, pkg, next);
+
				pkg_script_run(pkg, PKG_SCRIPT_PRE_DEINSTALL);
+
				pkgdb_unregister_pkg(j->db, pkg_get(pkg, PKG_ORIGIN));
+
				pkg = NULL;
+
			}
+
			pkgdb_it_free(it);
+
		}
		snprintf(path, sizeof(path), "%s/%s", cachedir,
				 pkg_get(p, PKG_REPOPATH));

+
		pkg_open(&newpkg, path, NULL);
		if (pkg_get(p, PKG_NEWVERSION) != NULL) {
-
			p->type = PKG_INSTALLED;
-
			if (pkg_delete2(p, j->db, 1, 0) != EPKG_OK)
-
				return (EPKG_FATAL);
+
			pkg_emit_upgrade_begin(p);
+
		} else {
+
			pkg_emit_install_begin(newpkg);
+
		}
+
		STAILQ_FOREACH(pkg, &pkg_queue, next)
+
			pkg_jobs_keep_files_to_del(pkg, newpkg);
+

+
		STAILQ_FOREACH_SAFE(pkg, &pkg_queue, next, pkg_temp) {
+
			if (strcmp(pkg_get(p, PKG_ORIGIN), pkg_get(pkg, PKG_ORIGIN)) == 0) {
+
				STAILQ_REMOVE(&pkg_queue, pkg, pkg, next);
+
				pkg_delete_files(pkg, 1);
+
				pkg_script_run(pkg, PKG_SCRIPT_POST_DEINSTALL);
+
				pkg_delete_dirs(j->db, pkg, 0);
+
				pkg_free(pkg);
+
				break;
+
			}
		}

-
		if (pkg_add2(j->db, path, 0, pkg_is_automatic(p)) != EPKG_OK)
+
		if (pkg_add2(j->db, path, 1, pkg_is_automatic(p)) != EPKG_OK) {
+
			sql_exec(j->db->sqlite, "ROLLBACK TO upgrade;");
			return (EPKG_FATAL);
+
		}
+

+
		if (pkg_get(p, PKG_NEWVERSION) != NULL)
+
			pkg_emit_upgrade_finished(p);
+
		else
+
			pkg_emit_install_finished(newpkg);
+

+
		if (STAILQ_EMPTY(&pkg_queue)) {
+
			sql_exec(j->db->sqlite, "RELEASE upgrade;");
+
			sql_exec(j->db->sqlite, "SAVEPOINT upgrade;");
+
		}
	}
+
	sql_exec(j->db->sqlite, "RELEASE upgrade;");
+

+
	pkg_free(newpkg);

	return (EPKG_OK);
}
modified libpkg/pkg_private.h
@@ -65,6 +65,7 @@ struct pkg_file {
	char sha256[SHA256_DIGEST_LENGTH * 2 +1];
	char uname[MAXLOGNAME +1];
	char gname[MAXLOGNAME +1];
+
	int keep;
	mode_t perm;
	STAILQ_ENTRY(pkg_file) next;
};
@@ -74,6 +75,7 @@ struct pkg_dir {
	char uname[MAXLOGNAME +1];
	char gname[MAXLOGNAME +1];
	mode_t perm;
+
	int keep;
	int try;
	STAILQ_ENTRY(pkg_dir) next;
};
@@ -97,10 +99,8 @@ struct pkg_option {

struct pkg_jobs {
	STAILQ_HEAD(jobs, pkg) jobs;
-
	LIST_HEAD(nodes, pkg_jobs_node) nodes;
	struct pkgdb *db;
	pkg_jobs_t type;
-
	unsigned int resolved :1;
};

struct pkg_jobs_node {
@@ -181,6 +181,7 @@ int pkgdb_is_dir_used(struct pkgdb *db, const char *dir, int64_t *res);

int pkgdb_integrity_append(struct pkgdb *db, struct pkg *p);
int pkgdb_integrity_check(struct pkgdb *db);
+
struct pkgdb_it *pkgdb_integrity_conflict_local(struct pkgdb *db, const char *origin);

int pkg_set_rowid(struct pkg *, int64_t rowid);

modified libpkg/pkgdb.c
@@ -1161,7 +1161,7 @@ pkgdb_has_flag(struct pkgdb *db, int flag)
	(db)->flags &= ~(flag)

int
-
pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)
+
pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int complete)
{
	struct pkg_dep *dep = NULL;
	struct pkg_file *file = NULL;
@@ -1245,14 +1245,14 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg)

	assert(db != NULL);

-
	if (pkgdb_has_flag(db, PKGDB_FLAG_IN_FLIGHT)) {
+
	if (!complete && pkgdb_has_flag(db, PKGDB_FLAG_IN_FLIGHT)) {
		pkg_emit_error("%s", "tried to register a package with an in-flight SQL command");
		return (EPKG_FATAL);
	}

	s = db->sqlite;

-
	if (sql_exec(s, sql_begin) != EPKG_OK)
+
	if (!complete && sql_exec(s, sql_begin) != EPKG_OK)
		return (EPKG_FATAL);

	PKGDB_SET_FLAG(db, PKGDB_FLAG_IN_FLIGHT);
@@ -1921,29 +1921,38 @@ pkgdb_query_upgrades(struct pkgdb *db)

	create_temporary_pkgjobs(db->sqlite);

-
	sql_exec(db->sqlite, "INSERT INTO pkgjobs (pkgid, origin, name, version, comment, desc, message, arch, "
-
			"osversion, maintainer, www, prefix, flatsize, newversion, newflatsize, pkgsize, "
+
	sql_exec(db->sqlite,  "INSERT OR IGNORE INTO pkgjobs (pkgid, origin, name, version, comment, desc, arch, "
+
			"osversion, maintainer, www, prefix, flatsize, pkgsize, "
			"cksum, repopath, automatic) "
-
			"SELECT l.id, l.origin, l.name, l.version, l.comment, l.desc, "
-
			"l.message, l.arch, l.osversion, l.maintainer, "
-
			"l.www, l.prefix, l.flatsize, r.version AS newversion, r.flatsize AS newflatsize, "
-
			"r.pkgsize, r.cksum, r.path AS repopath, l.automatic "
-
			"FROM main.packages AS l, "
-
			"remote.packages AS r "
-
			"WHERE l.origin = r.origin "
-
			"AND (PKGLT(l.version, r.version) OR (l.name != r.name))");
+
			"SELECT id, origin, name, version, comment, desc, "
+
			"arch, osversion, maintainer, www, prefix, flatsize, pkgsize, "
+
			"cksum, path, 0 FROM remote.packages WHERE origin IN (select origin from main.packages)");

+
	/* Remove packages already installed and in the latest version */
+
	sql_exec(db->sqlite, "DELETE from pkgjobs where (select p.origin from main.packages as p where p.origin=pkgjobs.origin and version=pkgjobs.version) IS NOT NULL;");
+

+
	/* Append dependencies */
	do {
-
		sql_exec(db->sqlite, "INSERT INTO pkgjobs (pkgid, origin, name, version, comment, desc, arch, "
-
			"osversion, maintainer, www, prefix, flatsize, pkgsize, "
-
			"cksum, repopath, automatic)"
-
			"SELECT DISTINCT id, origin, name, version, comment, desc, arch, osversion, maintainer, www, prefix, flatsize, "
-
			"pkgsize, cksum, path as repopath, 1 FROM remote.packages WHERE origin IN ("
-
			"SELECT DISTINCT deps.origin FROM remote.deps as deps, pkgjobs WHERE deps.package_id = pkgjobs.pkgid and "
-
			"deps.origin NOT IN (SELECT DISTINCT origin from pkgjobs) AND deps.origin NOT IN (SELECT DISTINCT origin from main.packages)"
-
			");");
+
		sql_exec(db->sqlite, "INSERT OR IGNORE INTO pkgjobs (pkgid, origin, name, version, comment, desc, arch, "
+
				"osversion, maintainer, www, prefix, flatsize, pkgsize, "
+
				"cksum, repopath, automatic) "
+
				"SELECT DISTINCT r.id, r.origin, r.name, r.version, r.comment, r.desc, "
+
				"r.arch, r.osversion, r.maintainer, r.www, r.prefix, r.flatsize, r.pkgsize, "
+
				"r.cksum, r.path, 1 "
+
				"from remote.packages AS r where r.origin IN "
+
				"(SELECT d.origin from remote.deps AS d, pkgjobs as j WHERE d.package_id = j.pkgid) "
+
				"AND (SELECT p.origin from main.packages as p WHERE p.origin=r.origin AND version=r.version) IS NULL;");
	} while (sqlite3_changes(db->sqlite) != 0);

+
	/* Determine if there is an upgrade needed */
+
	sql_exec(db->sqlite, "INSERT OR REPLACE INTO pkgjobs (pkgid, origin, name, version, comment, desc, message, arch, "
+
			"osversion, maintainer, www, prefix, flatsize, newversion, newflatsize, pkgsize, "
+
			"cksum, repopath, automatic) "
+
			"SELECT l.id, l.origin, l.name, l.version, l.comment, l.desc, l.message, l.arch, "
+
			"l.osversion, l.maintainer, l.www, l.prefix, l.flatsize, r.version AS newversion, "
+
			"r.flatsize AS newflatsize, r.pkgsize, r.cksum, r.repopath, r.automatic "
+
			"FROM main.packages AS l, pkgjobs AS r WHERE l.origin = r.origin "
+
			"AND (PKGLT(l.version, r.version) OR (l.name != r.name))");

	if (sqlite3_prepare_v2(db->sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) {
		ERROR_SQLITE(db->sqlite);
@@ -2316,7 +2325,29 @@ pkgdb_integrity_check(struct pkgdb *db)
	sqlite3_finalize(stmt);
	sbuf_delete(conflictmsg);

-
	sql_exec(db->sqlite, "DROP TABLE IF EXISTS integritycheck");
+
/*	sql_exec(db->sqlite, "DROP TABLE IF EXISTS integritycheck");*/

	return (ret);
}
+

+
struct pkgdb_it *
+
pkgdb_integrity_conflict_local(struct pkgdb *db, const char *origin)
+
{
+
       sqlite3_stmt *stmt;
+

+
       assert(db != NULL && origin != NULL);
+

+
       const char sql_conflicts [] = "SELECT DISTINCT p.id as rowid, p.origin, p.name, p.version, p.prefix "
+
               "FROM packages AS p, files AS f, integritycheck AS i "
+
               "WHERE p.id = f.package_id AND f.path = i.path AND i.origin = ?1";
+

+
       if (sqlite3_prepare_v2(db->sqlite, sql_conflicts, -1, &stmt, NULL) != SQLITE_OK) {
+
               ERROR_SQLITE(db->sqlite);
+
               return (NULL);
+
       }
+

+
       sqlite3_bind_text(stmt, 1, origin, -1, SQLITE_TRANSIENT);
+

+
       return (pkgdb_it_new(db, stmt, PKG_INSTALLED));
+
}
+

modified libpkg/scripts.c
@@ -52,7 +52,6 @@ pkg_script_run(struct pkg * const pkg, pkg_script_t type)
			sbuf_cat(script_cmd, pkg_script_data(script));
			sbuf_finish(script_cmd);
			system(sbuf_data(script_cmd));
-

		}
	}

modified pkg/event.c
@@ -72,7 +72,7 @@ event_callback(void *data, struct pkg_event *ev)
		fflush(stdout);
		break;
	case PKG_EVENT_UPGRADE_FINISHED:
-
		printf("done\n");
+
		printf(" done\n");
		break;
	case PKG_EVENT_REQUIRED:
		pkg = ev->e_required.pkg;
modified pkg/register.c
@@ -194,12 +194,7 @@ exec_register(int argc, char **argv)
		free(input_path);
	}

-
	if (pkgdb_register_pkg(db, pkg) != EPKG_OK) {
-
		retcode = EPKG_FATAL;
-
	}
-

-
	pkgdb_register_finale(db, ret);
-
	if (ret != EPKG_OK) {
+
	if (pkgdb_register_pkg(db, pkg, 1) != EPKG_OK) {
		retcode = EPKG_FATAL;
	}