From 7e18398781b056f858ef60200e24b0f8ab394cfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 20 Jun 2013 13:12:44 +0300 Subject: [PATCH] commit, db: make file conflicts and script errors non-fatal fixes #1482 --- src/apk_package.h | 14 +++-- src/commit.c | 52 ++++++++++------ src/database.c | 149 +++++++++++++++++++++------------------------- src/fix.c | 18 ++++-- src/package.c | 41 ++++++------- test/fix4.test | 2 +- test/fix5.test | 2 +- test/fix6.test | 4 +- 8 files changed, 144 insertions(+), 138 deletions(-) diff --git a/src/apk_package.h b/src/apk_package.h index 2d8a431..f743c3e 100644 --- a/src/apk_package.h +++ b/src/apk_package.h @@ -78,9 +78,6 @@ APK_ARRAY(apk_dependency_array, struct apk_dependency); struct apk_installed_package { struct apk_package *pkg; - unsigned int run_all_triggers : 1; - unsigned int repository_tag : 6; - unsigned short replaces_priority; struct list_head installed_pkgs_list; struct list_head trigger_pkgs_list; struct hlist_head owned_dirs; @@ -88,6 +85,12 @@ struct apk_installed_package { struct apk_string_array *triggers; struct apk_string_array *pending_triggers; struct apk_dependency_array *replaces; + + unsigned short replaces_priority; + unsigned repository_tag : 6; + unsigned run_all_triggers : 1; + unsigned broken_files : 1; + unsigned broken_script : 1; }; #define APK_PKG_UNINSTALLABLE ((char*) -1) @@ -177,9 +180,8 @@ 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, - struct apk_database *db, - unsigned int type, char **argv); +void apk_ipkg_run_script(struct apk_installed_package *ipkg, struct apk_database *db, + 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/commit.c b/src/commit.c index 09e8b28..7beb68a 100644 --- a/src/commit.c +++ b/src/commit.c @@ -48,7 +48,7 @@ static int print_change(struct apk_database *db, struct apk_change *change, } else if (newpkg == oldpkg) { if (change->reinstall) { if (pkg_available(db, newpkg)) - msg = "Re-installing"; + msg = "Reinstalling"; else msg = "[APK unavailable, skipped] Re-installing"; } else if (change->old_repository_tag != change->new_repository_tag) { @@ -161,6 +161,11 @@ static int cmp_new(struct apk_change *change) return change->old_pkg == NULL; } +static int cmp_reinstall(struct apk_change *change) +{ + return change->reinstall; +} + static int cmp_downgrade(struct apk_change *change) { if (change->new_pkg == NULL || change->old_pkg == NULL) @@ -217,7 +222,9 @@ int apk_solver_commit_changeset(struct apk_database *db, { struct progress prog; struct apk_change *change; - int r = 0, size_diff = 0, size_unit; + char buf[32], size_unit; + ssize_t size_diff = 0; + int r, errors = 0; if (apk_db_check_world(db, world) != 0) { apk_error("Not committing changes due to missing repository tags. Use --force to override."); @@ -252,7 +259,9 @@ int apk_solver_commit_changeset(struct apk_database *db, "The following NEW packages will be installed"); dump_packages(changeset, cmp_upgrade, "The following packages will be upgraded"); - printf("After this operation, %d %ciB of %s\n", + dump_packages(changeset, cmp_reinstall, + "The following packages will be reinstalled"); + printf("After this operation, %zd %ciB of %s\n", abs(size_diff), size_unit, (size_diff < 0) ? "disk space will be freed." : @@ -269,25 +278,24 @@ int apk_solver_commit_changeset(struct apk_database *db, } /* Go through changes */ - r = 0; foreach_array_item(change, changeset->changes) { + r = change->old_pkg && + (change->old_pkg->ipkg->broken_files || + change->old_pkg->ipkg->broken_script); if (print_change(db, change, prog.done.changes, prog.total.changes)) { prog.pkg = change->new_pkg; progress_cb(&prog, 0); - if (!(apk_flags & APK_SIMULATE)) { - if (change->old_pkg != change->new_pkg || - (change->reinstall && pkg_available(db, change->new_pkg))) - r = apk_db_install_pkg(db, - change->old_pkg, change->new_pkg, - progress_cb, &prog); - if (r != 0) - break; - if (change->new_pkg) - change->new_pkg->ipkg->repository_tag = change->new_repository_tag; + if (!(apk_flags & APK_SIMULATE) && + ((change->old_pkg != change->new_pkg) || + (change->reinstall && pkg_available(db, change->new_pkg)))) { + r = apk_db_install_pkg(db, change->old_pkg, change->new_pkg, + progress_cb, &prog) != 0; } + if (r == 0 && change->new_pkg && change->new_pkg->ipkg) + change->new_pkg->ipkg->repository_tag = change->new_repository_tag; } - + errors += r; count_change(change, &prog.done); } apk_print_progress(prog.total.bytes + prog.total.packages, @@ -299,21 +307,27 @@ all_done: apk_dependency_array_copy(&db->world, world); apk_db_write_config(db); - if (r == 0 && !db->performing_self_update) { + if (!db->performing_self_update) { + if (errors) + snprintf(buf, sizeof(buf), "%d errors;", errors); + else + strcpy(buf, "OK:"); if (apk_verbosity > 1) { - apk_message("OK: %d packages, %d dirs, %d files, %zu MiB", + apk_message("%s %d packages, %d dirs, %d files, %zu MiB", + buf, db->installed.stats.packages, db->installed.stats.dirs, db->installed.stats.files, db->installed.stats.bytes / (1024 * 1024)); } else { - apk_message("OK: %zu MiB in %d packages", + apk_message("%s %zu MiB in %d packages", + buf, db->installed.stats.bytes / (1024 * 1024), db->installed.stats.packages); } } - return r; + return 0; } enum { diff --git a/src/database.c b/src/database.c index 2360bda..ba13620 100644 --- a/src/database.c +++ b/src/database.c @@ -859,12 +859,20 @@ int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo) case 's': ipkg->repository_tag = apk_db_get_tag_id(db, l); break; - default: - if (r != 0 && !(apk_flags & APK_FORCE)) { - /* Installed db should not have unsupported fields */ - apk_error("This apk-tools is too old to handle installed packages"); - return -1; + case 'f': + for (r = 0; r < l.len; r++) { + switch (l.ptr[r]) { + case 'f': ipkg->broken_files = 1; break; + case 's': ipkg->broken_script = 1; break; + default: + if (!(apk_flags & APK_FORCE)) + goto old_apk_tools; + } } + break; + default: + if (r != 0 && !(apk_flags & APK_FORCE)) + goto old_apk_tools; /* Installed. So mark the package as installable. */ pkg->filename = NULL; continue; @@ -874,8 +882,11 @@ int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo) return -1; } } - return 0; +old_apk_tools: + /* Installed db should not have unsupported fields */ + apk_error("This apk-tools is too old to handle installed packages"); + return -1; } static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os) @@ -919,6 +930,13 @@ static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os) apk_blob_push_uint(&bbuf, diri->gid, 10); apk_blob_push_blob(&bbuf, APK_BLOB_STR(":")); apk_blob_push_uint(&bbuf, diri->mode, 8); + if (ipkg->broken_files || ipkg->broken_script) { + apk_blob_push_blob(&bbuf, APK_BLOB_STR("\nf:")); + if (ipkg->broken_files) + apk_blob_push_blob(&bbuf, APK_BLOB_STR("f")); + if (ipkg->broken_script) + apk_blob_push_blob(&bbuf, APK_BLOB_STR("s")); + } apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n")); hlist_for_each_entry(file, c2, &diri->owned_files, diri_files_list) { @@ -2148,23 +2166,12 @@ static void extract_cb(void *_ctx, size_t bytes_done) ctx->cb(ctx->cb_ctx, min(ctx->installed_size + bytes_done, ctx->pkg->installed_size)); } -static int apk_db_run_pending_script(struct install_ctx *ctx) +static void 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_ipkg_run_script(ctx->ipkg, ctx->db, ctx->script, - ctx->script_args); - if (r != 0) - apk_error("%s-%s: Failed to execute " - "pre-install/upgrade script", - ctx->pkg->name->name, ctx->pkg->version); - return r; + if (ctx->script_pending && ctx->sctx.control_verified) { + ctx->script_pending = FALSE; + apk_ipkg_run_script(ctx->ipkg, ctx->db, ctx->script, ctx->script_args); + } } static int read_info_line(void *_ctx, apk_blob_t line) @@ -2251,11 +2258,10 @@ static int apk_db_install_archive_entry(void *_ctx, apk_ipkg_add_script(ipkg, is, type, ae->size); if (type == ctx->script) ctx->script_pending = TRUE; - return apk_db_run_pending_script(ctx); + apk_db_run_pending_script(ctx); + return 0; } - r = apk_db_run_pending_script(ctx); - if (r != 0) - return r; + apk_db_run_pending_script(ctx); /* Installable entry */ ctx->current_file_size = apk_calc_installed_size(ae->size); @@ -2272,9 +2278,10 @@ static int apk_db_install_archive_entry(void *_ctx, diri = find_diri(ipkg, bdir, diri, &ctx->file_diri_node); if (diri == NULL) { if (!APK_BLOB_IS_NULL(bdir)) { - apk_error("%s: File '%*s' entry without directory entry.\n", - pkg->name->name, name.len, name.ptr); - return -1; + apk_error(PKG_VER_FMT": "BLOB_FMT": no dirent in archive\n", + pkg, BLOB_PRINTF(name)); + ipkg->broken_files = 1; + return 0; } diri = apk_db_install_directory_entry(ctx, bdir); } @@ -2316,15 +2323,13 @@ static int apk_db_install_archive_entry(void *_ctx, break; if (!(apk_flags & APK_FORCE)) { - apk_error("%s: Trying to overwrite %s " - "owned by %s.", - pkg->name->name, ae->name, - opkg->name->name); - return -1; + apk_error(PKG_VER_FMT": trying to overwrite %s owned by "PKG_VER_FMT".", + PKG_VER_PRINTF(pkg), ae->name, PKG_VER_PRINTF(opkg)); + ipkg->broken_files = 1; + return 0; } - apk_warning("%s: Overwriting %s owned by %s.", - pkg->name->name, ae->name, - opkg->name->name); + apk_warning(PKG_VER_FMT": overwriting %s owned by "PKG_VER_FMT".", + PKG_VER_PRINTF(pkg), ae->name, PKG_VER_PRINTF(opkg)); } while (0); } @@ -2521,16 +2526,14 @@ static void apk_db_migrate_files(struct apk_database *db, static int apk_db_unpack_pkg(struct apk_database *db, struct apk_installed_package *ipkg, - int upgrade, int reinstall, - apk_progress_cb cb, void *cb_ctx, + int upgrade, apk_progress_cb cb, void *cb_ctx, char **script_args) { struct install_ctx ctx; - struct apk_bstream *bs = NULL; + struct apk_bstream *bs = NULL, *cache_bs; struct apk_istream *tar; struct apk_repository *repo; struct apk_package *pkg = ipkg->pkg; - const char *action = ""; char file[PATH_MAX]; char tmpcacheitem[128], *cacheitem = &tmpcacheitem[tmpprefix.len]; int r, filefd = AT_FDCWD, need_copy = FALSE; @@ -2538,7 +2541,6 @@ static int apk_db_unpack_pkg(struct apk_database *db, if (pkg->filename == NULL) { repo = apk_db_select_repo(db, pkg); if (repo == NULL) { - action = "unable to select package: "; r = -ENOPKG; goto err_msg; } @@ -2563,12 +2565,12 @@ static int apk_db_unpack_pkg(struct apk_database *db, apk_blob_t b = APK_BLOB_BUF(tmpcacheitem); apk_blob_push_blob(&b, tmpprefix); apk_pkg_format_cache_pkg(b, pkg); - bs = apk_bstream_tee(bs, db->cache_fd, tmpcacheitem, NULL, NULL); - if (bs == NULL) { - action = "unable cache package: "; - r = -errno; - goto err_msg; - } + cache_bs = apk_bstream_tee(bs, db->cache_fd, tmpcacheitem, NULL, NULL); + if (cache_bs != NULL) + bs = cache_bs; + else + apk_warning(PKG_VER_FMT": unable to cache: %s", + PKG_VER_PRINTF(pkg), apk_error_str(errno)); } ctx = (struct install_ctx) { @@ -2598,26 +2600,15 @@ static int apk_db_unpack_pkg(struct apk_database *db, if (r != 0) goto err_msg; - r = apk_db_run_pending_script(&ctx); - if (r != 0) { - action = "unable to run script: "; - goto err_msg; - } - - apk_db_migrate_files(db, ipkg); - + apk_db_run_pending_script(&ctx); return 0; err_msg: - apk_error("%s: %s%s", file, action, apk_error_str(r)); - if (!reinstall) - apk_db_purge_pkg(db, ipkg, ".apk-new"); + apk_error(PKG_VER_FMT": %s", PKG_VER_PRINTF(pkg), apk_error_str(r)); 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 apk_db_install_pkg(struct apk_database *db, struct apk_package *oldpkg, + struct apk_package *newpkg, apk_progress_cb cb, void *cb_ctx) { char *script_args[] = { NULL, NULL, NULL, NULL }; struct apk_installed_package *ipkg; @@ -2634,18 +2625,11 @@ int apk_db_install_pkg(struct apk_database *db, /* Just purging? */ if (oldpkg != NULL && newpkg == NULL) { ipkg = oldpkg->ipkg; - if (ipkg == NULL) goto ret_r; - - r = apk_ipkg_run_script(ipkg, db, - APK_SCRIPT_PRE_DEINSTALL, script_args); - if (r != 0) - goto ret_r; - + apk_ipkg_run_script(ipkg, db, APK_SCRIPT_PRE_DEINSTALL, script_args); apk_db_purge_pkg(db, ipkg, NULL); - r = apk_ipkg_run_script(ipkg, db, - APK_SCRIPT_POST_DEINSTALL, script_args); + apk_ipkg_run_script(ipkg, db, APK_SCRIPT_POST_DEINSTALL, script_args); apk_pkg_uninstall(db, oldpkg); goto ret_r; } @@ -2661,12 +2645,14 @@ int apk_db_install_pkg(struct apk_database *db, if (newpkg->installed_size != 0) { r = apk_db_unpack_pkg(db, ipkg, (oldpkg != NULL), - (oldpkg == newpkg), cb, cb_ctx, - script_args); + cb, cb_ctx, script_args); if (r != 0) { + if (oldpkg != newpkg) + apk_db_purge_pkg(db, ipkg, ".apk-new"); apk_pkg_uninstall(db, newpkg); goto ret_r; } + apk_db_migrate_files(db, ipkg); } if (oldpkg != NULL && oldpkg != newpkg && oldpkg->ipkg != NULL) { @@ -2674,14 +2660,13 @@ int apk_db_install_pkg(struct apk_database *db, apk_pkg_uninstall(db, oldpkg); } - r = apk_ipkg_run_script(ipkg, db, - (oldpkg == NULL) ? - APK_SCRIPT_POST_INSTALL : APK_SCRIPT_POST_UPGRADE, - script_args); - if (r != 0) { - apk_error(PKG_VER_FMT ": Failed to execute post-install/upgrade script", - PKG_VER_PRINTF(newpkg)); - } + apk_ipkg_run_script( + ipkg, db, + (oldpkg == NULL) ? APK_SCRIPT_POST_INSTALL : APK_SCRIPT_POST_UPGRADE, + script_args); + + if (ipkg->broken_files || ipkg->broken_script) + r = -1; ret_r: free(script_args[1]); free(script_args[2]); diff --git a/src/fix.c b/src/fix.c index f71613f..4672813 100644 --- a/src/fix.c +++ b/src/fix.c @@ -52,16 +52,20 @@ static int mark_recalculate(apk_hash_item item, void *ctx) return 0; } -static void set_solver_flags(struct apk_database *db, const char *match, struct apk_name *name, void *pctx) +static void mark_fix(struct fix_ctx *ctx, struct apk_name *name) { - struct fix_ctx *ctx = (struct fix_ctx *) pctx; - apk_solver_set_name_flags(name, ctx->solver_flags, ctx->fix_depends ? ctx->solver_flags : 0); } +static void set_solver_flags(struct apk_database *db, const char *match, struct apk_name *name, void *ctx) +{ + mark_fix(ctx, name); +} + static int fix_main(void *pctx, struct apk_database *db, struct apk_string_array *args) { struct fix_ctx *ctx = (struct fix_ctx *) pctx; + struct apk_installed_package *ipkg; if (!ctx->solver_flags) ctx->solver_flags = APK_SOLVERF_REINSTALL; @@ -69,7 +73,13 @@ static int fix_main(void *pctx, struct apk_database *db, struct apk_string_array if (ctx->fix_directory_permissions) apk_hash_foreach(&db->installed.dirs, mark_recalculate, db); - apk_name_foreach_matching(db, args, apk_foreach_genid(), set_solver_flags, ctx); + if (args->num == 0) { + list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { + if (ipkg->broken_files || ipkg->broken_script) + mark_fix(ctx, ipkg->pkg->name); + } + } else + apk_name_foreach_matching(db, args, apk_foreach_genid(), set_solver_flags, ctx); return apk_solver_commit(db, 0, db->world); } diff --git a/src/package.c b/src/package.c index f38a57e..6723de6 100644 --- a/src/package.c +++ b/src/package.c @@ -796,7 +796,7 @@ int apk_pkg_add_info(struct apk_database *db, struct apk_package *pkg, pkg->commit = apk_blob_cstr(value); break; case 'F': case 'M': case 'R': case 'Z': case 'r': case 'q': - case 'a': case 's': + case 'a': case 's': case 'f': /* installed db entries which are handled in database.c */ return 1; default: @@ -973,9 +973,9 @@ int apk_ipkg_add_script(struct apk_installed_package *ipkg, return 0; } -int apk_ipkg_run_script(struct apk_installed_package *ipkg, - struct apk_database *db, - unsigned int type, char **argv) +void apk_ipkg_run_script(struct apk_installed_package *ipkg, + struct apk_database *db, + unsigned int type, char **argv) { static char * const environment[] = { "PATH=/usr/sbin:/usr/bin:/sbin:/bin", @@ -986,11 +986,8 @@ int apk_ipkg_run_script(struct apk_installed_package *ipkg, int fd, status, root_fd = db->root_fd; pid_t pid; - if (type >= APK_SCRIPT_MAX) - return -1; - - if (ipkg->script[type].ptr == NULL) - return 0; + if (type >= APK_SCRIPT_MAX || ipkg->script[type].ptr == NULL) + return; argv[0] = (char *) apk_script_types[type]; @@ -1001,43 +998,41 @@ int apk_ipkg_run_script(struct apk_installed_package *ipkg, apk_message("Executing %s", &fn[15]); if (apk_flags & APK_SIMULATE) - return 0; + return; fd = openat(root_fd, fn, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 0755); if (fd < 0) { mkdirat(root_fd, "var/cache/misc", 0755); fd = openat(root_fd, fn, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 0755); if (fd < 0) - return -errno; + goto error; } if (write(fd, ipkg->script[type].ptr, ipkg->script[type].len) < 0) { close(fd); - return -errno; + goto error; } close(fd); pid = fork(); if (pid == -1) - return -1; + goto error; if (pid == 0) { - if (fchdir(root_fd) < 0 || chroot(".") < 0) { - apk_error("chroot: %s", strerror(errno)); - } else { + if (fchdir(root_fd) == 0 && chroot(".") == 0) execve(fn, argv, environment); - } exit(1); } waitpid(pid, &status, 0); unlinkat(root_fd, fn, 0); apk_id_cache_reset(&db->id_cache); - if (WIFEXITED(status)) { - int rc = WEXITSTATUS(status); - if (rc != 0) - apk_warning("%s: returned error %d", &fn[15], rc); - return 0; + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + apk_error("%s: script exited with error %d", &fn[15], WEXITSTATUS(status)); + ipkg->broken_script = 1; } - return -1; + return; +error: + apk_error("%s: failed to execute: %s", &fn[15], apk_error_str(errno)); + ipkg->broken_script = 1; } static int parse_index_line(void *ctx, apk_blob_t line) diff --git a/test/fix4.test b/test/fix4.test index 431266b..8005d5f 100644 --- a/test/fix4.test +++ b/test/fix4.test @@ -4,5 +4,5 @@ --test-world a fix b @EXPECT -(1/1) Re-installing b (1) +(1/1) Reinstalling b (1) OK: 0 MiB in 2 packages diff --git a/test/fix5.test b/test/fix5.test index 33029fc..3c00d94 100644 --- a/test/fix5.test +++ b/test/fix5.test @@ -4,5 +4,5 @@ --test-world a fix a @EXPECT -(1/1) Re-installing a (1) +(1/1) Reinstalling a (1) OK: 0 MiB in 2 packages diff --git a/test/fix6.test b/test/fix6.test index c6dc6bd..ff87a10 100644 --- a/test/fix6.test +++ b/test/fix6.test @@ -5,6 +5,6 @@ --depends fix a @EXPECT -(1/2) Re-installing b (1) -(2/2) Re-installing a (1) +(1/2) Reinstalling b (1) +(2/2) Reinstalling a (1) OK: 0 MiB in 2 packages