Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package libguestfs for openSUSE:Factory 
checked in at 2026-07-21 23:14:35
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libguestfs (Old)
 and      /work/SRC/openSUSE:Factory/.libguestfs.new.24530 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libguestfs"

Tue Jul 21 23:14:35 2026 rev:133 rq:1367026 version:1.60.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/libguestfs/libguestfs.changes    2026-07-14 
13:50:44.520656638 +0200
+++ /work/SRC/openSUSE:Factory/.libguestfs.new.24530/libguestfs.changes 
2026-07-21 23:14:48.287336468 +0200
@@ -1,0 +2,7 @@
+Tue Jul 14 13:01:08 MDT 2026 - [email protected]
+
+- bsc#1271111 - guestfish initrd-list can't list our initrd due to
+  zstd compression. (Jiri Belka and AI)
+  add-support-for-initrd-compression-formats.patch
+
+-------------------------------------------------------------------

New:
----
  add-support-for-initrd-compression-formats.patch

----------(New B)----------
  New:  zstd compression. (Jiri Belka and AI)
  add-support-for-initrd-compression-formats.patch
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libguestfs.spec ++++++
--- /var/tmp/diff_new_pack.GdT10G/_old  2026-07-21 23:14:49.711385215 +0200
+++ /var/tmp/diff_new_pack.GdT10G/_new  2026-07-21 23:14:49.715385352 +0200
@@ -35,6 +35,7 @@
 Patch1:         reproducible-builds.patch
 Patch2:         drop-initviocons-from-package-list.patch
 Patch3:         Ensure-fds-0-1-2-are-open-in-the-subcommand.patch
+Patch4:         add-support-for-initrd-compression-formats.patch
 Patch100:       use-fuse3-for-build.patch
 
 BuildRequires:  bison

++++++ add-support-for-initrd-compression-formats.patch ++++++
References: bsc#1271111

Add support for common compression formats used on the initrd file.
This allows guestfish to successfully open and list the contents.

Patch contributed by Jiri Belka and AI.

Signed-off-by: Charles Arnold <[email protected]>

diff --git a/daemon/initrd.c b/daemon/initrd.c
index 9293846eb..1d4f6580c 100644
--- libguestfs-1.55.13.orig/daemon/initrd.c
+++ libguestfs-1.55.13/daemon/initrd.c
@@ -33,0 +34,187 @@
+/* Length of a newc/crc format cpio entry header (not including the
+ * filename which follows it).
+ */
+#define CPIO_NEWC_HDR_LEN 110
+
+enum initrd_compression {
+  COMPRESS_NONE,
+  COMPRESS_GZIP,
+  COMPRESS_BZIP2,
+  COMPRESS_XZ,
+  COMPRESS_ZSTD,
+};
+
+static const char *
+decompressor_command (enum initrd_compression compression)
+{
+  switch (compression) {
+  case COMPRESS_GZIP:   return "zcat";
+  case COMPRESS_BZIP2:  return "bzcat";
+  case COMPRESS_XZ:     return "xzcat";
+  case COMPRESS_ZSTD:   return "zstdcat";
+  case COMPRESS_NONE:
+  default:              return "cat";
+  }
+}
+
+static int
+is_cpio_magic (const unsigned char *magic)
+{
+  return memcmp (magic, "070701", 6) == 0 || memcmp (magic, "070702", 6) == 0;
+}
+
+/**
+ * Modern initramfs images are often composed of several concatenated
+ * cpio archives: one or more uncompressed "early cpio" archives
+ * (used by the kernel/dracut to carry CPU microcode etc, see
+ * F<Documentation/x86/microcode.rst> in the kernel sources) followed
+ * by the main, compressed cpio archive containing the real
+ * initramfs contents.
+ *
+ * This parses a single newc/crc format cpio archive starting at
+ * C<offset> in C<fd>, up to and including its C<TRAILER!!!> entry,
+ * and returns the offset of the byte following it, rounded up to
+ * the next 512-byte boundary (early cpio archives are padded to a
+ * block boundary before the next archive is appended).  Returns
+ * C<-1> if the archive is truncated or malformed.
+ */
+static off_t
+skip_early_cpio_archive (int fd, off_t offset, off_t file_size)
+{
+  unsigned char hdr[CPIO_NEWC_HDR_LEN];
+  char field[9];
+  long namesize, filesize;
+  off_t name_offset, data_offset, next;
+  CLEANUP_FREE char *name = NULL;
+
+  field[8] = '\0';
+
+  for (;;) {
+    if (offset + CPIO_NEWC_HDR_LEN > file_size)
+      return -1;
+    if (pread (fd, hdr, CPIO_NEWC_HDR_LEN, offset) != CPIO_NEWC_HDR_LEN)
+      return -1;
+    if (!is_cpio_magic (hdr))
+      return -1;
+
+    /* c_filesize is the 7th 8-hex-digit field, c_namesize is the
+     * 12th, each starting right after the 6-byte magic.
+     */
+    memcpy (field, hdr + 6 + 6*8, 8);
+    filesize = strtol (field, NULL, 16);
+    memcpy (field, hdr + 6 + 11*8, 8);
+    namesize = strtol (field, NULL, 16);
+
+    if (namesize <= 0 || namesize > PATH_MAX || filesize < 0)
+      return -1;
+
+    name_offset = offset + CPIO_NEWC_HDR_LEN;
+    if (name_offset + namesize > file_size)
+      return -1;
+
+    free (name);
+    name = malloc (namesize + 1);
+    if (name == NULL)
+      return -1;
+    if (pread (fd, name, namesize, name_offset) != namesize)
+      return -1;
+    name[namesize] = '\0';
+
+    /* Header + filename is padded to a 4-byte boundary, then the
+     * file data follows and is itself padded to a 4-byte boundary.
+     */
+    data_offset = (name_offset + namesize + 3) & ~(off_t)3;
+    next = (data_offset + filesize + 3) & ~(off_t)3;
+
+    if (STREQ (name, "TRAILER!!!"))
+      return (next + 511) & ~(off_t)511;
+
+    offset = next;
+  }
+}
+
+/**
+ * Work out where the "real" (possibly compressed) cpio archive
+ * starts within C<path>, skipping over any leading uncompressed
+ * early cpio archives, and detect its compression format (if any)
+ * by looking at its magic bytes.
+ *
+ * Returns 0 on success, or -1 on error (having already called
+ * C<reply_with_*>).
+ */
+static int
+detect_initrd (const char *path, off_t *offset_r,
+               enum initrd_compression *compression_r)
+{
+  CLEANUP_FREE char *fullpath = NULL;
+  int fd;
+  struct stat statbuf;
+  off_t offset = 0, next;
+  unsigned char magic[6];
+
+  fullpath = sysroot_path (path);
+  if (fullpath == NULL) {
+    reply_with_perror ("malloc");
+    return -1;
+  }
+
+  fd = open (fullpath, O_RDONLY|O_CLOEXEC);
+  if (fd == -1) {
+    reply_with_perror ("open: %s", path);
+    return -1;
+  }
+  if (fstat (fd, &statbuf) == -1) {
+    reply_with_perror ("fstat: %s", path);
+    close (fd);
+    return -1;
+  }
+
+  while (offset + (off_t) sizeof magic <= statbuf.st_size &&
+         pread (fd, magic, sizeof magic, offset) == (ssize_t) sizeof magic &&
+         is_cpio_magic (magic)) {
+    next = skip_early_cpio_archive (fd, offset, statbuf.st_size);
+    if (next < 0 || next >= statbuf.st_size)
+      break;
+    offset = next;
+  }
+
+  if (pread (fd, magic, sizeof magic, offset) < 4)
+    *compression_r = COMPRESS_NONE;
+  else if (magic[0] == 0x1f && magic[1] == 0x8b)
+    *compression_r = COMPRESS_GZIP;
+  else if (magic[0] == 0x42 && magic[1] == 0x5a && magic[2] == 0x68)
+    *compression_r = COMPRESS_BZIP2;
+  else if (magic[0] == 0xfd && magic[1] == 0x37 && magic[2] == 0x7a &&
+           magic[3] == 0x58)
+    *compression_r = COMPRESS_XZ;
+  else if (magic[0] == 0x28 && magic[1] == 0xb5 && magic[2] == 0x2f &&
+           magic[3] == 0xfd)
+    *compression_r = COMPRESS_ZSTD;
+  else
+    *compression_r = COMPRESS_NONE;
+
+  close (fd);
+  *offset_r = offset;
+  return 0;
+}
+
+/* Write the pipeline needed to produce the decompressed cpio stream
+ * for <path> to fp, ie. "[tail -c +N <path> |] <decompressor> <path>".
+ */
+static void
+write_decompress_pipeline (FILE *fp, const char *path,
+                           off_t offset, enum initrd_compression compression)
+{
+  const char *decompressor = decompressor_command (compression);
+
+  if (offset > 0) {
+    fprintf (fp, "tail -c +%lld ", (long long) offset + 1);
+    sysroot_shell_quote (path, fp);
+    fprintf (fp, " | %s", decompressor);
+  }
+  else {
+    fprintf (fp, "%s ", decompressor);
+    sysroot_shell_quote (path, fp);
+  }
+}
+
@@ -44,0 +232,5 @@ do_initrd_list (const char *path)
+  off_t offset;
+  enum initrd_compression compression;
+
+  if (detect_initrd (path, &offset, &compression) == -1)
+    return NULL;
@@ -46 +238 @@ do_initrd_list (const char *path)
-  /* "zcat /sysroot/<path> | cpio --quiet -it", but path must be quoted. */
+  /* "[tail -c +N /sysroot/<path> |] zcat | cpio --quiet -it" */
@@ -53,2 +245 @@ do_initrd_list (const char *path)
-  fprintf (fp, "zcat ");
-  sysroot_shell_quote (path, fp);
+  write_decompress_pipeline (fp, path, offset, compression);
@@ -108,0 +300,5 @@ do_initrd_cat (const char *path, const char *filename, 
size_t *size_r)
+  off_t offset;
+  enum initrd_compression compression;
+
+  if (detect_initrd (path, &offset, &compression) == -1)
+    return NULL;
@@ -120 +316,3 @@ do_initrd_cat (const char *path, const char *filename, size_t 
*size_r)
-  /* "zcat /sysroot/<path> | cpio --quiet -id file", but paths must be quoted 
*/
+  /* "cd tmpdir && [tail -c +N |] zcat /sysroot/<path> | cpio --quiet -id 
file",
+   * but paths must be quoted.
+   */
@@ -130,2 +328,2 @@ do_initrd_cat (const char *path, const char *filename, 
size_t *size_r)
-  fprintf (fp, " && zcat ");
-  sysroot_shell_quote (path, fp);
+  fprintf (fp, " && ");
+  write_decompress_pipeline (fp, path, offset, compression);

Reply via email to