helper/init: Handle compressed modules transparently.
authorErik Nolte <erik_nolte@acm.org>
Thu, 6 Oct 2011 20:31:37 +0000 (14:31 -0600)
committerRichard W.M. Jones <rjones@redhat.com>
Fri, 14 Oct 2011 09:57:46 +0000 (10:57 +0100)
Detect libz and, if present, define HAS_LIBZ and add -lz to Makefile's
LIBS variable.

Add entry on optional zlib package requirement.

Detect both uncompressed and gzipped kernel modules.

Some Linux distros (like ArchLinux) use gzipped kernel modules with
filenames like ext2.ko.gz.  This change modifies the filename pattern
from (e.g.) "ext2.ko" to "ext2.ko*".

When available, use libz to read the module.

The init_module system call requires uncompressed kernel module bytes.
On some systems (e.g. ArchLinux) the modules are gzipped on disk.
Libz is used to read and uncompress gzipped disk files (*.ko.gz) or
transparently read uncompressed modules (*.ko).

README
configure.ac
helper/ext2initrd.c
helper/init.c

diff --git a/README b/README
index 99c4d36..2c42b2e 100644 (file)
--- a/README
+++ b/README
@@ -59,6 +59,8 @@ are building:
   qemu >= 0.13
   kernel >= 2.6.36
 
+  zlib - if your kernel uses gzipped modules
+
 Building and installing
 -----------------------
 
index 23c876b..dca5032 100644 (file)
@@ -86,6 +86,9 @@ AC_SUBST([APT_CACHE_DEPENDS_RECURSE_BROKEN])
 dnl For ArchLinux handler.
 AC_CHECK_PROG(PACMAN,[pacman],[pacman],[no])
 
+dnl Support for gzipped kernel modules.
+AC_CHECK_LIB([z],[gzopen])
+
 dnl Required programs, libraries.
 AC_PATH_PROG([MKE2FS],[mke2fs],[no],
              [$PATH$PATH_SEPARATOR/sbin$PATH_SEPARATOR])
index c4fc353..bb00c72 100644 (file)
@@ -52,21 +52,21 @@ extern char _binary_init_start, _binary_init_end, _binary_init_size;
  * ext2 filesystem on it.
  */
 static const char *kmods[] = {
-  "ext2.ko",
-  "ext4.ko", /* CONFIG_EXT4_USE_FOR_EXT23=y option might be set */
-  "virtio*.ko",
-  "ide*.ko",
-  "libata*.ko",
-  "piix*.ko",
-  "scsi_transport_spi.ko",
-  "scsi_mod.ko",
-  "sd_mod.ko",
-  "sym53c8xx.ko",
-  "ata_piix.ko",
-  "sr_mod.ko",
-  "mbcache.ko",
-  "crc*.ko",
-  "libcrc*.ko",
+  "ext2.ko*",
+  "ext4.ko*", /* CONFIG_EXT4_USE_FOR_EXT23=y option might be set */
+  "virtio*.ko*",
+  "ide*.ko*",
+  "libata*.ko*",
+  "piix*.ko*",
+  "scsi_transport_spi.ko*",
+  "scsi_mod.ko*",
+  "sd_mod.ko*",
+  "sym53c8xx.ko*",
+  "ata_piix.ko*",
+  "sr_mod.ko*",
+  "mbcache.ko*",
+  "crc*.ko*",
+  "libcrc*.ko*",
   NULL
 };
 
index 34a8450..447df8e 100644 (file)
 
 #include <asm/unistd.h>
 
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
 extern long init_module (void *, unsigned long, const char *);
 
 /* translation taken from module-init-tools/insmod.c  */
@@ -201,9 +205,40 @@ main ()
 static void
 insmod (const char *filename)
 {
+  size_t size;
+
   if (verbose)
     fprintf (stderr, "febootstrap: internal insmod %s\n", filename);
 
+#ifdef HAVE_LIBZ
+  gzFile gzfp = gzopen (filename, "rb");
+  int capacity = 64*1024;
+  char *buf = (char *) malloc (capacity);
+  int tmpsize = 8 * 1024;
+  char tmp[tmpsize];
+  int num;
+
+  size = 0;
+
+  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);
+      capacity = size;
+    }
+    memcpy (buf+size, tmp, num);
+    capacity -= num;
+    size += num;
+  }
+  if (num == -1) {
+    perror ("insmod: gzread");
+    exit (EXIT_FAILURE);
+  }
+  gzclose (gzfp);
+#else
   int fd = open (filename, O_RDONLY);
   if (fd == -1) {
     fprintf (stderr, "insmod: open: %s: %m\n", filename);
@@ -214,24 +249,30 @@ insmod (const char *filename)
     perror ("insmod: fstat");
     exit (EXIT_FAILURE);
   }
-  char buf[st.st_size];
-  long offset = 0;
+  size = st.st_size;
+  char buf[size];
+  size_t offset = 0;
   do {
-    long rc = read (fd, buf + offset, st.st_size - offset);
+    ssize_t rc = read (fd, buf + offset, size - offset);
     if (rc == -1) {
       perror ("insmod: read");
       exit (EXIT_FAILURE);
     }
     offset += rc;
-  } while (offset < st.st_size);
+  } while (offset < size);
   close (fd);
+#endif
 
-  if (init_module (buf, st.st_size, "") != 0) {
+  if (init_module (buf, size, "") != 0) {
     fprintf (stderr, "insmod: init_module: %s: %s\n", filename, moderror (errno));
     /* However ignore the error because this can just happen because
      * of a missing device.
      */
   }
+
+#ifdef HAVE_LIBZ
+  free (buf);
+#endif
 }
 
 /* Mount /proc unless it's mounted already. */