Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
First step toward real safe upgrade.
Baptiste Daroussin committed 14 years ago
commit 1cd01f26b545f9b4ac384ddab8e62a174919a749
parent bad204d
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;
	}