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);
