Modern distros like Fedora have started to compress their kernel module files, so we can't simply read the file contents and load the module. We have to first do a decompression step, as the kernel won't do that itself. While Fedora uses lzma, upstream kernels are also capable of using gzip. This links in the lzma and gzip libraries to handle decompression. NB the static versions of lzma/gzip are required since libvirt-sandbox-init-qemu must be statically linked. --- configure.ac | 4 + libvirt-sandbox.spec.in | 2 + libvirt-sandbox/Makefile.am | 7 ++ libvirt-sandbox/libvirt-sandbox-builder-initrd.c | 35 +++--- libvirt-sandbox/libvirt-sandbox-init-qemu.c | 143 ++++++++++++++++++++++- 5 files changed, 173 insertions(+), 18 deletions(-) diff --git a/configure.ac b/configure.ac index cd3745a..4f53c94 100644 --- a/configure.ac +++ b/configure.ac @@ -17,6 +17,8 @@ LIBVIRT_GCONFIG_REQUIRED=0.1.8 LIBVIRT_GLIB_REQUIRED=0.1.7 LIBVIRT_GOBJECT_REQUIRED=0.1.7 GOBJECT_INTROSPECTION_REQUIRED=0.10.8 +LZMA_REQUIRED=5.0.0 +ZLIB_REQUIRED=1.2.0 LIBVIRT_SANDBOX_MAJOR_VERSION=`echo $VERSION | awk -F. '{print $1}'` LIBVIRT_SANDBOX_MINOR_VERSION=`echo $VERSION | awk -F. '{print $2}'` @@ -78,6 +80,8 @@ PKG_CHECK_MODULES(LIBVIRT, libvirt >= $LIBVIRT_REQUIRED) PKG_CHECK_MODULES(LIBVIRT_GLIB, libvirt-glib-1.0 >= $LIBVIRT_GOBJECT_REQUIRED) PKG_CHECK_MODULES(LIBVIRT_GOBJECT, libvirt-gobject-1.0 >= $LIBVIRT_GOBJECT_REQUIRED) PKG_CHECK_MODULES(LIBVIRT_GCONFIG, libvirt-gconfig-1.0 >= $LIBVIRT_GCONFIG_REQUIRED) +PKG_CHECK_MODULES(ZLIB, zlib >= $ZLIB_REQUIRED) +PKG_CHECK_MODULES(LZMA, liblzma >= $LZMA_REQUIRED) LIBVIRT_SANDBOX_CAPNG LIBVIRT_SANDBOX_GETTEXT diff --git a/libvirt-sandbox.spec.in b/libvirt-sandbox.spec.in index 7deadb2..1ec6e27 100644 --- a/libvirt-sandbox.spec.in +++ b/libvirt-sandbox.spec.in @@ -27,6 +27,8 @@ BuildRequires: /usr/bin/pod2man BuildRequires: intltool BuildRequires: libselinux-devel BuildRequires: glib2-devel >= 2.32.0 +BuildRequires: xz-devel >= 5.0.0, xz-static +BuildRequires: zlib-devel >= 1.2.0, zlib-static Requires: rpm-python # For virsh lxc-enter-namespace command Requires: libvirt-client >= %{libvirt_version} diff --git a/libvirt-sandbox/Makefile.am b/libvirt-sandbox/Makefile.am index 96302cb..30c9ebf 100644 --- a/libvirt-sandbox/Makefile.am +++ b/libvirt-sandbox/Makefile.am @@ -139,6 +139,7 @@ libvirt_sandbox_1_0_la_CFLAGS = \ -DLOCALEDIR="\"$(datadir)/locale"\" \ $(COVERAGE_CFLAGS) \ -I$(top_srcdir) \ + -I$(top_builddir) \ $(GIO_UNIX_CFLAGS) \ $(LIBVIRT_GLIB_CFLAGS) \ $(LIBVIRT_GOBJECT_CFLAGS) \ @@ -172,6 +173,7 @@ libvirt_sandbox_init_common_CFLAGS = \ -DLOCALEDIR="\"$(datadir)/locale"\" \ $(COVERAGE_CFLAGS) \ -I$(top_srcdir) \ + -I$(top_builddir) \ $(GIO_UNIX_CFLAGS) \ $(LIBVIRT_GLIB_CFLAGS) \ $(LIBVIRT_GOBJECT_CFLAGS) \ @@ -196,6 +198,7 @@ libvirt_sandbox_init_lxc_CFLAGS = \ -DLIBEXECDIR="\"$(libexecdir)\"" \ -DSANDBOXCONFIGDIR="\"$(sandboxconfigdir)\"" \ -I$(top_srcdir) \ + -I$(top_builddir) \ $(GIO_UNIX_CFLAGS) \ $(LIBVIRT_GLIB_CFLAGS) \ $(LIBVIRT_GOBJECT_CFLAGS) \ @@ -217,11 +220,15 @@ libvirt_sandbox_init_qemu_SOURCES = libvirt-sandbox-init-qemu.c libvirt_sandbox_init_qemu_CFLAGS = \ -DLIBEXECDIR="\"$(libexecdir)\"" \ -DSANDBOXCONFIGDIR="\"$(sandboxconfigdir)\"" \ + $(ZLIB_CFLAGS) \ + $(LZMA_CFLAGS) \ $(WARN_CFLAGS) \ $(NULL) libvirt_sandbox_init_qemu_LDFLAGS = \ -all-static \ $(COVERAGE_CFLAGS:-f%=-Wc,f%) \ + $(ZLIB_LIBS) \ + $(LZMA_LIBS) \ $(WARN_CFLAGS) \ $(NULL) diff --git a/libvirt-sandbox/libvirt-sandbox-builder-initrd.c b/libvirt-sandbox/libvirt-sandbox-builder-initrd.c index 95f05e2..59a03e6 100644 --- a/libvirt-sandbox/libvirt-sandbox-builder-initrd.c +++ b/libvirt-sandbox/libvirt-sandbox-builder-initrd.c @@ -232,7 +232,7 @@ static GList *gvir_sandbox_builder_initrd_find_files(GList *modnames, if (strstr(thisname, ".ko")) { GList *tmp = modnames; while (tmp) { - if (g_str_equal(thisname, tmp->data)) { + if (g_str_has_prefix(thisname, tmp->data)) { modfiles = g_list_append(modfiles, child); child = NULL; } @@ -293,7 +293,7 @@ static GList *gvir_sandbox_builder_initrd_find_files(GList *modnames, if (strstr(de->d_name, ".ko")) { GList *tmp = modnames; while (tmp) { - if (g_str_equal(de->d_name, tmp->data)) { + if (g_str_has_prefix(de->d_name, tmp->data)) { modfiles = g_list_append(modfiles, child); child = NULL; } @@ -366,7 +366,6 @@ static gboolean gvir_sandbox_builder_initrd_populate_tmpdir(const gchar *tmpdir, GFile *modlist = NULL; gchar *modlistpath = NULL; GOutputStream *modlistos = NULL; - GError *e = NULL; if (!gvir_sandbox_builder_initrd_copy_file( gvir_sandbox_config_initrd_get_init(config), @@ -374,11 +373,9 @@ static gboolean gvir_sandbox_builder_initrd_populate_tmpdir(const gchar *tmpdir, return FALSE; modnames = gvir_sandbox_config_initrd_get_modules(config); - modfiles = gvir_sandbox_builder_initrd_find_modules(modnames, config, &e); - if (e) { - g_propagate_error(error, e); + modfiles = gvir_sandbox_builder_initrd_find_modules(modnames, config, error); + if (*error) goto cleanup; - } tmp = modfiles; while (tmp) { @@ -404,14 +401,22 @@ static gboolean gvir_sandbox_builder_initrd_populate_tmpdir(const gchar *tmpdir, tmp = modnames; while (tmp) { - if (!g_output_stream_write_all(modlistos, - tmp->data, strlen(tmp->data), - NULL, NULL, error)) - goto cleanup; - if (!g_output_stream_write_all(modlistos, - "\n", 1, - NULL, NULL, error)) - goto cleanup; + GList *files = modfiles; + while (files) { + const gchar *basename = g_file_get_basename(files->data); + if (g_str_has_prefix(basename, tmp->data)) { + if (!g_output_stream_write_all(modlistos, + basename, strlen(basename), + NULL, NULL, error)) + goto cleanup; + if (!g_output_stream_write_all(modlistos, + "\n", 1, + NULL, NULL, error)) + goto cleanup; + break; + } + files = files->next; + } tmp = tmp->next; } diff --git a/libvirt-sandbox/libvirt-sandbox-init-qemu.c b/libvirt-sandbox/libvirt-sandbox-init-qemu.c index 750c9de..2c2c803 100644 --- a/libvirt-sandbox/libvirt-sandbox-init-qemu.c +++ b/libvirt-sandbox/libvirt-sandbox-init-qemu.c @@ -42,6 +42,8 @@ #include <fcntl.h> #include <sys/reboot.h> #include <termios.h> +#include <lzma.h> +#include <zlib.h> #define ATTR_UNUSED __attribute__((__unused__)) @@ -481,15 +483,150 @@ static char *readall(const char *filename, size_t *len) return data; } + +static int +has_suffix(const char *filename, const char *ext) +{ + char *offset = strstr(filename, ext); + return (offset && + offset[strlen(ext)] == '\0'); +} + +static char * +load_module_file_lzma(const char *filename, size_t *len) +{ + lzma_stream st = LZMA_STREAM_INIT; + char *xzdata; + size_t xzlen; + char *data; + lzma_ret ret; + + *len = 0; + + if (debug) + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, filename); + + if ((ret = lzma_stream_decoder(&st, UINT64_MAX, + LZMA_CONCATENATED)) != LZMA_OK) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s: lzma init failure: %d\n", + __func__, filename, ret); + exit_poweroff(); + } + xzdata = readall(filename, &xzlen); + + st.next_in = (unsigned char *)xzdata; + st.avail_in = xzlen; + + *len = 32 * 1024; + if (!(data = malloc(*len))) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, strerror(errno)); + exit_poweroff(); + } + + st.next_out = (unsigned char *)data; + st.avail_out = *len; + + do { + ret = lzma_code(&st, LZMA_FINISH); + if (st.avail_out == 0) { + size_t used = *len; + *len += (32 * 1024); + if (!(data = realloc(data, *len))) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, strerror(errno)); + exit_poweroff(); + } + st.next_out = (unsigned char *)data + used; + st.avail_out = *len - used; + } + if (ret != LZMA_OK && ret != LZMA_STREAM_END) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s: lzma decode failure: %d\n", + __func__, filename, ret); + exit_poweroff(); + } + } while (ret != LZMA_STREAM_END); + lzma_end(&st); + free(xzdata); + return data; +} + +static char * +load_module_file_zlib(const char *filename, size_t *len) +{ + gzFile fp; + char *data; + unsigned int avail; + size_t total; + int got; + + if (debug) + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, filename); + + if (!(fp = gzopen(filename, "rb"))) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s: gzopen failure\n", + __func__, filename); + exit_poweroff(); + } + + *len = 32 * 1024; + if (!(data = malloc(*len))) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, strerror(errno)); + exit_poweroff(); + } + + avail = *len; + total = 0; + + do { + got = gzread(fp, data + total, avail); + + if (got < 0) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s: gzread failure\n", + __func__, filename); + exit_poweroff(); + } + + total += got; + if (total >= *len) { + *len += (32 * 1024); + if (!(data = realloc(data, *len))) { + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, strerror(errno)); + exit_poweroff(); + } + avail = *len - total; + } + } while (got > 0); + + gzclose(fp); + return data; +} + +static char * +load_module_file_raw(const char *filename, size_t *len) +{ + if (debug) + fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, filename); + return readall(filename, len); +} + +static char * +load_module_file(const char *filename, size_t *len) +{ + if (has_suffix(filename, ".ko.xz")) + return load_module_file_lzma(filename, len); + else if (has_suffix(filename, ".ko.gz")) + return load_module_file_zlib(filename, len); + else + return load_module_file_raw(filename, len); +} + + static void insmod(const char *filename) { char *data; size_t len; - if (debug) - fprintf(stderr, "libvirt-sandbox-init-qemu: %s: %s\n", __func__, filename); - data = readall(filename, &len); + data = load_module_file(filename, &len); if (init_module(data, (unsigned long)len, "") < 0) { const char *msg; -- 2.4.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list