[Libguestfs] [PATCH v2 3/3] Add support for xz-compressed kernel modules.

Richard W.M. Jones rjones at redhat.com
Mon Aug 19 08:43:39 UTC 2013


From: Joseph Wang <joequant at gmail.com>

RWMJ:

 - Whitespace fixes.

 - Detect static-linked xz.
---
 README        |  2 ++
 configure.ac  | 32 ++++++++++++++++++++
 helper/init.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 126 insertions(+), 1 deletion(-)

diff --git a/README b/README
index 3461d9d..61eb953 100644
--- a/README
+++ b/README
@@ -70,6 +70,8 @@ are building:
 
   zlib (statically linked) - if your kernel uses gzipped modules
 
+  xz (statically linked) - if your kernel uses xz-compressed modules
+
 Building and installing
 -----------------------
 
diff --git a/configure.ac b/configure.ac
index b3144a4..8e3d64d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -133,6 +133,38 @@ if test "x$zlib_static" = "xyes"; then
     AC_SUBST([ZLIB_STATIC_LIBS])
 fi
 
+dnl Support for xzed kernel modules.
+AC_CHECK_HEADER([lzma.h],[
+    AC_CHECK_LIB([lzma],[lzma_code],[
+        AC_MSG_CHECKING([for xz static library])
+        old_CFLAGS="$CFLAGS"
+        old_LDFLAGS="$LDFLAGS"
+        old_LIBS="$LIBS"
+        CFLAGS="$CFLAGS -static"
+        LDFLAGS="$LDFLAGS -static"
+        LIBS="$LIBS -llzma"
+        AC_LINK_IFELSE([
+            #include <stdio.h>
+            #include <stdlib.h>
+            #include <lzma.h>
+            int main () { lzma_stream s = LZMA_STREAM_INIT; exit (s ? 1 : 0); }
+        ],[
+            lzma_static=yes
+            LZMA_STATIC_LIBS="-llzma"
+            AC_MSG_RESULT([yes])
+        ],[
+            AC_MSG_RESULT([no])
+        ])
+        CFLAGS="$old_CFLAGS"
+        LDFLAGS="$old_LDFLAGS"
+        LIBS="$old_LIBS"
+    ])
+])
+if test "x$lzma_static" = "xyes"; then
+    AC_DEFINE([HAVE_LZMA],[1],[Define if you have static lzma])
+    AC_SUBST([LZMA_STATIC_LIBS])
+fi
+
 dnl mke2fs.
 AC_PATH_PROG([MKE2FS],[mke2fs],[no],
              [$PATH$PATH_SEPARATOR/sbin$PATH_SEPARATOR])
diff --git a/helper/init.c b/helper/init.c
index 4c10bff..7f096ec 100644
--- a/helper/init.c
+++ b/helper/init.c
@@ -45,6 +45,10 @@
 #include <zlib.h>
 #endif
 
+#ifdef HAVE_LZMA
+#include <lzma.h>
+#endif
+
 /* Maximum time to wait for the root device to appear (seconds).
  *
  * On slow machines with lots of disks (Koji running the 255 disk test
@@ -100,6 +104,9 @@ main ()
 #ifdef HAVE_ZLIB
            " zlib"
 #endif
+#ifdef HAVE_LZMA
+           " xz"
+#endif
            "\n");
 
   read_cmdline ();
@@ -260,6 +267,20 @@ main ()
   exit (EXIT_FAILURE);
 }
 
+#if HAVE_LZMA
+static int
+ends_with (const char *str, const char *suffix)
+{
+  if (!str || !suffix)
+    return 0;
+  size_t lenstr = strlen (str);
+  size_t lensuffix = strlen (suffix);
+  if (lensuffix >  lenstr)
+    return 0;
+  return strncmp (str + lenstr - lensuffix, suffix, lensuffix) == 0;
+}
+#endif
+
 static void
 insmod (const char *filename)
 {
@@ -269,15 +290,81 @@ insmod (const char *filename)
     fprintf (stderr, "supermin: internal insmod %s\n", filename);
 
 #ifdef HAVE_ZLIB
-  gzFile gzfp = gzopen (filename, "rb");
   int capacity = 64*1024;
   char *buf = (char *) malloc (capacity);
   int tmpsize = 8 * 1024;
   char tmp[tmpsize];
   int num;
 
+  errno = 0;
   size = 0;
 
+#ifdef HAVE_LZMA
+  if (ends_with(filename, ".xz")) {
+    lzma_stream strm = LZMA_STREAM_INIT;
+    lzma_ret ret = lzma_stream_decoder(&strm, UINT64_MAX,
+          LZMA_CONCATENATED);
+    if (verbose)
+      fprintf (stderr, "supermin: running xz\n");
+    FILE *fd = fopen (filename, "r");
+    if (!fd) {
+      perror("popen failed");
+      exit (EXIT_FAILURE);
+    }
+    char tmp_out[tmpsize];
+    strm.avail_in = 0;
+    strm.next_out = tmp_out;
+    strm.avail_out = tmpsize;
+
+    lzma_action action = LZMA_RUN;
+
+    while (1) {
+      if (strm.avail_in == 0) {
+	strm.next_in = tmp;
+	strm.avail_in = fread(tmp, 1, tmpsize, fd);
+
+	if (ferror(fd)) {
+	  // POSIX says that fread() sets errno if
+	  // an error occurred. ferror() doesn't
+	  // touch errno.
+	  perror("Error reading input file");
+	  exit (EXIT_FAILURE);
+	}
+	if (feof(fd)) action = LZMA_FINISH;
+      }
+
+      ret = lzma_code(&strm, action);
+
+      // Write and check write error before checking decoder error.
+      // This way as much data as possible gets written to output
+      // even if decoder detected an error.
+      if (strm.avail_out == 0 || ret != LZMA_OK) {
+          const size_t num =  tmpsize - strm.avail_out;
+          if (num > capacity) {
+	        buf = (char*) realloc (buf, size*2);
+	        capacity = size;
+          }
+          memcpy (buf+size, tmp_out, num);
+          capacity -= num;
+          size += num;
+          strm.next_out = tmp_out;
+          strm.avail_out = tmpsize;
+      }
+      if (ret != LZMA_OK) {
+	if (ret == LZMA_STREAM_END) {
+	    break;
+	} else {
+	 perror("internal error");
+        exit(EXIT_FAILURE);
+	}
+     }
+    }
+    fclose (fd);
+    if (verbose)
+      fprintf (stderr, "done with xz %d read\n", size);
+  } else {
+#endif
+  gzFile gzfp = gzopen (filename, "rb");
   if (gzfp == NULL) {
     fprintf (stderr, "insmod: gzopen failed: %s", filename);
     exit (EXIT_FAILURE);
@@ -296,6 +383,10 @@ insmod (const char *filename)
     exit (EXIT_FAILURE);
   }
   gzclose (gzfp);
+#ifdef HAVE_LZMA
+}
+#endif
+
 #else
   int fd = open (filename, O_RDONLY);
   if (fd == -1) {
-- 
1.8.3.1




More information about the Libguestfs mailing list