From: Joseph Wang <joequant(a)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