[pacman-dev] [PATCH] Turn libarchive warnings into libalpm warnings
Rather than hiding these warnings, show them to the user as they happen. This will prevent things such as hiding full filesystem errors (ENOSPC) from the user as seen in FS#11639. Signed-off-by: Dan McGee <dan@archlinux.org> --- Note: this patch is almost superseded by the next one, but its important to note we are suddenly going to put more force behind these libarchive warnings. lib/libalpm/add.c | 4 ++-- lib/libalpm/util.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index 5040589..f4caa5c 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -444,7 +444,7 @@ static int extract_single_file(struct archive *archive, ret = archive_read_extract(archive, entry, archive_flags); if(ret == ARCHIVE_WARN) { /* operation succeeded but a non-critical error was encountered */ - _alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n", + _alpm_log(PM_LOG_WARNING, "warning extracting %s (%s)\n", entryname_orig, archive_error_string(archive)); } else if(ret != ARCHIVE_OK) { _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"), @@ -594,7 +594,7 @@ static int extract_single_file(struct archive *archive, ret = archive_read_extract(archive, entry, archive_flags); if(ret == ARCHIVE_WARN) { /* operation succeeded but a non-critical error was encountered */ - _alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n", + _alpm_log(PM_LOG_WARNING, "warning extracting %s (%s)\n", entryname_orig, archive_error_string(archive)); } else if(ret != ARCHIVE_OK) { _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"), diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index da3463b..a9330d3 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -333,7 +333,7 @@ int _alpm_unpack(const char *archive, const char *prefix, const char *fn) int readret = archive_read_extract(_archive, entry, 0); if(readret == ARCHIVE_WARN) { /* operation succeeded but a non-critical error was encountered */ - _alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n", + _alpm_log(PM_LOG_WARNING, "warning extracting %s (%s)\n", entryname, archive_error_string(_archive)); } else if(readret != ARCHIVE_OK) { _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"), -- 1.6.0.3
This should hopefully address some of the concerns raised in FS#11639 with regards to continuing after filling the disk up. I'm not sure if we are being too quick on the trigger here by failing after the package on every warning libarchive can emit, but it remains to be seen. Add some more checks and passing of error conditions between our functions. We now ensure errors are returned when warnings or errors occur extracting a single file, and then note the presence of errors after extraction of an entire package is complete. If so, we abort the transaction to be on the safe side and keep damage to a minimum. Signed-off-by: Dan McGee <dan@archlinux.org> --- Hey guys, I would *love* it if someone could take this patch and run with it. I really just wanted to hash out a possible fix, but unfortunately it isn't easy for two reasons: our code structure is a bit rough, and we really don't have a hard-and-fast set of rules for continuing or failing immediately. If anyone wants to attack the problem further, you are more than welcome. Although this patch doesn't cause any pactests to fail, I'm a bit wary of applying it as-is, especially to maint. -Dan lib/libalpm/add.c | 89 +++++++++++++++++++++++++++++++++------------------- 1 files changed, 56 insertions(+), 33 deletions(-) diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index f4caa5c..ee0898c 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -268,6 +268,32 @@ static int upgrade_remove(pmpkg_t *oldpkg, pmpkg_t *newpkg, pmtrans_t *trans, pm return(0); } +static int perform_extraction(struct archive *archive, + struct archive_entry *entry, const char *filename, const char *origname) +{ + int ret; + const int archive_flags = ARCHIVE_EXTRACT_OWNER | + ARCHIVE_EXTRACT_PERM | + ARCHIVE_EXTRACT_TIME; + + archive_entry_set_pathname(entry, filename); + + ret = archive_read_extract(archive, entry, archive_flags); + if(ret == ARCHIVE_WARN) { + /* operation succeeded but a non-critical error was encountered */ + _alpm_log(PM_LOG_WARNING, "warning extracting %s (%s)\n", + origname, archive_error_string(archive)); + return(2); + } else if(ret != ARCHIVE_OK) { + _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"), + origname, archive_error_string(archive)); + alpm_logaction("error: could not extract %s (%s)\n", + origname, archive_error_string(archive)); + return(1); + } + return(0); +} + static int extract_single_file(struct archive *archive, struct archive_entry *entry, pmpkg_t *newpkg, pmpkg_t *oldpkg, pmtrans_t *trans, pmdb_t *db) @@ -278,9 +304,6 @@ static int extract_single_file(struct archive *archive, int needbackup = 0, notouch = 0; char *hash_orig = NULL; char *entryname_orig = NULL; - const int archive_flags = ARCHIVE_EXTRACT_OWNER | - ARCHIVE_EXTRACT_PERM | - ARCHIVE_EXTRACT_TIME; int errors = 0; entryname = archive_entry_pathname(entry); @@ -439,18 +462,13 @@ static int extract_single_file(struct archive *archive, int ret; snprintf(checkfile, PATH_MAX, "%s.paccheck", filename); - archive_entry_set_pathname(entry, checkfile); - - ret = archive_read_extract(archive, entry, archive_flags); - if(ret == ARCHIVE_WARN) { - /* operation succeeded but a non-critical error was encountered */ - _alpm_log(PM_LOG_WARNING, "warning extracting %s (%s)\n", - entryname_orig, archive_error_string(archive)); - } else if(ret != ARCHIVE_OK) { - _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"), - entryname_orig, archive_error_string(archive)); - alpm_logaction("error: could not extract %s (%s)\n", - entryname_orig, archive_error_string(archive)); + + ret = perform_extraction(archive, entry, checkfile, entryname_orig); + if(ret == 2) { + /* warning */ + errors++; + } else if(ret == 1) { + /* error */ FREE(hash_orig); FREE(entryname_orig); return(1); @@ -589,18 +607,12 @@ static int extract_single_file(struct archive *archive, unlink(filename); } - archive_entry_set_pathname(entry, filename); - - ret = archive_read_extract(archive, entry, archive_flags); - if(ret == ARCHIVE_WARN) { - /* operation succeeded but a non-critical error was encountered */ - _alpm_log(PM_LOG_WARNING, "warning extracting %s (%s)\n", - entryname_orig, archive_error_string(archive)); - } else if(ret != ARCHIVE_OK) { - _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"), - entryname_orig, archive_error_string(archive)); - alpm_logaction("error: could not extract %s (%s)\n", - entryname_orig, archive_error_string(archive)); + ret = perform_extraction(archive, entry, filename, entryname_orig); + if(ret == 2) { + /* warning */ + errors++; + } else if(ret == 1) { + /* error */ FREE(entryname_orig); return(1); } @@ -851,6 +863,7 @@ cleanup: int _alpm_add_commit(pmtrans_t *trans, pmdb_t *db) { int pkg_count, pkg_current; + int skip_ldconfig = 0, ret = 0; alpm_list_t *targ; ALPM_LOG_FUNC; @@ -868,19 +881,29 @@ int _alpm_add_commit(pmtrans_t *trans, pmdb_t *db) /* loop through our package list adding/upgrading one at a time */ for(targ = trans->packages; targ; targ = targ->next) { if(handle->trans->state == STATE_INTERRUPTED) { - return(0); + return(ret); } pmpkg_t *newpkg = (pmpkg_t *)targ->data; - commit_single_pkg(newpkg, pkg_current, pkg_count, trans, db); + if(commit_single_pkg(newpkg, pkg_current, pkg_count, trans, db)) { + /* something screwed up on the commit, abort the trans */ + trans->state = STATE_INTERRUPTED; + pm_errno = PM_ERR_TRANS_ABORT; + /* running ldconfig at this point could possibly screw system */ + skip_ldconfig = 1; + ret = -1; + } + pkg_current++; } - /* run ldconfig if it exists */ - _alpm_log(PM_LOG_DEBUG, "running \"ldconfig -r %s\"\n", handle->root); - _alpm_ldconfig(handle->root); + if(!skip_ldconfig) { + /* run ldconfig if it exists */ + _alpm_log(PM_LOG_DEBUG, "running \"ldconfig -r %s\"\n", handle->root); + _alpm_ldconfig(handle->root); + } - return(0); + return(ret); } /* vim: set ts=2 sw=2 noet: */ -- 1.6.0.3
Hey guys,
I would *love* it if someone could take this patch and run with it. I really just wanted to hash out a possible fix, but unfortunately it isn't easy for two reasons: our code structure is a bit rough, and we really don't have a hard-and-fast set of rules for continuing or failing immediately. If anyone wants to attack the problem further, you are more than welcome. Although this patch doesn't cause any pactests to fail, I'm a bit wary of applying it as-is, especially to maint.
-Dan
1. The first part of the patch is just a code clean-up, right? 2. The add_commit part: There is something I don't understand: We have trans->state and handle->trans->state. This is intentional? Probably you wanted to set handle->trans->state. (handle->trans != trans in case of sync transaction.) Btw, our transaction system is a nightmare, we should have *one* transaction at every moment... I don't know if this immediate stop is better. If we choose this way, we should give a BIG warning: Some packages were installed some packages were not. So your system probably became inconsistent (broken dependencies etc.) Bye P.S.: Transaction rollback would be the ideal solution. (Which is not an easy game.)
On Sat, Nov 1, 2008 at 7:58 AM, Nagy Gabor <ngaba@bibl.u-szeged.hu> wrote:
Hey guys,
I would *love* it if someone could take this patch and run with it. I really just wanted to hash out a possible fix, but unfortunately it isn't easy for two reasons: our code structure is a bit rough, and we really don't have a hard-and-fast set of rules for continuing or failing immediately. If anyone wants to attack the problem further, you are more than welcome. Although this patch doesn't cause any pactests to fail, I'm a bit wary of applying it as-is, especially to maint.
-Dan
1. The first part of the patch is just a code clean-up, right? Yes, so we don't do the actual extraction in two different places. But it has important consequences because we now handle the two cases differently.
2. The add_commit part: There is something I don't understand: We have trans->state and handle->trans->state. This is intentional? Probably you wanted to set handle->trans->state. No, if things are sane, I want to abort the *current* transaction. We are looking at that one's packages. In this case, because this is the add transaction, we should only have one? Or am I completely off and we still make another sub-transaction.
(handle->trans != trans in case of sync transaction.) Btw, our transaction system is a nightmare, we should have *one* transaction at every moment... You are saying the same thing I've been thinking for a while. It is a huge mess and I'm not happy about it, so I'm right with you here. :)
I don't know if this immediate stop is better. If we choose this way, http://bugs.archlinux.org/task/11639 needs to get addressed, and preferably in a maint release. I'm all ears for other suggestions.
we should give a BIG warning: Some packages were installed some packages were not. So your system probably became inconsistent (broken dependencies etc.) The idea was your system is probably inconsistant because you have broken packages installed (files didn't make it out of the archive properly).
Bye
P.S.: Transaction rollback would be the ideal solution. (Which is not an easy game.) We've been saying this for a while too. :)
There is something I don't understand: We have trans->state and handle->trans->state. This is intentional? Probably you wanted to set handle->trans->state. No, if things are sane, I want to abort the *current* transaction. We are looking at that one's packages. In this case, because this is the add transaction, we should only have one? Or am I completely off and we still make another sub-transaction.
I may completely misunderstand something. So I guess that the purpose of this patch, that pacman should stop immediately after package upgrade if error occurs (not trying to commit the whole transaction, ie. installing the remaining packages.) This will work with -A/-U, where trans == handle->trans. However, if trans != handle->trans, setting trans->state has no effect, because add_commit watches the state of handle->trans only (in the first line of the loop). This is the situation with -S: handle->trans is a sync transaction, but sync_commit will create a new upgrade transaction, and it will commit it (this is passed to add_commit). So as I see, this patch has no effect on sync transaction. Maybe you forgot to insert a "break;" somewhere... Bye
participants (3)
-
Dan McGee
-
Dan McGee
-
Nagy Gabor