diff --git a/src/apk_database.h b/src/apk_database.h index f2b5ca7..42e214a 100644 --- a/src/apk_database.h +++ b/src/apk_database.h @@ -38,6 +38,7 @@ struct apk_db_file { #define APK_DBDIRF_PROTECTED 0x0001 #define APK_DBDIRF_SYMLINKS_ONLY 0x0002 +#define APK_DBDIRF_MODIFIED 0x0100 struct apk_db_dir { apk_hash_node hash_node; @@ -111,6 +112,7 @@ struct apk_database { struct { struct list_head packages; + struct list_head triggers; struct apk_hash dirs; struct apk_hash files; struct { diff --git a/src/apk_package.h b/src/apk_package.h index d759211..6bca03d 100644 --- a/src/apk_package.h +++ b/src/apk_package.h @@ -20,12 +20,14 @@ struct apk_database; struct apk_name; #define APK_SCRIPT_INVALID -1 -#define APK_SCRIPT_PRE_INSTALL 1 -#define APK_SCRIPT_POST_INSTALL 2 -#define APK_SCRIPT_PRE_DEINSTALL 3 -#define APK_SCRIPT_POST_DEINSTALL 4 -#define APK_SCRIPT_PRE_UPGRADE 5 -#define APK_SCRIPT_POST_UPGRADE 6 +#define APK_SCRIPT_PRE_INSTALL 0 +#define APK_SCRIPT_POST_INSTALL 1 +#define APK_SCRIPT_PRE_DEINSTALL 2 +#define APK_SCRIPT_POST_DEINSTALL 3 +#define APK_SCRIPT_PRE_UPGRADE 4 +#define APK_SCRIPT_POST_UPGRADE 5 +#define APK_SCRIPT_TRIGGER 6 +#define APK_SCRIPT_MAX 7 #define APK_PKG_NOT_INSTALLED 0 #define APK_PKG_INSTALLED 1 @@ -58,13 +60,6 @@ struct apk_sign_ctx { } signature; }; -struct apk_script { - struct hlist_node script_list; - unsigned int type; - unsigned int size; - char script[]; -}; - #define APK_DEPMASK_REQUIRE (APK_VERSION_EQUAL|APK_VERSION_LESS|\ APK_VERSION_GREATER) #define APK_DEPMASK_CONFLICT (0) @@ -76,9 +71,17 @@ struct apk_dependency { }; APK_ARRAY(apk_dependency_array, struct apk_dependency); +struct apk_installed_package { + struct apk_package *pkg; + struct list_head installed_pkgs_list; + struct list_head trigger_pkgs_list; + struct hlist_head owned_dirs; + apk_blob_t script[APK_SCRIPT_MAX]; + struct apk_string_array *triggers; +}; + struct apk_package { apk_hash_node hash_node; - unsigned repos; struct apk_name *name; char *version; @@ -87,11 +90,7 @@ struct apk_package { size_t installed_size, size; char *filename; struct apk_checksum csum; - - /* for installed packages only */ - struct list_head installed_pkgs_list; - struct hlist_head owned_dirs; - struct hlist_head scripts; + struct apk_installed_package *ipkg; }; APK_ARRAY(apk_package_array, struct apk_package *); @@ -134,12 +133,15 @@ int apk_pkg_parse_name(apk_blob_t apkname, apk_blob_t *name, apk_blob_t *version int apk_pkg_add_info(struct apk_database *db, struct apk_package *pkg, char field, apk_blob_t value); -int apk_pkg_get_state(struct apk_package *pkg); -void apk_pkg_set_state(struct apk_database *db, struct apk_package *pkg, int state); -int apk_pkg_add_script(struct apk_package *pkg, struct apk_istream *is, - unsigned int type, unsigned int size); -int apk_pkg_run_script(struct apk_package *pkg, int root_fd, - unsigned int type); + +struct apk_installed_package *apk_pkg_install(struct apk_database *db, struct apk_package *pkg); +void apk_pkg_uninstall(struct apk_database *db, struct apk_package *pkg); + +int apk_ipkg_add_script(struct apk_installed_package *ipkg, + struct apk_istream *is, + unsigned int type, unsigned int size); +int apk_ipkg_run_script(struct apk_installed_package *ipkg, int root_fd, + unsigned int type, char **argv); struct apk_package *apk_pkg_parse_index_entry(struct apk_database *db, apk_blob_t entry); int apk_pkg_write_index_entry(struct apk_package *pkg, struct apk_ostream *os); diff --git a/src/audit.c b/src/audit.c index df6dbdc..9867227 100644 --- a/src/audit.c +++ b/src/audit.c @@ -106,6 +106,7 @@ static int audit_backup(struct apk_database *db) static int audit_system(struct apk_database *db) { + struct apk_installed_package *ipkg; struct apk_package *pkg; struct apk_db_dir_instance *diri; struct apk_db_file *file; @@ -113,8 +114,9 @@ static int audit_system(struct apk_database *db) char name[PATH_MAX]; int done; - list_for_each_entry(pkg, &db->installed.packages, installed_pkgs_list) { - hlist_for_each_entry(diri, dn, &pkg->owned_dirs, pkg_dirs_list) { + list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { + pkg = ipkg->pkg; + hlist_for_each_entry(diri, dn, &ipkg->owned_dirs, pkg_dirs_list) { if (diri->dir->flags & APK_DBDIRF_PROTECTED) continue; diff --git a/src/database.c b/src/database.c index 7b0900c..79e9cb3 100644 --- a/src/database.c +++ b/src/database.c @@ -35,9 +35,12 @@ static const char * const apk_linked_cache_dir = "etc/apk/cache"; struct install_ctx { struct apk_database *db; struct apk_package *pkg; + struct apk_installed_package *ipkg; int script; + char **script_args; int script_pending : 1; + struct apk_db_dir_instance *diri; struct apk_checksum data_csum; struct apk_sign_ctx sctx; @@ -471,6 +474,7 @@ int apk_cache_download(struct apk_database *db, const char *url, int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo) { struct apk_package *pkg = NULL; + struct apk_installed_package *ipkg = NULL; struct apk_db_dir_instance *diri = NULL; struct apk_db_file *file = NULL; struct hlist_node **diri_node = NULL; @@ -485,14 +489,13 @@ int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo) if (repo >= 0) pkg->repos |= BIT(repo); - else if (repo == -1) - apk_pkg_set_state(db, pkg, APK_PKG_INSTALLED); - if (apk_db_pkg_add(db, pkg) != pkg && repo == -1) { + if (apk_db_pkg_add(db, pkg) == NULL) { apk_error("Installed database load failed"); return -1; } pkg = NULL; + ipkg = NULL; continue; } @@ -505,7 +508,7 @@ int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo) if (pkg == NULL) { pkg = apk_pkg_new(); diri = NULL; - diri_node = hlist_tail_ptr(&pkg->owned_dirs); + diri_node = NULL; file_diri_node = NULL; } @@ -518,6 +521,12 @@ int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo) return -1; } + /* Create the installation entry */ + if (ipkg == NULL) { + ipkg = apk_pkg_install(db, pkg); + diri_node = hlist_tail_ptr(&ipkg->owned_dirs); + } + /* Check FDB special entries */ switch (field) { case 'F': @@ -568,6 +577,7 @@ int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo) static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os) { + struct apk_installed_package *ipkg; struct apk_package *pkg; struct apk_db_dir_instance *diri; struct apk_db_file *file; @@ -576,12 +586,13 @@ static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os) apk_blob_t bbuf = APK_BLOB_BUF(buf); int r; - list_for_each_entry(pkg, &db->installed.packages, installed_pkgs_list) { + list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { + pkg = ipkg->pkg; r = apk_pkg_write_index_entry(pkg, os); if (r < 0) return r; - hlist_for_each_entry(diri, c1, &pkg->owned_dirs, pkg_dirs_list) { + hlist_for_each_entry(diri, c1, &ipkg->owned_dirs, pkg_dirs_list) { apk_blob_push_blob(&bbuf, APK_BLOB_STR("F:")); apk_blob_push_blob(&bbuf, APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen)); apk_blob_push_blob(&bbuf, APK_BLOB_STR("\nM:")); @@ -617,19 +628,23 @@ static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os) static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os) { + struct apk_installed_package *ipkg; struct apk_package *pkg; - struct apk_script *script; - struct hlist_node *c2; struct apk_file_info fi; char filename[256]; apk_blob_t bfn; - int r; + int r, i; + + list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { + pkg = ipkg->pkg; + + for (i = 0; i < APK_SCRIPT_MAX; i++) { + if (ipkg->script[i].ptr == NULL) + continue; - list_for_each_entry(pkg, &db->installed.packages, installed_pkgs_list) { - hlist_for_each_entry(script, c2, &pkg->scripts, script_list) { fi = (struct apk_file_info) { .name = filename, - .size = script->size, + .size = ipkg->script[i].len, .mode = 0755 | S_IFREG, }; /* The scripts db expects file names in format: @@ -641,10 +656,10 @@ static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os apk_blob_push_blob(&bfn, APK_BLOB_STR(".")); apk_blob_push_csum(&bfn, &pkg->csum); apk_blob_push_blob(&bfn, APK_BLOB_STR(".")); - apk_blob_push_blob(&bfn, APK_BLOB_STR(apk_script_types[script->type])); + apk_blob_push_blob(&bfn, APK_BLOB_STR(apk_script_types[i])); apk_blob_push_blob(&bfn, APK_BLOB_PTR_LEN("", 1)); - r = apk_tar_write_entry(os, &fi, script->script); + r = apk_tar_write_entry(os, &fi, ipkg->script[i].ptr); if (r < 0) return r; } @@ -668,8 +683,8 @@ static int apk_db_scriptdb_read_v1(struct apk_database *db, struct apk_istream * csum.type = APK_CHECKSUM_MD5; pkg = apk_db_get_pkg(db, &csum); - if (pkg != NULL) - apk_pkg_add_script(pkg, is, hdr.type, hdr.size); + if (pkg != NULL && pkg->ipkg != NULL) + apk_ipkg_add_script(pkg->ipkg, is, hdr.type, hdr.size); else apk_istream_skip(is, hdr.size); } @@ -711,8 +726,8 @@ static int apk_read_script_archive_entry(void *ctx, /* Attach script */ pkg = apk_db_get_pkg(db, &csum); - if (pkg != NULL) - apk_pkg_add_script(pkg, is, type, ae->size); + if (pkg != NULL && pkg->ipkg != NULL) + apk_ipkg_add_script(pkg->ipkg, is, type, ae->size); return 0; } @@ -805,7 +820,7 @@ static int write_index_entry(apk_hash_item item, void *ctx) static int apk_db_index_write_nr_cache(struct apk_database *db) { struct index_write_ctx ctx = { NULL, 0, TRUE }; - struct apk_package *pkg; + struct apk_installed_package *ipkg; struct apk_ostream *os; int r; @@ -822,10 +837,10 @@ static int apk_db_index_write_nr_cache(struct apk_database *db) return -1; ctx.os = os; - list_for_each_entry(pkg, &db->installed.packages, installed_pkgs_list) { - if (pkg->repos != 0) + list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { + if (ipkg->pkg->repos != 0) continue; - r = write_index_entry(pkg, &ctx); + r = write_index_entry(ipkg->pkg, &ctx); if (r != 0) return r; } @@ -1074,13 +1089,13 @@ int apk_db_write_config(struct apk_database *db) void apk_db_close(struct apk_database *db) { - struct apk_package *pkg; + struct apk_installed_package *ipkg; 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) { + list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { + hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, pkg_dirs_list) { apk_db_diri_free(db, diri); } } @@ -1384,7 +1399,8 @@ static int apk_db_run_pending_script(struct install_ctx *ctx) return 0; ctx->script_pending = FALSE; - r = apk_pkg_run_script(ctx->pkg, ctx->db->root_fd, ctx->script); + r = apk_ipkg_run_script(ctx->ipkg, ctx->db->root_fd, ctx->script, + ctx->script_args); if (r != 0) apk_error("%s-%s: Failed to execute " "pre-install/upgrade script", @@ -1392,7 +1408,7 @@ static int apk_db_run_pending_script(struct install_ctx *ctx) return r; } -static struct apk_db_dir_instance *find_diri(struct apk_package *pkg, +static struct apk_db_dir_instance *find_diri(struct apk_installed_package *ipkg, apk_blob_t dirname, struct apk_db_dir_instance *curdiri, struct hlist_node ***tail) @@ -1406,7 +1422,7 @@ static struct apk_db_dir_instance *find_diri(struct apk_package *pkg, dirname) == 0) return curdiri; - hlist_for_each_entry(diri, n, &pkg->owned_dirs, pkg_dirs_list) { + hlist_for_each_entry(diri, n, &ipkg->owned_dirs, pkg_dirs_list) { if (apk_blob_compare(APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen), dirname) == 0) { if (tail != NULL) @@ -1428,9 +1444,23 @@ static int parse_replaces(void *_ctx, apk_blob_t blob) return 0; } +static int parse_triggers(void *_ctx, apk_blob_t blob) +{ + struct install_ctx *ctx = (struct install_ctx *) _ctx; + struct apk_installed_package *ipkg = ctx->ipkg; + + if (blob.len == 0) + return 0; + + *apk_string_array_add(&ipkg->triggers) = apk_blob_cstr(blob); + return 0; +} + static int read_info_line(void *_ctx, apk_blob_t line) { struct install_ctx *ctx = (struct install_ctx *) _ctx; + struct apk_installed_package *ipkg = ctx->ipkg; + struct apk_database *db = ctx->db; apk_blob_t l, r; if (line.ptr == NULL || line.len < 1 || line.ptr[0] == '#') @@ -1441,10 +1471,18 @@ static int read_info_line(void *_ctx, apk_blob_t line) if (apk_blob_compare(APK_BLOB_STR("replaces"), l) == 0) { apk_blob_for_each_segment(r, " ", parse_replaces, ctx); - return 0; + } else if (apk_blob_compare(APK_BLOB_STR("triggers"), l) == 0) { + if (ipkg->triggers) { + free(ipkg->triggers); + ipkg->triggers = NULL; + } + if (!list_hashed(&ipkg->trigger_pkgs_list)) + list_add(&ipkg->trigger_pkgs_list, + &db->installed.triggers); + apk_blob_for_each_segment(r, " ", parse_triggers, ctx); + } else { + apk_sign_ctx_parse_pkginfo_line(&ctx->sctx, line); } - - apk_sign_ctx_parse_pkginfo_line(&ctx->sctx, line); return 0; } @@ -1455,6 +1493,7 @@ static int apk_db_install_archive_entry(void *_ctx, struct install_ctx *ctx = (struct install_ctx *) _ctx; struct apk_database *db = ctx->db; struct apk_package *pkg = ctx->pkg, *opkg; + struct apk_installed_package *ipkg = pkg->ipkg; apk_blob_t name = APK_BLOB_STR(ae->name), bdir, bfile; struct apk_db_dir_instance *diri = ctx->diri; struct apk_db_file *file; @@ -1493,7 +1532,7 @@ static int apk_db_install_archive_entry(void *_ctx, /* Handle script */ if (type != APK_SCRIPT_INVALID) { - apk_pkg_add_script(pkg, is, type, ae->size); + apk_ipkg_add_script(ipkg, is, type, ae->size); if (type == ctx->script) ctx->script_pending = TRUE; return apk_db_run_pending_script(ctx); @@ -1520,7 +1559,7 @@ static int apk_db_install_archive_entry(void *_ctx, return 0; /* Make sure the file is part of the cached directory tree */ - diri = find_diri(pkg, bdir, diri, &ctx->file_diri_node); + diri = find_diri(ipkg, bdir, diri, &ctx->file_diri_node); if (diri == NULL) { apk_error("%s: File '%*s' entry without directory entry.\n", pkg->name->name, name.len, name.ptr); @@ -1579,7 +1618,7 @@ static int apk_db_install_archive_entry(void *_ctx, '/', &bdir, &bfile)) break; - ldiri = find_diri(pkg, bdir, diri, NULL); + ldiri = find_diri(ipkg, bdir, diri, NULL); if (ldiri == NULL) break; @@ -1604,7 +1643,7 @@ static int apk_db_install_archive_entry(void *_ctx, name.len--; if (ctx->diri_node == NULL) - ctx->diri_node = hlist_tail_ptr(&pkg->owned_dirs); + ctx->diri_node = hlist_tail_ptr(&ipkg->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); @@ -1617,7 +1656,8 @@ static int apk_db_install_archive_entry(void *_ctx, return r; } -static void apk_db_purge_pkg(struct apk_database *db, struct apk_package *pkg, +static void apk_db_purge_pkg(struct apk_database *db, + struct apk_installed_package *ipkg, const char *exten) { struct apk_db_dir_instance *diri; @@ -1628,7 +1668,10 @@ static void apk_db_purge_pkg(struct apk_database *db, struct apk_package *pkg, 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(diri, dc, dn, &ipkg->owned_dirs, pkg_dirs_list) { + if (exten == NULL) + diri->dir->flags |= APK_DBDIRF_MODIFIED; + hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) { snprintf(name, sizeof(name), "%s/%s%s", diri->dir->name, file->name, exten ?: ""); @@ -1653,15 +1696,14 @@ static void apk_db_purge_pkg(struct apk_database *db, struct apk_package *pkg, } } apk_db_diri_rmdir(db, diri); - __hlist_del(dc, &pkg->owned_dirs.first); + __hlist_del(dc, &ipkg->owned_dirs.first); apk_db_diri_free(db, diri); } - apk_pkg_set_state(db, pkg, APK_PKG_NOT_INSTALLED); } static void apk_db_migrate_files(struct apk_database *db, - struct apk_package *pkg) + struct apk_installed_package *ipkg) { struct apk_db_dir_instance *diri; struct apk_db_dir *dir; @@ -1673,8 +1715,9 @@ static void apk_db_migrate_files(struct apk_database *db, char name[PATH_MAX], tmpname[PATH_MAX]; int cstype, r; - hlist_for_each_entry_safe(diri, dc, dn, &pkg->owned_dirs, pkg_dirs_list) { + hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, pkg_dirs_list) { dir = diri->dir; + dir->flags |= APK_DBDIRF_MODIFIED; hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) { snprintf(name, sizeof(name), "%s/%s", @@ -1741,45 +1784,47 @@ static void apk_db_migrate_files(struct apk_database *db, } static int apk_db_unpack_pkg(struct apk_database *db, - struct apk_package *newpkg, + struct apk_installed_package *ipkg, int upgrade, int reinstall, - apk_progress_cb cb, void *cb_ctx) + apk_progress_cb cb, void *cb_ctx, + char **script_args) { struct install_ctx ctx; struct apk_bstream *bs = NULL; struct apk_istream *tar; + struct apk_package *pkg = ipkg->pkg; char file[PATH_MAX]; int r, need_copy = FALSE; - if (newpkg->filename == NULL) { + if (pkg->filename == NULL) { struct apk_repository *repo; - repo = apk_db_select_repo(db, newpkg); + repo = apk_db_select_repo(db, pkg); if (repo == NULL) { apk_error("%s-%s: package is not currently available", - newpkg->name->name, newpkg->version); + pkg->name->name, pkg->version); return -1; } if (apk_db_cache_active(db) && apk_repo_is_remote(repo)) { - apk_pkg_format_cache(newpkg, APK_BLOB_BUF(file)); + apk_pkg_format_cache(pkg, APK_BLOB_BUF(file)); bs = apk_bstream_from_file(db->cache_fd, file); } if (bs == NULL) { - apk_pkg_format_plain(newpkg, APK_BLOB_BUF(file)); + apk_pkg_format_plain(pkg, APK_BLOB_BUF(file)); bs = apk_repo_file_open(repo, file); if (apk_repo_is_remote(repo)) need_copy = TRUE; } } else { - bs = apk_bstream_from_file(AT_FDCWD, newpkg->filename); + bs = apk_bstream_from_file(AT_FDCWD, pkg->filename); need_copy = TRUE; } if (!apk_db_cache_active(db)) need_copy = FALSE; if (need_copy) { - apk_pkg_format_cache(newpkg, APK_BLOB_BUF(file)); + apk_pkg_format_cache(pkg, APK_BLOB_BUF(file)); bs = apk_bstream_tee(bs, db->cachetmp_fd, file); } @@ -1790,13 +1835,15 @@ static int apk_db_unpack_pkg(struct apk_database *db, ctx = (struct install_ctx) { .db = db, - .pkg = newpkg, + .pkg = pkg, + .ipkg = ipkg, .script = upgrade ? APK_SCRIPT_PRE_UPGRADE : APK_SCRIPT_PRE_INSTALL, + .script_args = script_args, .cb = cb, .cb_ctx = cb_ctx, }; - apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY_IDENTITY, &newpkg->csum, db->keys_fd); + apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY_IDENTITY, &pkg->csum, db->keys_fd); tar = apk_bstream_gunzip_mpart(bs, apk_sign_ctx_mpart_cb, &ctx.sctx); r = apk_tar_parse(tar, apk_db_install_archive_entry, &ctx, TRUE); apk_sign_ctx_free(&ctx.sctx); @@ -1813,7 +1860,7 @@ static int apk_db_unpack_pkg(struct apk_database *db, if (r != 0) { apk_error("%s-%s: %s", - newpkg->name->name, newpkg->version, + pkg->name->name, pkg->version, apk_error_str(r)); goto err; } @@ -1821,12 +1868,12 @@ static int apk_db_unpack_pkg(struct apk_database *db, if (r != 0) goto err; - apk_db_migrate_files(db, newpkg); + apk_db_migrate_files(db, ipkg); return 0; err: if (!reinstall) - apk_db_purge_pkg(db, newpkg, ".apk-new"); + apk_db_purge_pkg(db, ipkg, ".apk-new"); return r; } @@ -1835,37 +1882,59 @@ int apk_db_install_pkg(struct apk_database *db, struct apk_package *newpkg, apk_progress_cb cb, void *cb_ctx) { + char *script_args[] = { NULL, NULL, NULL }; + struct apk_installed_package *ipkg; int r; + /* Upgrade script gets two args: */ + if (oldpkg != NULL && newpkg != NULL) { + script_args[0] = newpkg->version; + script_args[1] = oldpkg->version; + } else { + script_args[0] = oldpkg ? oldpkg->version : newpkg->version; + } + /* Just purging? */ if (oldpkg != NULL && newpkg == NULL) { - r = apk_pkg_run_script(oldpkg, db->root_fd, - APK_SCRIPT_PRE_DEINSTALL); + ipkg = oldpkg->ipkg; + + if (ipkg == NULL) + return 0; + + r = apk_ipkg_run_script(ipkg, db->root_fd, + APK_SCRIPT_PRE_DEINSTALL, script_args); if (r != 0) return r; - apk_db_purge_pkg(db, oldpkg, NULL); + apk_db_purge_pkg(db, ipkg, NULL); + r = apk_ipkg_run_script(ipkg, db->root_fd, + APK_SCRIPT_POST_DEINSTALL, script_args); + apk_pkg_uninstall(db, oldpkg); - r = apk_pkg_run_script(oldpkg, db->root_fd, - APK_SCRIPT_POST_DEINSTALL); return r; } /* Install the new stuff */ + ipkg = apk_pkg_install(db, newpkg); if (newpkg->installed_size != 0) { - r = apk_db_unpack_pkg(db, newpkg, (oldpkg != NULL), - (oldpkg == newpkg), cb, cb_ctx); - if (r != 0) + r = apk_db_unpack_pkg(db, ipkg, (oldpkg != NULL), + (oldpkg == newpkg), cb, cb_ctx, + script_args); + if (r != 0) { + apk_pkg_uninstall(db, newpkg); return r; + } } - apk_pkg_set_state(db, newpkg, APK_PKG_INSTALLED); - if (oldpkg != NULL && oldpkg != newpkg) - apk_db_purge_pkg(db, oldpkg, NULL); + if (oldpkg != NULL && oldpkg != newpkg && oldpkg->ipkg != NULL) { + apk_db_purge_pkg(db, oldpkg->ipkg, NULL); + apk_pkg_uninstall(db, oldpkg); + } - r = apk_pkg_run_script(newpkg, db->root_fd, - (oldpkg == NULL) ? - APK_SCRIPT_POST_INSTALL : APK_SCRIPT_POST_UPGRADE); + r = apk_ipkg_run_script(ipkg, db->root_fd, + (oldpkg == NULL) ? + APK_SCRIPT_POST_INSTALL : APK_SCRIPT_POST_UPGRADE, + script_args); if (r != 0) { apk_error("%s-%s: Failed to execute post-install/upgrade script", newpkg->name->name, newpkg->version); diff --git a/src/fix.c b/src/fix.c index e54631d..756db6a 100644 --- a/src/fix.c +++ b/src/fix.c @@ -53,7 +53,7 @@ static int fix_main(void *pctx, struct apk_database *db, int argc, char **argv) goto err; for (j = 0; j < name->pkgs->num; j++) { - if (apk_pkg_get_state(name->pkgs->item[j]) == APK_PKG_INSTALLED) + if (name->pkgs->item[j]->ipkg != NULL) break; } if (j >= name->pkgs->num) { diff --git a/src/info.c b/src/info.c index c3fa275..8d89bd3 100644 --- a/src/info.c +++ b/src/info.c @@ -73,10 +73,10 @@ static void verbose_print_pkg(struct apk_package *pkg, int minimal_verbosity) static int info_list(struct info_ctx *ctx, struct apk_database *db, int argc, char **argv) { - struct apk_package *pkg; + struct apk_installed_package *ipkg; - list_for_each_entry(pkg, &db->installed.packages, installed_pkgs_list) - verbose_print_pkg(pkg, 1); + list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) + verbose_print_pkg(ipkg->pkg, 1); return 0; } @@ -99,7 +99,7 @@ static int info_exists(struct info_ctx *ctx, struct apk_database *db, for (j = 0; j < name->pkgs->num; j++) { pkg = name->pkgs->item[j]; - if (apk_pkg_get_state(pkg) == APK_PKG_INSTALLED) + if (pkg->ipkg != NULL) break; } if (j >= name->pkgs->num) @@ -178,7 +178,7 @@ static int info_package(struct info_ctx *ctx, struct apk_database *db, } for (j = 0; j < name->pkgs->num; j++) { struct apk_package *pkg = name->pkgs->item[j]; - if (apk_pkg_get_state(pkg) == APK_PKG_INSTALLED) + if (pkg->ipkg != NULL) info_subaction(ctx, pkg); } } @@ -187,14 +187,18 @@ static int info_package(struct info_ctx *ctx, struct apk_database *db, static void info_print_contents(struct apk_package *pkg) { + struct apk_installed_package *ipkg = pkg->ipkg; struct apk_db_dir_instance *diri; struct apk_db_file *file; struct hlist_node *dc, *dn, *fc, *fn; + if (ipkg == NULL) + return; + if (apk_verbosity == 1) printf("%s-%s contains:\n", pkg->name->name, pkg->version); - hlist_for_each_entry_safe(diri, dc, dn, &pkg->owned_dirs, + hlist_for_each_entry_safe(diri, dc, dn, &ipkg->owned_dirs, pkg_dirs_list) { hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files, diri_files_list) { @@ -241,8 +245,7 @@ static void info_print_required_by(struct apk_package *pkg) for (j = 0; j < name0->pkgs->num; j++) { struct apk_package *pkg0 = name0->pkgs->item[j]; - if (apk_pkg_get_state(pkg0) != APK_PKG_INSTALLED || - pkg0->depends == NULL) + if (pkg0->ipkg == NULL || pkg0->depends == NULL) continue; for (k = 0; k < pkg0->depends->num; k++) { if (pkg0->depends->item[k].name != pkg->name) diff --git a/src/package.c b/src/package.c index 33d6519..24faaaf 100644 --- a/src/package.c +++ b/src/package.c @@ -53,13 +53,52 @@ void apk_pkg_format_cache(struct apk_package *pkg, apk_blob_t to) struct apk_package *apk_pkg_new(void) { - struct apk_package *pkg; + return calloc(1, sizeof(struct apk_package)); +} - pkg = calloc(1, sizeof(struct apk_package)); - if (pkg != NULL) - list_init(&pkg->installed_pkgs_list); +struct apk_installed_package *apk_pkg_install(struct apk_database *db, + struct apk_package *pkg) +{ + struct apk_installed_package *ipkg; - return pkg; + if (pkg->ipkg != NULL) + return pkg->ipkg; + + pkg->ipkg = ipkg = calloc(1, sizeof(struct apk_installed_package)); + ipkg->pkg = pkg; + list_init(&ipkg->installed_pkgs_list); + + db->installed.stats.packages++; + list_add_tail(&ipkg->installed_pkgs_list, &db->installed.packages); + + return ipkg; +} + +void apk_pkg_uninstall(struct apk_database *db, struct apk_package *pkg) +{ + struct apk_installed_package *ipkg = pkg->ipkg; + int i; + + if (ipkg == NULL) + return; + + if (db != NULL) + db->installed.stats.packages--; + + list_del(&ipkg->installed_pkgs_list); + + if (ipkg->triggers) { + list_del(&ipkg->trigger_pkgs_list); + for (i = 0; i < ipkg->triggers->num; i++) + free(ipkg->triggers->item[i]); + free(ipkg->triggers); + } + + for (i = 0; i < APK_SCRIPT_MAX; i++) + if (ipkg->script[i].ptr != NULL) + free(ipkg->script[i].ptr); + free(ipkg); + pkg->ipkg = NULL; } int apk_pkg_parse_name(apk_blob_t apkname, @@ -293,6 +332,7 @@ const char *apk_script_types[] = { [APK_SCRIPT_POST_DEINSTALL] = "post-deinstall", [APK_SCRIPT_PRE_UPGRADE] = "pre-upgrade", [APK_SCRIPT_POST_UPGRADE] = "post-upgrade", + [APK_SCRIPT_TRIGGER] = "trigger", }; int apk_script_type(const char *name) @@ -763,15 +803,10 @@ err: void apk_pkg_free(struct apk_package *pkg) { - struct apk_script *script; - struct hlist_node *c, *n; - if (pkg == NULL) return; - hlist_for_each_entry_safe(script, c, n, &pkg->scripts, script_list) - free(script); - + apk_pkg_uninstall(NULL, pkg); if (pkg->depends) free(pkg->depends); if (pkg->version) @@ -785,106 +820,84 @@ void apk_pkg_free(struct apk_package *pkg) free(pkg); } -int apk_pkg_get_state(struct apk_package *pkg) +int apk_ipkg_add_script(struct apk_installed_package *ipkg, + struct apk_istream *is, + unsigned int type, unsigned int size) { - if (list_hashed(&pkg->installed_pkgs_list)) - return APK_PKG_INSTALLED; - return APK_PKG_NOT_INSTALLED; -} - -void apk_pkg_set_state(struct apk_database *db, struct apk_package *pkg, int state) -{ - switch (state) { - case APK_PKG_INSTALLED: - if (!list_hashed(&pkg->installed_pkgs_list)) { - db->installed.stats.packages++; - list_add_tail(&pkg->installed_pkgs_list, - &db->installed.packages); - } - break; - case APK_PKG_NOT_INSTALLED: - if (list_hashed(&pkg->installed_pkgs_list)) { - db->installed.stats.packages--; - list_del(&pkg->installed_pkgs_list); - } - break; - } -} - -int apk_pkg_add_script(struct apk_package *pkg, struct apk_istream *is, - unsigned int type, unsigned int size) -{ - struct apk_script *script; + void *ptr; int r; - script = malloc(sizeof(struct apk_script) + size); - script->type = type; - script->size = size; - r = is->read(is, script->script, size); + if (type >= APK_SCRIPT_MAX) + return -1; + + ptr = malloc(size); + r = is->read(is, ptr, size); if (r < 0) { - free(script); + free(ptr); return r; } - hlist_add_head(&script->script_list, &pkg->scripts); - return r; + if (ipkg->script[type].ptr) + free(ipkg->script[type].ptr); + ipkg->script[type].ptr = ptr; + ipkg->script[type].len = size; + return 0; } -int apk_pkg_run_script(struct apk_package *pkg, int root_fd, - unsigned int type) +int apk_ipkg_run_script(struct apk_installed_package *ipkg, int root_fd, + unsigned int type, char **argv) { - static const char * const environment[] = { + static char * const environment[] = { "PATH=/usr/sbin:/usr/bin:/sbin:/bin", NULL }; - struct apk_script *script; - struct hlist_node *c; + struct apk_package *pkg = ipkg->pkg; + char fn[PATH_MAX]; int fd, status; pid_t pid; - char fn[PATH_MAX]; - hlist_for_each_entry(script, c, &pkg->scripts, script_list) { - if (script->type != type) - continue; - - /* Avoid /tmp as it can be mounted noexec */ - snprintf(fn, sizeof(fn), "var/cache/misc/%s-%s.%s", - pkg->name->name, pkg->version, - apk_script_types[type]); - - fd = openat(root_fd, fn, O_CREAT|O_RDWR|O_TRUNC, 0755); - if (fd < 0) { - mkdirat(root_fd, "var/cache/misc", 0755); - fd = openat(root_fd, fn, O_CREAT|O_RDWR|O_TRUNC, 0755); - if (fd < 0) - return -errno; - } - write(fd, script->script, script->size); - close(fd); - - apk_message("Executing %s", &fn[15]); - - pid = fork(); - if (pid == -1) - return -1; - if (pid == 0) { - fchdir(root_fd); - if (chroot(".") < 0) { - apk_error("chroot: %s", strerror(errno)); - } else { - execle(fn, apk_script_types[type], - pkg->version, "", NULL, environment); - } - exit(1); - } - waitpid(pid, &status, 0); - unlinkat(root_fd, fn, 0); - if (WIFEXITED(status)) - return WEXITSTATUS(status); + if (type >= APK_SCRIPT_MAX) return -1; - } - return 0; + if (ipkg->script[type].ptr == NULL) + return 0; + + argv[0] = (char *) apk_script_types[type]; + + /* Avoid /tmp as it can be mounted noexec */ + snprintf(fn, sizeof(fn), "var/cache/misc/%s-%s.%s", + pkg->name->name, pkg->version, + apk_script_types[type]); + + fd = openat(root_fd, fn, O_CREAT|O_RDWR|O_TRUNC, 0755); + if (fd < 0) { + mkdirat(root_fd, "var/cache/misc", 0755); + fd = openat(root_fd, fn, O_CREAT|O_RDWR|O_TRUNC, 0755); + if (fd < 0) + return -errno; + } + write(fd, ipkg->script[type].ptr, ipkg->script[type].len); + close(fd); + + apk_message("Executing %s", &fn[15]); + + pid = fork(); + if (pid == -1) + return -1; + if (pid == 0) { + fchdir(root_fd); + if (chroot(".") < 0) { + apk_error("chroot: %s", strerror(errno)); + } else { + execve(fn, argv, environment); + } + exit(1); + } + waitpid(pid, &status, 0); + unlinkat(root_fd, fn, 0); + if (WIFEXITED(status)) + return WEXITSTATUS(status); + return -1; } static int parse_index_line(void *ctx, apk_blob_t line) diff --git a/src/state.c b/src/state.c index 6d6c569..a33a13e 100644 --- a/src/state.c +++ b/src/state.c @@ -296,7 +296,7 @@ int apk_state_lock_dependency(struct apk_state *state, for (i = 0; i < c->num; i++) { struct apk_package *pkg = c->pkgs[i]; - if (apk_pkg_get_state(c->pkgs[i]) == APK_PKG_INSTALLED) + if (c->pkgs[i]->ipkg != NULL) installed = pkg; else if (pkg->filename == NULL && apk_db_select_repo(state->db, pkg) == NULL) @@ -422,8 +422,7 @@ static int for_each_broken_reverse_depency(struct apk_state *state, ns_to_choices(state->name[name0->id]); for (j = 0; j < ns->num; j++) { - if (apk_pkg_get_state(ns->pkgs[j]) - != APK_PKG_INSTALLED) + if (ns->pkgs[j]->ipkg == NULL) continue; r = call_if_dependency_broke(state, ns->pkgs[j], @@ -436,7 +435,7 @@ static int for_each_broken_reverse_depency(struct apk_state *state, for (j = 0; j < name0->pkgs->num; j++) { pkg0 = name0->pkgs->item[j]; - if (apk_pkg_get_state(pkg0) != APK_PKG_INSTALLED) + if (pkg0->ipkg == NULL) continue; r = call_if_dependency_broke(state, @@ -487,8 +486,7 @@ int apk_state_lock_name(struct apk_state *state, struct apk_package *pkg = name->pkgs->item[i]; if (name->pkgs->item[i]->name == name && - apk_pkg_get_state(name->pkgs->item[i]) - == APK_PKG_INSTALLED) + name->pkgs->item[i]->ipkg != NULL) oldpkg = pkg; } } diff --git a/src/ver.c b/src/ver.c index 24754c1..5a8fb9c 100644 --- a/src/ver.c +++ b/src/ver.c @@ -93,7 +93,7 @@ static void ver_print_package_status(struct apk_package *pkg, const char *limit) static int ver_main(void *ctx, struct apk_database *db, int argc, char **argv) { struct ver_ctx *ictx = (struct ver_ctx *) ctx; - struct apk_package *pkg; + struct apk_installed_package *ipkg; struct apk_name *name; int i, j, ret = 0; @@ -105,9 +105,9 @@ static int ver_main(void *ctx, struct apk_database *db, int argc, char **argv) printf("%-42sAvailable:\n", "Installed:"); if (argc == 0) { - list_for_each_entry(pkg, &db->installed.packages, + list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { - ver_print_package_status(pkg, ictx->limchars); + ver_print_package_status(ipkg->pkg, ictx->limchars); } goto ver_exit; } @@ -121,7 +121,7 @@ static int ver_main(void *ctx, struct apk_database *db, int argc, char **argv) } for (j = 0; j < name->pkgs->num; j++) { struct apk_package *pkg = name->pkgs->item[j]; - if (apk_pkg_get_state(pkg) == APK_PKG_INSTALLED) + if (pkg->ipkg != NULL) ver_print_package_status(pkg, ictx->limchars); } }