diff options
author | Panu Matilainen <pmatilai@redhat.com> | 2020-08-27 10:31:07 +0300 |
---|---|---|
committer | Panu Matilainen <pmatilai@redhat.com> | 2020-12-10 13:28:07 +0200 |
commit | ba0f1bc146a0495171837b074255f2eb79670022 (patch) | |
tree | b41e534476b677fc9cd50ea13cd70eb05221de4c | |
parent | 24c10a49078e679d7ccf3f1d4fe656d4e5f2c1f0 (diff) | |
download | rpm-ba0f1bc146a0495171837b074255f2eb79670022.tar.gz |
Upgrade FA_TOUCH to FA_CREATE if the file went away (RhBug:1872141)
When %_minimize_writes is enabled, we determine unchanged files during
fingerprinting and only update their metadata (FA_TOUCH) instead of
always recreating from scratch (FA_CREATE) during install. However
package scriptlets (and administrators) can and will do arbitrary stuff
in the meanwhile, such as rm -f their own files in %pre, hoping to
get a fresh copy of contents no matter what. Or something.
Now, if the file was determined to not need changing by rpm, this will
just fail with chown & friends trying to touch non-existent file.
One can consider this a case of package shooting itself in the foot, but
when a package update fails or succeeds depending on %_minimize_writes this
to me suggests the feature is at fault as much as the package.
Do fsmVerify() on all files to be FA_TOUCH'ed to detect files whose
type changed or were removed since fingerprinting. This still doesn't
ensure correctness if something tampers with the contents in the meanwhile,
(for that we'd need to run the file through the whole machinery again,
checksumming and all) but covers the most glaring cases.
(cherry picked from commit 886c24cfc6c0fec90d8db1406a0e32c0e09e92c9)
-rw-r--r-- | lib/fsm.c | 15 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rw-r--r-- | tests/data/SPECS/suicidal.spec | 19 | ||||
-rw-r--r-- | tests/rpmi.at | 39 |
4 files changed, 70 insertions, 4 deletions
@@ -902,10 +902,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, if (!skip) { int setmeta = 1; - /* When touching we don't need any of this... */ - if (action == FA_TOUCH) - goto touch; - /* Directories replacing something need early backup */ if (!suffix) { rc = fsmBackup(fi, action); @@ -917,6 +913,17 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, rc = RPMERR_ENOENT; } + /* See if the file was removed while our attention was elsewhere */ + if (rc == RPMERR_ENOENT && action == FA_TOUCH) { + rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", fpath); + action = FA_CREATE; + fsmDebug(fpath, action, &sb); + } + + /* When touching we don't need any of this... */ + if (action == FA_TOUCH) + goto touch; + if (S_ISREG(sb.st_mode)) { if (rc == RPMERR_ENOENT) { rc = fsmMkfile(fi, fpath, files, psm, nodigest, diff --git a/tests/Makefile.am b/tests/Makefile.am index f7f63a91a..f742a9e1d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -73,6 +73,7 @@ EXTRA_DIST += data/SPECS/scriptfail.spec EXTRA_DIST += data/SPECS/scriptfile.spec EXTRA_DIST += data/SPECS/selfconflict.spec EXTRA_DIST += data/SPECS/shebang.spec +EXTRA_DIST += data/SPECS/suicidal.spec EXTRA_DIST += data/SPECS/replacetest.spec EXTRA_DIST += data/SPECS/triggers.spec EXTRA_DIST += data/SPECS/filetriggers.spec diff --git a/tests/data/SPECS/suicidal.spec b/tests/data/SPECS/suicidal.spec new file mode 100644 index 000000000..77d17d8c9 --- /dev/null +++ b/tests/data/SPECS/suicidal.spec @@ -0,0 +1,19 @@ +Name: suicidal +Version: 1 +Release: %{rel} +License: GPL +Group: Testing +Summary: Testing suicidal package behavior +BuildArch: noarch + +%description + +%build +mkdir -p %{buildroot}/opt +echo shoot > %{buildroot}/opt/foot + +%pre -p <lua> +os.remove('/opt/foot') + +%files +/opt/foot diff --git a/tests/rpmi.at b/tests/rpmi.at index a55a50116..42dc52ba3 100644 --- a/tests/rpmi.at +++ b/tests/rpmi.at @@ -683,3 +683,42 @@ test -e ${RPMTEST}/opt/vattrtest/a || exit 1 [], []) AT_CLEANUP + +AT_SETUP([rpm -U <suicidal>]) +AT_KEYWORDS([install]) +RPMDB_INIT + +for r in 1 2; do + runroot rpmbuild -bb --quiet \ + --define "rel ${r}" \ + /data/SPECS/suicidal.spec +done + +AT_CHECK([ +RPMDB_INIT + +for r in 1 2; do + runroot rpm -U \ + --define "_minimize_writes 0" \ + /build/RPMS/noarch/suicidal-1-${r}.noarch.rpm +done +runroot rpm -V --nouser --nogroup suicidal +], +[0], +[], +[]) + +AT_CHECK([ +RPMDB_INIT + +for r in 1 2; do + runroot rpm -U \ + --define "_minimize_writes 1" \ + /build/RPMS/noarch/suicidal-1-${r}.noarch.rpm +done +runroot rpm -V --nouser --nogroup suicidal +], +[0], +[], +[]) +AT_CLEANUP |