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 next commit). --- 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