RPM 6.0 intentionally changed rpmtsRun() to return -1 whenever any
scriptlet fails, even non-critical ones like %post where warn_only=True
(upstream RPM PR#3819, lib/transaction.cc).
Root cause — two changes in RPM 6 lib/transaction.cc vs RPM 4:
1. New field set before warn_only resets rc (transaction.cc:1754):
ts->scriptError = 1;
2. Final exit now ORs in the new flag (transaction.cc:1910):
RPM 4: rc = nfailed ? -1 : 0;
RPM 6: rc = (nfailed || ts->scriptError) ? -1 : 0;
Call chain for a failing %post in RPM 4 (exits 0):
runScript() warn_only=1 → rc reset to RPMRC_OK
psm.c:896 if (rc) break → NOT taken, install continues
rpmte.c:823 if (failed) → NOT taken, rpmteMarkFailed() skipped
transaction.c:1652 if (failed) → NOT taken, nfailed stays 0
transaction.c:1896 rc = nfailed ? -1 : 0 → rc=0
Python ts.run() returns None → DNF exits 0
Call chain for a failing %post in RPM 6 (exits 1):
runScript() ts->scriptError=1, then rc reset to RPMRC_OK
psm.c:896 if (rc) break → NOT taken (rc still 0)
rpmte.c:823 if (failed) → NOT taken (same as RPM 4)
transaction.cc:1652 if (failed) → NOT taken, nfailed stays 0
transaction.cc:1910 rc = (nfailed || ts->scriptError) ? -1 : 0 → rc=-1
Python ts.run() returns [] → DNF raises "Could not run
transaction."
→ DNF exits 1
In both RPM versions, RPMCALLBACK_SCRIPT_ERROR fires and DNF's
_scriptError() (dnf/yum/rpmtrans.py:407-418) prints:
"Error in POSTIN scriptlet in rpm package <name>"
OE's install_pkgs() already scans for this line and calls
failed_postinsts_abort() (package_manager/rpm/__init__.py:210-219).
With RPM 4 this path is always reached because DNF exits 0. With RPM 6
the CalledProcessError raised by DNF's non-zero exit intercepts
execution
in _invoke_dnf() before the scan runs.
DNF 4 (lib/dnf/base.py:1146-1158) was never updated for this RPM 6
behaviour. When ts.run() returns [] with no failed elements it
unconditionally raises "Could not run transaction." — the comment at
base.py:1147 still describes RPM 4 semantics where this case meant a
global error such as a transaction lock failure. There is an open DNF5
issue (#2507) but no fix in DNF 4.
Fix: detect "Error in POSTIN scriptlet in rpm package" in the DNF output
inside _invoke_dnf()'s CalledProcessError handler and return the output
instead of calling bb.fatal(), allowing install_pkgs()'s existing
scriptlet scan to run as it did with RPM 4.
Tested with oe-selftest runtime_test.Postinst.test_failing_postinst:
rpm 4.20.x: PASSED — DNF exits 0, scan path exercised as expected
rpm 6.0.x without fix: FAILED — CalledProcessError before scan reached
rpm 6.0.x with fix: PASSED — scan path restored, bb.fatal() fires
References:
https://github.com/rpm-software-management/rpm/pull/3819
Signed-off-by: Sumanth Gavini <[email protected]>
---
meta/lib/oe/package_manager/rpm/__init__.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/meta/lib/oe/package_manager/rpm/__init__.py
b/meta/lib/oe/package_manager/rpm/__init__.py
index cd6efe3d3b..ccb4316bd0 100644
--- a/meta/lib/oe/package_manager/rpm/__init__.py
+++ b/meta/lib/oe/package_manager/rpm/__init__.py
@@ -333,6 +333,13 @@ class RpmPM(PackageManager):
except subprocess.CalledProcessError as e:
if print_output:
e_output = e.output.decode("utf-8")
+ # RPM 6 fails the entire transaction when a %post scriptlet
+ # fails, causing dnf to exit non-zero. Let install_pkgs handle
+ # scriptlet failures via its existing "Error in POSTIN
scriptlet"
+ # scanning rather than treating this as a fatal dnf invocation
error.
+ if "Error in POSTIN scriptlet in rpm package" in e_output:
+ bb.note(e_output)
+ return e_output
extra_info = ""
if "install" in dnf_args:
if "Error: Unable to find a match:" in e_output:
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#244171):
https://lists.openembedded.org/g/openembedded-core/message/244171
Mute This Topic: https://lists.openembedded.org/mt/120914002/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-