Skip to content
Snippets Groups Projects
database.c 42.5 KiB
Newer Older
	struct apk_package *pkg;
	struct apk_db_dir_instance *diri;
	struct hlist_node *dc, *dn;
	int i;

	list_for_each_entry(pkg, &db->installed.packages, installed_pkgs_list) {
		hlist_for_each_entry_safe(diri, dc, dn, &pkg->owned_dirs, pkg_dirs_list) {
			apk_db_diri_free(db, diri);
		}
	}

	for (i = 0; i < db->num_repos; i++) {
		free(db->repos[i].url);
	if (db->protected_paths) {
		for (i = 0; i < db->protected_paths->num; i++)
			free(db->protected_paths->item[i]);
		free(db->protected_paths);
	}
	if (db->world)
		free(db->world);
	apk_hash_free(&db->available.names);
	apk_hash_free(&db->available.packages);
	apk_hash_free(&db->installed.files);
		close(db->root_fd);
	if (db->lock_fd)
		close(db->lock_fd);
	if (db->root != NULL)
Timo Teräs's avatar
Timo Teräs committed
int apk_db_cache_active(struct apk_database *db)
{
	return db->cache_dir != apk_static_cache_dir;
}

int apk_db_permanent(struct apk_database *db)
{
	return db->permanent;
Timo Teräs's avatar
Timo Teräs committed
struct apk_package *apk_db_get_pkg(struct apk_database *db,
				   struct apk_checksum *csum)
Timo Teräs's avatar
Timo Teräs committed
	return apk_hash_get(&db->available.packages, APK_BLOB_CSUM(*csum));
struct apk_package *apk_db_get_file_owner(struct apk_database *db,
					  apk_blob_t filename)
{
	if (filename.len && filename.ptr[0] == '/')
		filename.len--, filename.ptr++;
	if (!apk_blob_rsplit(filename, '/', &key.dirname, &key.filename))
		return NULL;

	dbf = (struct apk_db_file *) apk_hash_get(&db->installed.files,
						  APK_BLOB_BUF(&key));
static struct apk_bstream *apk_db_cache_open(struct apk_database *db,
Timo Teräs's avatar
Timo Teräs committed
					     struct apk_checksum *csum,
					     const char *file)
{
	char tmp[256];

	if (db->root == NULL)
		return NULL;
	apk_db_cache_get_name(tmp, sizeof(tmp), db, csum, file, FALSE);
	return apk_bstream_from_file(tmp);
}

static struct apk_bstream *apk_repository_file_open(struct apk_repository *repo,
						    const char *file)
{
	char tmp[256];
Timo Teräs's avatar
Timo Teräs committed
	const char *url = repo->url;
Timo Teräs's avatar
Timo Teräs committed
	snprintf(tmp, sizeof(tmp), "%s%s%s",
		 url, url[strlen(url)-1] == '/' ? "" : "/", file);

	return apk_bstream_from_url(tmp);
}

Timo Teräs's avatar
Timo Teräs committed
int apk_cache_download(struct apk_database *db, struct apk_checksum *csum,
		       const char *url, const char *item, int verify)
{
	char tmp[256], tmp2[256];
	snprintf(tmp, sizeof(tmp), "%s%s%s",
		 url, url[strlen(url)-1] == '/' ? "" : "/", item);
Timo Teräs's avatar
Timo Teräs committed
	apk_message("fetch %s", tmp);
Timo Teräs's avatar
Timo Teräs committed
	if (apk_flags & APK_SIMULATE)
		return 0;
Timo Teräs's avatar
Timo Teräs committed
	apk_db_cache_get_name(tmp2, sizeof(tmp2), db, csum, item, TRUE);
	r = apk_url_download(tmp, tmp2);
	if (r < 0)
		return r;

	if (verify != APK_SIGN_NONE) {
		struct apk_istream *is;
		struct apk_sign_ctx sctx;

		apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL);
		is = apk_bstream_gunzip_mpart(apk_bstream_from_file(tmp2),
			apk_sign_ctx_mpart_cb, &sctx);
		r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx);
Timo Teräs's avatar
Timo Teräs committed
		is->close(is);
		apk_sign_ctx_free(&sctx);
Timo Teräs's avatar
Timo Teräs committed
		if (r != 0) {
			unlink(tmp2);
Timo Teräs's avatar
Timo Teräs committed
			return r;
Timo Teräs's avatar
Timo Teräs committed
	apk_db_cache_get_name(tmp, sizeof(tmp), db, csum, item, FALSE);
	if (rename(tmp2, tmp) < 0)
		return -errno;

	return 0;
}

Timo Teräs's avatar
Timo Teräs committed
int apk_cache_exists(struct apk_database *db, struct apk_checksum *csum,
		     const char *item)
Timo Teräs's avatar
Timo Teräs committed
{
	char tmp[256];

	if (db->root == NULL)
		return 0;

	apk_db_cache_get_name(tmp, sizeof(tmp), db, csum, item, FALSE);
	return access(tmp, R_OK | W_OK) == 0;
}

static int apk_cache_delete(struct apk_database *db, struct apk_checksum *csum,
			    const char *item)
{
	char tmp[256];

	if (db->root == NULL)
		return 0;

	apk_db_cache_get_name(tmp, sizeof(tmp), db, csum, item, FALSE);
	return unlink(tmp);
}

Timo Teräs's avatar
Timo Teräs committed
int apk_repository_update(struct apk_database *db, struct apk_repository *repo)
{
Timo Teräs's avatar
Timo Teräs committed
	if (repo->csum.type == APK_CHECKSUM_NONE)
Timo Teräs's avatar
Timo Teräs committed
		return 0;

	r = apk_cache_download(db, &repo->csum, repo->url, apkindex_tar_gz,
			       APK_SIGN_VERIFY);
Timo Teräs's avatar
Timo Teräs committed
	if (r == 0 || r == -ENOKEY || r == -EKEYREJECTED) {
		if (r == -ENOKEY)
			apk_error("%s: verify: UNTRUSTED", repo->url);
		else if (r == -EKEYREJECTED)
			apk_error("%s: verify: FAILED", repo->url);
		apk_cache_delete(db, &repo->csum, apk_index_gz);
		return r;
	}

	r = apk_cache_download(db, &repo->csum, repo->url, apk_index_gz,
			       APK_SIGN_NONE);
	if (r != 0)
Timo Teräs's avatar
Timo Teräs committed
		apk_error("Failed to update %s: download failed", repo->url);
}

struct apkindex_ctx {
	struct apk_database *db;
	struct apk_sign_ctx sctx;
};

static int load_apkindex(void *sctx, const struct apk_file_info *fi,
			 struct apk_istream *is)
{
	struct apkindex_ctx *ctx = (struct apkindex_ctx *) sctx;
	struct apk_bstream *bs;

	if (apk_sign_ctx_process_file(&ctx->sctx, fi, is) == 0)
		return 0;

	if (strcmp(fi->name, "APKINDEX") != 0)
		return 0;

	bs = apk_bstream_from_istream(is);
	apk_db_index_read(ctx->db, bs, ctx->repo);
	bs->close(bs, NULL);

static int load_index(struct apk_database *db, struct apk_bstream *bs,
		      int targz, int repo)
{
	if (targz) {
		struct apk_istream *is;
		struct apkindex_ctx ctx;

		ctx.db = db;
		ctx.repo = repo;
		apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY, NULL);
		is = apk_bstream_gunzip_mpart(bs, apk_sign_ctx_mpart_cb, &ctx.sctx);
		r = apk_tar_parse(is, load_apkindex, &ctx);
		is->close(is);
		apk_sign_ctx_free(&ctx.sctx);
			r = -ENOMSG;
	} else {
		bs = apk_bstream_from_istream(apk_bstream_gunzip(bs));
		apk_db_index_read(db, bs, repo);
		bs->close(bs, NULL);
	}
}

int apk_db_index_read_file(struct apk_database *db, const char *file, int repo)
{
	int targz = 1;

	if (strstr(file, ".tar.gz") == NULL && strstr(file, ".gz") != NULL)
		targz = 0;

	return load_index(db, apk_bstream_from_file(file), targz, repo);
}

int apk_db_add_repository(apk_database_t _db, apk_blob_t repository)
{
	struct apk_database *db = _db.db;
	struct apk_bstream *bs = NULL;
	struct apk_repository *repo;
	int r, targz = 1;
	if (repository.ptr == NULL || *repository.ptr == '\0'
			|| *repository.ptr == '#')
		return 0;

	if (db->num_repos >= APK_MAX_REPOS)
		return -1;

	r = db->num_repos++;

	repo = &db->repos[r];
	*repo = (struct apk_repository) {
		.url = apk_blob_cstr(repository),
	if (apk_url_local_file(repo->url) == NULL) {
Timo Teräs's avatar
Timo Teräs committed
		apk_blob_checksum(repository, apk_default_checksum(), &repo->csum);
		if (apk_flags & APK_UPDATE_CACHE)
			apk_repository_update(db, repo);
		bs = apk_db_cache_open(db, &repo->csum, apkindex_tar_gz);
		if (bs == NULL) {
Timo Teräs's avatar
Timo Teräs committed
			bs = apk_db_cache_open(db, &repo->csum, apk_index_gz);
			targz = 0;
		bs = apk_repository_file_open(repo, apkindex_tar_gz);
		if (bs == NULL) {
			bs = apk_repository_file_open(repo, apk_index_gz);
			targz = 0;
		}
		apk_warning("Failed to open index for %s", repo->url);
	r = load_index(db, bs, targz, r);
	if (r != 0)
		apk_error("%s: Bad repository signature", repo->url);
	return r;
static void extract_cb(void *_ctx, size_t progress)
{
	struct install_ctx *ctx = (struct install_ctx *) _ctx;

	if (ctx->cb) {
		size_t size = ctx->installed_size;

		size += muldiv(progress, ctx->current_file_size, APK_PROGRESS_SCALE);
		if (size > ctx->pkg->installed_size)
			size = ctx->pkg->installed_size;

		ctx->cb(ctx->cb_ctx, muldiv(APK_PROGRESS_SCALE, size, ctx->pkg->installed_size));
	}
}

static int apk_db_run_pending_script(struct install_ctx *ctx)
{
	int r;

	if (!ctx->script_pending)
		return 0;
	if (!ctx->sctx.control_verified)
		return 0;

	ctx->script_pending = FALSE;
	r = apk_pkg_run_script(ctx->pkg, ctx->db->root_fd, ctx->script);
	if (r != 0)
		apk_error("%s-%s: Failed to execute "
			  "pre-install/upgrade script",
			  ctx->pkg->name->name, ctx->pkg->version);
	return r;
}

static int apk_db_install_archive_entry(void *_ctx,
					const struct apk_file_info *ae,
					struct apk_istream *is)
	struct install_ctx *ctx = (struct install_ctx *) _ctx;
	struct apk_package *pkg = ctx->pkg, *opkg;
	apk_blob_t name = APK_BLOB_STR(ae->name), bdir, bfile;
	struct apk_db_dir_instance *diri = ctx->diri;
	char alt_name[PATH_MAX];
	int r = 0, type = APK_SCRIPT_INVALID;
	apk_sign_ctx_verify_tar(&ctx->sctx, ae, is);
	/* Package metainfo and script processing */
	if (ae->name[0] == '.') {
		/* APK 2.0 format */
		type = apk_script_type(&ae->name[1]);
		if (type == APK_SCRIPT_INVALID)
			return 0;
	} else if (strncmp(ae->name, "var/db/apk/", 11) == 0) {
		/* APK 1.0 format */
		p = &ae->name[11];
		if (strncmp(p, pkg->name->name, strlen(pkg->name->name)) != 0)
			return 0;
		p += strlen(pkg->name->name) + 1;
		if (strncmp(p, pkg->version, strlen(pkg->version)) != 0)
			return 0;
		p += strlen(pkg->version) + 1;

		type = apk_script_type(p);
		if (type == APK_SCRIPT_INVALID)
	/* Handle script */
	if (type != APK_SCRIPT_INVALID) {
		apk_pkg_add_script(pkg, is, type, ae->size);
		if (type == ctx->script)
			ctx->script_pending = TRUE;
		return apk_db_run_pending_script(ctx);
	}
	r = apk_db_run_pending_script(ctx);
	if (r != 0)
	/* Show progress */
	if (ctx->cb) {
		size_t size = ctx->installed_size;
		if (size > pkg->installed_size)
			size = pkg->installed_size;
		ctx->cb(ctx->cb_ctx, muldiv(APK_PROGRESS_SCALE, size, pkg->installed_size));
	}

	/* Installable entry */
	ctx->current_file_size = apk_calc_installed_size(ae->size);
		if (!apk_blob_rsplit(name, '/', &bdir, &bfile))
			return 0;

		if (bfile.len > 6 && memcmp(bfile.ptr, ".keep_", 6) == 0)
			return 0;

		/* Make sure the file is part of the cached directory tree */
		if (diri == NULL ||
		    apk_blob_compare(APK_BLOB_PTR_LEN(diri->dir->name,
						      diri->dir->namelen),
				     bdir) != 0) {
			struct hlist_node *n;
			hlist_for_each_entry(diri, n, &pkg->owned_dirs, pkg_dirs_list) {
Timo Teräs's avatar
Timo Teräs committed
				if (apk_blob_compare(APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen), bdir) == 0)
					break;
			}
			if (diri == NULL) {
				apk_error("%s: File '%*s' entry without directory entry.\n",
					  pkg->name->name, name.len, name.ptr);
				return -1;
			}
			ctx->diri = diri;
			ctx->file_diri_node = hlist_tail_ptr(&diri->owned_files);
Timo Teräs's avatar
Timo Teräs committed
		file = apk_db_file_query(db, bdir, bfile);
		if (file != NULL) {
			opkg = file->diri->pkg;
			if (opkg->name != pkg->name) {
				if (!(apk_flags & APK_FORCE)) {
					apk_error("%s: Trying to overwrite %s "
						  pkg->name->name, ae->name,
						  opkg->name->name);
					return -1;
				}
				apk_warning("%s: Overwriting %s owned by %s.",
					    pkg->name->name, ae->name,
					    opkg->name->name);
Timo Teräs's avatar
Timo Teräs committed
		/* Create the file entry without adding it to hash */
		file = apk_db_file_new(diri, bfile, &ctx->file_diri_node);

		if (apk_verbosity >= 3)
			apk_message("%s", ae->name);
Timo Teräs's avatar
Timo Teräs committed
		/* Extract the file as name.apk-new */
		snprintf(alt_name, sizeof(alt_name), "%s/%s.apk-new",
			 diri->dir->name, file->name);
		r = apk_archive_entry_extract(ae, is, alt_name,
					      extract_cb, ctx);
		if (apk_verbosity >= 3)
			apk_message("%s", ae->name);
		if (name.ptr[name.len-1] == '/')
			name.len--;

		if (ctx->diri_node == NULL)
			ctx->diri_node = hlist_tail_ptr(&pkg->owned_dirs);
		ctx->diri = diri = apk_db_diri_new(db, pkg, name,
						   &ctx->diri_node);
		ctx->file_diri_node = hlist_tail_ptr(&diri->owned_files);

		apk_db_diri_set(diri, ae->mode & 0777, ae->uid, ae->gid);
		apk_db_diri_mkdir(diri);
	ctx->installed_size += ctx->current_file_size;
Timo Teräs's avatar
Timo Teräs committed
static void apk_db_purge_pkg(struct apk_database *db, struct apk_package *pkg,
			     const char *exten)
	struct apk_db_dir_instance *diri;
	struct apk_db_file_hash_key key;
	struct apk_file_info fi;
	struct hlist_node *dc, *dn, *fc, *fn;
Timo Teräs's avatar
Timo Teräs committed
	unsigned long hash;
	char name[1024];

	hlist_for_each_entry_safe(diri, dc, dn, &pkg->owned_dirs, pkg_dirs_list) {
		hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) {
Timo Teräs's avatar
Timo Teräs committed
			snprintf(name, sizeof(name), "%s/%s%s",
				 diri->dir->name, file->name, exten ?: "");

			key = (struct apk_db_file_hash_key) {
Timo Teräs's avatar
Timo Teräs committed
				.dirname = APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen),
				.filename = APK_BLOB_PTR_LEN(file->name, file->namelen),
Timo Teräs's avatar
Timo Teräs committed
			hash = apk_blob_hash_seed(key.filename, diri->dir->hash);
			if (!(diri->dir->flags & APK_DBDIRF_PROTECTED) ||
			    (apk_flags & APK_PURGE) ||
			    (apk_file_get_info(name, file->csum.type, &fi) == 0 &&
			     apk_checksum_compare(&file->csum, &fi.csum) == 0))
				unlink(name);
			if (apk_verbosity >= 3)
				apk_message("%s", name);
			__hlist_del(fc, &diri->owned_files.first);
Timo Teräs's avatar
Timo Teräs committed
			if (exten == NULL) {
				apk_hash_delete_hashed(&db->installed.files, APK_BLOB_BUF(&key), hash);
				db->installed.stats.files--;
			}
		apk_db_diri_rmdir(diri);
		__hlist_del(dc, &pkg->owned_dirs.first);
		apk_db_diri_free(db, diri);
	apk_pkg_set_state(db, pkg, APK_PKG_NOT_INSTALLED);
Timo Teräs's avatar
Timo Teräs committed

static void apk_db_migrate_files(struct apk_database *db,
				 struct apk_package *pkg)
{
	struct apk_db_dir_instance *diri;
	struct apk_db_dir *dir;
	struct apk_db_file *file, *ofile;
	struct apk_db_file_hash_key key;
	struct apk_file_info fi;
	struct hlist_node *dc, *dn, *fc, *fn;
	unsigned long hash;
	char name[1024], tmpname[1024];
Timo Teräs's avatar
Timo Teräs committed
	int r;
Timo Teräs's avatar
Timo Teräs committed

	hlist_for_each_entry_safe(diri, dc, dn, &pkg->owned_dirs, pkg_dirs_list) {
		dir = diri->dir;

		hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) {
			snprintf(name, sizeof(name), "%s/%s",
				 diri->dir->name, file->name);
			snprintf(tmpname, sizeof(tmpname), "%s/%s.apk-new",
				 diri->dir->name, file->name);

			key = (struct apk_db_file_hash_key) {
				.dirname = APK_BLOB_PTR_LEN(dir->name, dir->namelen),
				.filename = APK_BLOB_PTR_LEN(file->name, file->namelen),
			};

			hash = apk_blob_hash_seed(key.filename, dir->hash);

			/* check for existing file */
			ofile = (struct apk_db_file *) apk_hash_get_hashed(
				&db->installed.files, APK_BLOB_BUF(&key), hash);

			r = apk_file_get_info(name,
				ofile ? ofile->csum.type : APK_CHECKSUM_NONE,
				&fi);
Timo Teräs's avatar
Timo Teräs committed
			if ((diri->dir->flags & APK_DBDIRF_PROTECTED) &&
			    (r == 0) &&
			    (ofile == NULL ||
			     apk_checksum_compare(&ofile->csum, &fi.csum) == 0)) {
				/* Protected directory, with file without
				 * db entry, or local modifications.
				 *
				 * Delete the apk-new if it's identical with the
				 * existing file */
				if (ofile == NULL ||
				    ofile->csum.type != file->csum.type)
Timo Teräs's avatar
Timo Teräs committed
					apk_file_get_info(name, file->csum.type, &fi);
				if ((apk_flags & APK_CLEAN_PROTECTED) ||
				    apk_checksum_compare(&file->csum, &fi.csum) == 0)
Timo Teräs's avatar
Timo Teräs committed
					unlink(tmpname);
			} else {
				/* Overwrite the old file */
				rename(tmpname, name);
			}

			/* Claim ownership of the file in db */
			if (ofile != NULL) {
				hlist_del(&ofile->diri_files_list,
Timo Teräs's avatar
Timo Teräs committed
					  &ofile->diri->owned_files);
Timo Teräs's avatar
Timo Teräs committed
				apk_hash_delete_hashed(&db->installed.files,
						       APK_BLOB_BUF(&key), hash);
			} else
				db->installed.stats.files++;

			apk_hash_insert_hashed(&db->installed.files, file, hash);
		}
	}
}

static int apk_db_unpack_pkg(struct apk_database *db,
			     struct apk_package *newpkg,
			     int upgrade, apk_progress_cb cb, void *cb_ctx)
	struct apk_bstream *bs = NULL;
	struct apk_istream *tar;
	char pkgname[256], file[256];
	int r, i, need_copy = FALSE;

	snprintf(pkgname, sizeof(pkgname), "%s-%s.apk",
		 newpkg->name->name, newpkg->version);
	if (newpkg->filename == NULL) {
		struct apk_repository *repo;

		for (i = 0; i < APK_MAX_REPOS; i++)
			if (newpkg->repos & BIT(i))
				break;

		if (i >= APK_MAX_REPOS) {
			apk_error("%s-%s: not present in any repository",
				  newpkg->name->name, newpkg->version);
			return -1;
		}

		repo = &db->repos[i];
Timo Teräs's avatar
Timo Teräs committed
		if (apk_db_cache_active(db) &&
		    repo->csum.type != APK_CHECKSUM_NONE)
			bs = apk_db_cache_open(db, &newpkg->csum, pkgname);

		if (bs == NULL) {
Timo Teräs's avatar
Timo Teräs committed
			bs = apk_repository_file_open(repo, pkgname);
Timo Teräs's avatar
Timo Teräs committed
			if (repo->csum.type != APK_CHECKSUM_NONE)
				need_copy = TRUE;
		}
	} else {
		bs = apk_bstream_from_file(newpkg->filename);
		need_copy = TRUE;
	}
Timo Teräs's avatar
Timo Teräs committed
	if (!apk_db_cache_active(db))
		need_copy = FALSE;
	if (need_copy) {
Timo Teräs's avatar
Timo Teräs committed
		apk_db_cache_get_name(file, sizeof(file), db, &newpkg->csum,
				      pkgname, TRUE);
		bs = apk_bstream_tee(bs, file);
	}
	if (bs == NULL) {
		apk_error("%s: %s", file, strerror(errno));

	ctx = (struct install_ctx) {
		.db = db,
		.pkg = newpkg,
		.script = upgrade ?
			APK_SCRIPT_PRE_UPGRADE : APK_SCRIPT_PRE_INSTALL,
		.cb = cb,
		.cb_ctx = cb_ctx,
	apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY_IDENTITY, &newpkg->csum);
	tar = apk_bstream_gunzip_mpart(bs, apk_sign_ctx_mpart_cb, &ctx.sctx);
	r = apk_tar_parse(tar, apk_db_install_archive_entry, &ctx);
	apk_sign_ctx_free(&ctx.sctx);
	tar->close(tar);
		apk_error("%s-%s: %s",
			  newpkg->name->name, newpkg->version,
			  apk_error_str(r));
Timo Teräs's avatar
Timo Teräs committed
		goto err;
	r = apk_db_run_pending_script(&ctx);
	if (r != 0)
Timo Teräs's avatar
Timo Teräs committed
		goto err;

	apk_db_migrate_files(db, newpkg);
	if (need_copy) {
		char file2[256];
		apk_db_cache_get_name(file2, sizeof(file2), db,
				      &newpkg->csum, pkgname, FALSE);
		rename(file, file2);
Timo Teräs's avatar
Timo Teräs committed
err:
	apk_db_purge_pkg(db, newpkg, ".apk-new");
	return r;
}

int apk_db_install_pkg(struct apk_database *db,
		       struct apk_package *oldpkg,
		       struct apk_package *newpkg,
		       apk_progress_cb cb, void *cb_ctx)
{
	int r;

	if (fchdir(db->root_fd) < 0)
		return errno;

	/* Just purging? */
	if (oldpkg != NULL && newpkg == NULL) {
		r = apk_pkg_run_script(oldpkg, db->root_fd,
				       APK_SCRIPT_PRE_DEINSTALL);
		if (r != 0)
			return r;

Timo Teräs's avatar
Timo Teräs committed
		apk_db_purge_pkg(db, oldpkg, NULL);

		r = apk_pkg_run_script(oldpkg, db->root_fd,
				       APK_SCRIPT_POST_DEINSTALL);
		return r;
	}

	/* Install the new stuff */
	if (newpkg->installed_size != 0) {
		r = apk_db_unpack_pkg(db, newpkg, (oldpkg != NULL), cb, cb_ctx);
		if (r != 0)
			return r;
	}
	apk_pkg_set_state(db, newpkg, APK_PKG_INSTALLED);
Timo Teräs's avatar
Timo Teräs committed
		apk_db_purge_pkg(db, oldpkg, NULL);
	r = apk_pkg_run_script(newpkg, db->root_fd,
			       (oldpkg == NULL) ?
			       APK_SCRIPT_POST_INSTALL : APK_SCRIPT_POST_UPGRADE);
		apk_error("%s-%s: Failed to execute post-install/upgrade script",
			  newpkg->name->name, newpkg->version);