On Tue, 2015-06-16 at 12:25 +0100, Daniel P. Berrange wrote: > 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) Would be great to have some check for the presence of the static libs we need here. rkeene pointed to this example doing similar thing: http://kitcreator.rkeene.org/fossil/info/b344f06840acf86cbd6b6fdc1bd45dd649db9ad2?ln=113-154 Even if not in this commit, would be good to have later. ACK for the rest. -- Cedric > 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; -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list