We previously didn't bother to check the return values from any librpm
calls. In some cases where possibly the RPM database is faulty, this
caused us to return a zero-length list of installed applications (but
no error indication).
One way to reproduce this is given below. Note this reproducer will
only work when run on a RHEL 8 host (or more specifically, with
rpm <= 4.16):
$ virt-builder fedora-28
$ guestfish -a fedora-28.img -i rm /var/lib/rpm/Packages
$ guestfish --ro -a fedora-28.img -i inspect-list-applications /dev/sda4 -vx
...
chroot: /sysroot: running 'librpm'
error: cannot open Packages index using db5 - Read-only file system (30)
error: cannot open Packages database in
error: cannot open Packages index using db5 - Read-only file system (30)
error: cannot open Packages database in
librpm returned 0 installed packages
...
With this commit we get an error instead:
...
chroot: /sysroot: running 'librpm'
error: cannot open Packages index using db5 - Read-only file system (30)
error: cannot open Packages database in
ocaml_exn: 'internal_list_rpm_applications' raised 'Failure' exception
guestfsd: error: rpmtsInitIterator
guestfsd: => internal_list_rpm_applications (0x1fe) took 0.01 secs
libguestfs: trace: internal_list_rpm_applications = NULL (error)
libguestfs: error: internal_list_rpm_applications: rpmtsInitIterator
libguestfs: trace: inspect_list_applications2 = NULL (error)
libguestfs: trace: inspect_list_applications = NULL (error)
...
Not in this case, but in some cases of corrupt RPM databases it is
possible to recover them by running "rpmdb --rebuilddb" as a guest
command (ie. with guestfs_sh).
See-also:
https://bugzilla.redhat.com/show_bug.cgi?id=2089623#c12
Fixes:
https://bugzilla.redhat.com/show_bug.cgi?id=2089623
Fixes: commit c9ee831affed55abe0f928134cbbd2ed83b2f510
Reported-by: Xiaodai Wang
Reported-by: Ming Xie
---
daemon/rpm-c.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/daemon/rpm-c.c b/daemon/rpm-c.c
index 74d325a17b..2cb50a62d2 100644
--- a/daemon/rpm-c.c
+++ b/daemon/rpm-c.c
@@ -24,6 +24,7 @@
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
#include <caml/alloc.h>
#include <caml/fail.h>
@@ -79,7 +80,14 @@ value
guestfs_int_daemon_rpm_init (value unitv)
{
CAMLparam1 (unitv);
- rpmReadConfigFiles (NULL, NULL);
+
+ /* Nothing in actual RPM C code bothers to check if this call
+ * succeeds, so using that as an example, just print a debug message
+ * if it failed, but continue. (The librpm Python bindings do check)
+ */
+ if (rpmReadConfigFiles (NULL, NULL) == -1)
+ fprintf (stderr, "rpmReadConfigFiles: failed, errno=%d\n", errno);
+
CAMLreturn (Val_unit);
}
@@ -92,6 +100,8 @@ guestfs_int_daemon_rpm_start_iterator (value unitv)
CAMLparam1 (unitv);
ts = rpmtsCreate ();
+ if (ts == NULL)
+ caml_failwith ("rpmtsCreate");
#ifdef RPMVSF_MASK_NOSIGNATURES
/* Disable signature checking (RHBZ#2064182). */
@@ -99,6 +109,14 @@ guestfs_int_daemon_rpm_start_iterator (value unitv)
#endif
iter = rpmtsInitIterator (ts, RPMDBI_PACKAGES, NULL, 0);
+ /* This could return NULL in theory if there are no packages, but
+ * that could not happen in a real guest. However it also returns
+ * NULL when unable to open the database (RHBZ#2089623) which is
+ * something we do need to detect.
+ */
+ if (iter == NULL)
+ caml_failwith ("rpmtsInitIterator");
+
CAMLreturn (Val_unit);
}
--
2.35.1