[Libguestfs] [PATCH supermin v2 1/4] init: Uncompress modules before adding them to the mini initrd.

Richard W.M. Jones rjones at redhat.com
Wed Feb 17 14:22:31 UTC 2016


When building the mini initrd, previously we copied the modules into
the initrd as-is, so for example if the module was xz-compressed, we
copied the foo.ko.xz file to the initrd.  This requires that the mini
init binary is linked to zlib & lzma, so that it knows how to
uncompress these modules when insmoding them at boot time.  Also since
the init is statically linked, it required _static_ versions of these
libraries.

This changes things so that the modules are uncompressed in the mini
initrd, so they are a little bit larger, but the init binary no longer
needs to be statically linked to zlib & lzma.

The init binary is smaller (966K -> 837K), but because we are storing
uncompressed modules in the mini initrd, the initrd as a whole becomes
larger (1.4M -> 2.6M)

However there are benefits to this change:

 - The code in the init binary is much simpler.

 - Removes the dependency on static zlib & lzma.

 - We can use an alternate libc to make a much smaller init binary
   (see following commits).
---
 README             |   4 +-
 configure.ac       |  74 ++-------------------------
 src/Makefile.am    |   1 -
 src/config.ml.in   |   2 +
 src/ext2_initrd.ml |  28 ++++++++++-
 src/init.c         | 145 -----------------------------------------------------
 6 files changed, 34 insertions(+), 220 deletions(-)

diff --git a/README b/README
index 34949a2..56a28f6 100644
--- a/README
+++ b/README
@@ -97,9 +97,9 @@ are building:
   qemu >= 0.13
   kernel >= 2.6.36
 
-  zlib (statically linked) - if your kernel uses gzipped modules
+  gunzip (command) - if your kernel uses gzipped modules
 
-  xz (statically linked) - if your kernel uses xz-compressed modules
+  unxz (command) - if your kernel uses xz-compressed modules
 
 Building and installing
 -----------------------
diff --git a/configure.ac b/configure.ac
index 126366b..0fe88c7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -127,77 +127,11 @@ dnl Check for fakeroot, only used a few drivers where the host package
 dnl manager contains broken/unnecessary tests for root privs.
 AC_PATH_PROG(FAKEROOT,[fakeroot],[no])
 
-dnl Support for compressed input files, gzipped kernel modules.
-AC_CHECK_HEADER([zlib.h],[
-    AC_CHECK_LIB([z],[gzopen],[
-        zlib=yes
-        ZLIB_LIBS=-lz
+dnl Check for gunzip, only needed if you have gzip-compressed kernel modules.
+AC_PATH_PROG(GUNZIP,[gunzip],[no])
 
-        AC_MSG_CHECKING([for gzip static library])
-        old_CFLAGS="$CFLAGS"
-        old_LDFLAGS="$LDFLAGS"
-        old_LIBS="$LIBS"
-        CFLAGS="$CFLAGS -static"
-        LDFLAGS="$LDFLAGS -static"
-        LIBS="$LIBS -lz"
-        AC_LINK_IFELSE([
-            #include <stdio.h>
-            #include <stdlib.h>
-            #include <zlib.h>
-            int main () { gzFile g = gzopen ("test", "rb"); exit (g ? 1 : 0); }
-        ],[
-            zlib_static=yes
-            ZLIB_STATIC_LIBS="$ZLIB_LIBS"
-            AC_MSG_RESULT([yes])
-        ],[
-            AC_MSG_RESULT([no])
-        ])
-        CFLAGS="$old_CFLAGS"
-        LDFLAGS="$old_LDFLAGS"
-        LIBS="$old_LIBS"
-    ])
-])
-if test "x$zlib" = "xyes"; then
-    AC_DEFINE([HAVE_ZLIB],[1],[Define if you have zlib])
-    AC_SUBST([ZLIB_LIBS])
-fi
-if test "x$zlib_static" = "xyes"; then
-    AC_DEFINE([HAVE_ZLIB_STATIC],[1],[Define if you have static zlib])
-    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.next_in == NULL ? 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_STATIC],[1],[Define if you have static lzma])
-    AC_SUBST([LZMA_STATIC_LIBS])
-fi
+dnl Check for unxz, only needed if you have xz-compressed kernel modules.
+AC_PATH_PROG(UNXZ,[unxz],[no])
 
 dnl mke2fs.
 AC_PATH_PROG([MKE2FS],[mke2fs],[no],
diff --git a/src/Makefile.am b/src/Makefile.am
index 6261c86..5a601fe 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -143,7 +143,6 @@ noinst_PROGRAMS = init
 init_SOURCES = init.c
 init_CFLAGS = -static
 init_LDFLAGS = -static
-init_LDADD = $(ZLIB_STATIC_LIBS) $(LZMA_STATIC_LIBS)
 
 CLEANFILES += ext2init-bin.S
 
diff --git a/src/config.ml.in b/src/config.ml.in
index 42cf833..19545b6 100644
--- a/src/config.ml.in
+++ b/src/config.ml.in
@@ -29,12 +29,14 @@ let dpkg_deb = "@DPKG_DEB@"
 let dpkg_query = "@DPKG_QUERY@"
 let dpkg_divert = "@DPKG_DIVERT@"
 let fakeroot = "@FAKEROOT@"
+let gunzip = "@GUNZIP@"
 let makepkg = "@MAKEPKG@"
 let pacman = "@PACMAN@"
 let pactree = "@PACTREE@"
 let pacman_g2 = "@PACMAN_G2@"
 let rpm = "@RPM@"
 let rpm2cpio = "@RPM2CPIO@"
+let unxz = "@UNXZ@"
 let urpmi = "@URPMI@"
 let yumdownloader = "@YUMDOWNLOADER@"
 let zypper = "@ZYPPER@"
diff --git a/src/ext2_initrd.ml b/src/ext2_initrd.ml
index b34f0e6..e49a19d 100644
--- a/src/ext2_initrd.ml
+++ b/src/ext2_initrd.ml
@@ -1,5 +1,5 @@
 (* supermin 5
- * Copyright (C) 2009-2014 Red Hat Inc.
+ * Copyright (C) 2009-2016 Red Hat Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -105,8 +105,32 @@ let rec build_initrd debug tmpdir modpath initrd =
             sprintf "cp -t %s %s" (quote initdir) (quote (modpath // modl)) in
           run_command cmd;
 
+          (* Uncompress the module, if the name ends in .xz or .gz. *)
+          let basename = Filename.basename modl in
+          let basename =
+            let len = String.length basename in
+            if Config.unxz <> "no" && Filename.check_suffix basename ".xz"
+            then (
+              let cmd = sprintf "%s %s"
+                                (quote Config.unxz)
+                                (quote (initdir // basename)) in
+              run_command cmd;
+              String.sub basename 0 (len-3)
+            )
+            else if Config.gunzip <> "no" &&
+                      Filename.check_suffix basename ".gz"
+            then (
+              let cmd = sprintf "%s %s"
+                                (quote Config.gunzip)
+                                (quote (initdir // basename)) in
+              run_command cmd;
+              String.sub basename 0 (len-3)
+            )
+            else
+              basename in
+
           (* Write module name to 'modules' file. *)
-          fprintf chan "%s\n" (Filename.basename modl);
+          fprintf chan "%s\n" basename;
           incr loaded
         )
     ) set
diff --git a/src/init.c b/src/init.c
index 814243a..25d6bc6 100644
--- a/src/init.c
+++ b/src/init.c
@@ -42,14 +42,6 @@
 
 #include <asm/unistd.h>
 
-#ifdef HAVE_ZLIB_STATIC
-#include <zlib.h>
-#endif
-
-#ifdef HAVE_LZMA_STATIC
-#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
@@ -102,12 +94,6 @@ main ()
   print_uptime ();
   fprintf (stderr, "supermin: ext2 mini initrd starting up: "
            PACKAGE_VERSION
-#ifdef HAVE_ZLIB_STATIC
-           " zlib"
-#endif
-#ifdef HAVE_LZMA_STATIC
-           " xz"
-#endif
            "\n");
 
   read_cmdline ();
@@ -283,20 +269,6 @@ main ()
   exit (EXIT_FAILURE);
 }
 
-#if HAVE_LZMA_STATIC
-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)
 {
@@ -305,118 +277,6 @@ insmod (const char *filename)
   if (verbose)
     fprintf (stderr, "supermin: internal insmod %s\n", filename);
 
-#ifdef HAVE_ZLIB_STATIC
-  int capacity = 64*1024;
-  char *buf = (char *) malloc (capacity);
-  int tmpsize = 8 * 1024;
-  char tmp[tmpsize];
-  int num;
-
-  errno = 0;
-  size = 0;
-
-  if (!buf) {
-    perror("malloc");
-    exit (EXIT_FAILURE);
-  }
-
-#ifdef HAVE_LZMA_STATIC
-  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);
-               if (!buf) {
-                    perror("realloc");
-                    exit (EXIT_FAILURE);
-               }
-               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);
-  }
-  while ((num = gzread (gzfp, tmp, tmpsize)) > 0) {
-    if (num > capacity) {
-      buf = (char*) realloc (buf, size*2);
-      if (!buf) {
-        perror("realloc");
-        exit (EXIT_FAILURE);
-      }
-      capacity = size;
-    }
-    memcpy (buf+size, tmp, num);
-    capacity -= num;
-    size += num;
-  }
-  if (num == -1) {
-    perror ("insmod: gzread");
-    exit (EXIT_FAILURE);
-  }
-  gzclose (gzfp);
-#ifdef HAVE_LZMA_STATIC
-}
-#endif
-
-#else
   int fd = open (filename, O_RDONLY);
   if (fd == -1) {
     fprintf (stderr, "insmod: open: %s: %m\n", filename);
@@ -439,7 +299,6 @@ insmod (const char *filename)
     offset += rc;
   } while (offset < size);
   close (fd);
-#endif
 
   if (init_module (buf, size, "") != 0) {
     fprintf (stderr, "insmod: init_module: %s: %s\n", filename, moderror (errno));
@@ -447,10 +306,6 @@ insmod (const char *filename)
      * of a missing device.
      */
   }
-
-#ifdef HAVE_ZLIB_STATIC
-  free (buf);
-#endif
 }
 
 /* Mount /proc unless it's mounted already. */
-- 
2.5.0




More information about the Libguestfs mailing list