From 083ea5a13b421dc8d97283df918abb81a4e21e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Mon, 26 Jul 2021 14:01:05 +0300 Subject: [PATCH] db: add some error checking to database state write Make errors more observable. Unfortunately full rollback is non-trivial to implement. This is something to be fixed with the v3 database format. --- src/commit.c | 2 +- src/database.c | 89 ++++++++++++++++++++++++++++---------------------- 2 files changed, 51 insertions(+), 40 deletions(-) diff --git a/src/commit.c b/src/commit.c index 640c135..d53ae8a 100644 --- a/src/commit.c +++ b/src/commit.c @@ -351,7 +351,7 @@ int apk_solver_commit_changeset(struct apk_database *db, all_done: apk_dependency_array_copy(&db->world, world); - apk_db_write_config(db); + if (apk_db_write_config(db) != 0) errors++; run_commit_hooks(db, POST_COMMIT_HOOK); if (!db->performing_self_upgrade) { diff --git a/src/database.c b/src/database.c index 1b281f7..2a18a47 100644 --- a/src/database.c +++ b/src/database.c @@ -930,14 +930,14 @@ static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os) struct hlist_node *c1, *c2; char buf[1024+PATH_MAX]; apk_blob_t bbuf = APK_BLOB_BUF(buf); - int r; + int r = 0; + + if (IS_ERR(os)) return PTR_ERR(os); 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; - } + if (r < 0) goto err; if (ipkg->replaces->num) { apk_blob_push_blob(&bbuf, APK_BLOB_STR("r:")); @@ -973,9 +973,12 @@ static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os) apk_blob_push_db_acl(&bbuf, 'M', diri->acl); bbuf = apk_blob_pushed(APK_BLOB_BUF(buf), bbuf); - if (APK_BLOB_IS_NULL(bbuf)) return -ENOBUFS; + if (APK_BLOB_IS_NULL(bbuf)) { + r = -ENOBUFS; + goto err; + } r = apk_ostream_write(os, bbuf.ptr, bbuf.len); - if (r < 0) return r; + if (r < 0) goto err; bbuf = APK_BLOB_BUF(buf); hlist_for_each_entry(file, c2, &diri->owned_files, diri_files_list) { @@ -993,17 +996,21 @@ static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os) } bbuf = apk_blob_pushed(APK_BLOB_BUF(buf), bbuf); - if (APK_BLOB_IS_NULL(bbuf)) return -ENOBUFS; + if (APK_BLOB_IS_NULL(bbuf)) { + r = -ENOBUFS; + goto err; + } r = apk_ostream_write(os, bbuf.ptr, bbuf.len); - if (r < 0) return r; + if (r < 0) goto err; bbuf = APK_BLOB_BUF(buf); } } r = apk_ostream_write(os, "\n", 1); - if (r < 0) return r; + if (r < 0) goto err; } - - return 0; +err: + if (r < 0) apk_ostream_cancel(os, r); + return apk_ostream_close(os); } static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os) @@ -1016,6 +1023,8 @@ static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os int r, i; time_t now = time(NULL); + if (IS_ERR(os)) return PTR_ERR(os); + list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { pkg = ipkg->pkg; @@ -1042,12 +1051,15 @@ static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os apk_blob_push_blob(&bfn, APK_BLOB_PTR_LEN("", 1)); r = apk_tar_write_entry(os, &fi, ipkg->script[i].ptr); - if (r < 0) - return r; + if (r < 0) { + apk_ostream_cancel(os, -APKE_V2DB_FORMAT); + break; + } } } - return apk_tar_write_entry(os, NULL, NULL); + apk_tar_write_entry(os, NULL, NULL); + return apk_ostream_close(os); } static int apk_read_script_archive_entry(void *ctx, @@ -1101,13 +1113,15 @@ static int parse_triggers(void *ctx, apk_blob_t blob) return 0; } -static void apk_db_triggers_write(struct apk_database *db, struct apk_ostream *os) +static int apk_db_triggers_write(struct apk_database *db, struct apk_ostream *os) { struct apk_installed_package *ipkg; char buf[APK_BLOB_CHECKSUM_BUF]; apk_blob_t bfn; char **trigger; + if (IS_ERR(os)) return PTR_ERR(os); + list_for_each_entry(ipkg, &db->installed.triggers, trigger_pkgs_list) { bfn = APK_BLOB_BUF(buf); apk_blob_push_csum(&bfn, &ipkg->pkg->csum); @@ -1120,6 +1134,7 @@ static void apk_db_triggers_write(struct apk_database *db, struct apk_ostream *o } apk_ostream_write(os, "\n", 1); } + return apk_ostream_close(os); } static int apk_db_triggers_read(struct apk_database *db, struct apk_istream *is) @@ -1737,7 +1752,7 @@ int apk_db_write_config(struct apk_database *db) { struct apk_out *out = &db->ctx->out; struct apk_ostream *os; - int r; + int r, rr = 0; if ((db->ctx->flags & APK_SIMULATE) || db->ctx->root == NULL) return 0; @@ -1748,33 +1763,30 @@ int apk_db_write_config(struct apk_database *db) } os = apk_ostream_to_file(db->root_fd, apk_world_file, 0644); - if (IS_ERR_OR_NULL(os)) return PTR_ERR(os); - apk_deps_write(db, db->world, os, APK_BLOB_PTR_LEN("\n", 1)); - apk_ostream_write(os, "\n", 1); - r = apk_ostream_close(os); - if (r < 0) return r; + if (!IS_ERR(os)) { + apk_deps_write(db, db->world, os, APK_BLOB_PTR_LEN("\n", 1)); + apk_ostream_write(os, "\n", 1); + r = apk_ostream_close(os); + if (r && !rr) rr = r; + } - os = apk_ostream_to_file(db->root_fd, apk_installed_file, 0644); - if (IS_ERR_OR_NULL(os)) return PTR_ERR(os); - apk_db_write_fdb(db, os); - r = apk_ostream_close(os); - if (r < 0) return r; + r = apk_db_write_fdb(db, apk_ostream_to_file(db->root_fd, apk_installed_file, 0644)); + if (r < 0 && !rr) rr = r; - os = apk_ostream_to_file(db->root_fd, apk_scripts_file, 0644); - if (IS_ERR_OR_NULL(os)) return PTR_ERR(os); - apk_db_scriptdb_write(db, os); - r = apk_ostream_close(os); - if (r < 0) return r; + r = apk_db_scriptdb_write(db, apk_ostream_to_file(db->root_fd, apk_scripts_file, 0644)); + if (r < 0 && !rr) rr = r; - apk_db_index_write_nr_cache(db); + r = apk_db_index_write_nr_cache(db); + if (r < 0 && !rr) rr = r; - os = apk_ostream_to_file(db->root_fd, apk_triggers_file, 0644); - if (IS_ERR_OR_NULL(os)) return PTR_ERR(os); - apk_db_triggers_write(db, os); - r = apk_ostream_close(os); - if (r < 0) return r; + r = apk_db_triggers_write(db, apk_ostream_to_file(db->root_fd, apk_triggers_file, 0644)); + if (r < 0 && !rr) rr = r; - return 0; + if (rr) { + apk_err(out, "System state may be inconsistent: failed to write database: %s", + apk_error_str(rr)); + } + return rr; } void apk_db_close(struct apk_database *db) @@ -2289,7 +2301,6 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t _repository) apk_url_parse(&urlp, repo->url); apk_warn(out, "Ignoring " URL_FMT ": %s", URL_PRINTF(urlp), apk_error_str(r)); db->available_repos &= ~BIT(repo_num); - r = 0; } else { db->repo_tags[tag_id].allowed_repos |= BIT(repo_num); }