implement zlib module loading.
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Fri, 16 Dec 2011 18:08:53 +0000 (16:08 -0200)
committerLucas De Marchi <lucas.demarchi@profusion.mobi>
Sat, 17 Dec 2011 21:43:11 +0000 (19:43 -0200)
Makefile.am
TODO
configure.ac
libkmod/libkmod-file.c [new file with mode: 0644]
libkmod/libkmod-module.c
libkmod/libkmod-private.h
libkmod/libkmod.pc.in

index 214f773..ca27139 100644 (file)
@@ -36,7 +36,8 @@ libkmod_libkmod_la_SOURCES =\
        libkmod/libkmod-util.c \
        libkmod/libkmod-index.c \
        libkmod/libkmod-index.h \
-       libkmod/libkmod-module.c
+       libkmod/libkmod-module.c \
+       libkmod/libkmod-file.c
 
 EXTRA_DIST += libkmod/libkmod.sym
 EXTRA_DIST += libkmod/COPYING libkmod/README
@@ -45,6 +46,7 @@ libkmod_libkmod_la_LDFLAGS = $(AM_LDFLAGS) \
        -version-info $(LIBKMOD_CURRENT):$(LIBKMOD_REVISION):$(LIBKMOD_AGE) \
        -Wl,--version-script=$(top_srcdir)/libkmod/libkmod.sym
 libkmod_libkmod_la_DEPENDENCIES = ${top_srcdir}/libkmod/libkmod.sym
+libkmod_libkmod_la_LIBADD = @zlib_libs@
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libkmod/libkmod.pc
diff --git a/TODO b/TODO
index 76ce804..8ace999 100644 (file)
--- a/TODO
+++ b/TODO
@@ -26,8 +26,6 @@ Features:
    - install and remove commands may exist when there's no module with that
      name. Properly handle this case
 
-* gzip support for modprobe
-
 Known Bugs:
 ===========
 
index b992188..b3bb218 100644 (file)
@@ -23,6 +23,8 @@ AC_C_TYPEOF
 AM_PROG_CC_C_O
 AC_PROG_GCC_TRADITIONAL
 
+required_private_libs=""
+
 AC_ARG_ENABLE([tools],
         AS_HELP_STRING([--disable-tools], [disable building tools that provide same functionality as module-init-tools @<:@default=enabled@:>@]),
        [], enable_tools=yes)
@@ -35,6 +37,43 @@ AS_IF([test "x$enable_logging" = "xyes"], [
        AC_DEFINE(ENABLE_LOGGING, [1], [System logging.])
 ])
 
+AC_ARG_ENABLE([zlib],
+        AS_HELP_STRING([--enable-zlib], [handle gzipped modules (options: static or dynamic) @<:@default=disabled@:>@]),
+       [], enable_zlib=no)
+if test "x$enable_zlib" = "xyes" -o "x$enable_zlib" = "xstatic"; then
+        enable_zlib="static"
+        zlib_libs="-Wl,-Bstatic -lz -Wl,-Bdynamic"
+        SAVE_LIBS="${LIBS}"
+        LIBS="${LIBS} ${zlib_libs}"
+        AC_MSG_CHECKING([if static zlib exists])
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+                #include <zlib.h>
+        ]], [[
+                gzFile f = gzopen("/tmp", "rb");
+        ]])],
+        [have_zlib=yes], [have_zlib=no])
+        LIBS="${SAVE_LIBS}"
+        AC_MSG_RESULT([$have_zlib])
+        if test "x$have_zlib" != "xyes"; then
+                zlib_libs=""
+                AC_MSG_ERROR([static zlib is not present])
+        fi
+elif test "x$enable_zlib" = "xdynamic"; then
+        AC_CHECK_LIB([z], [gzopen],
+                [
+                        zlib_libs="-lz"
+                        required_private_libs="${required_private_libs} ${zlib_libs}"
+                ],
+                [AC_MSG_ERROR([dynamic zlib is not present])])
+else
+        AC_MSG_NOTICE([zlib support not requested])
+        zlib_libs=""
+fi
+if test "x$zlib_libs" != "x"; then
+        AC_DEFINE(ENABLE_ZLIB, [1], [Enable zlib for modules.])
+fi
+AC_SUBST(zlib_libs)
+
 AC_ARG_ENABLE([debug],
        AS_HELP_STRING([--enable-debug], [enable debug messages @<:@default=disabled@:>@]),
        [], [enable_debug=no])
@@ -92,6 +131,8 @@ CC_CHECK_CFLAGS_APPEND([ \
                        -Wl,--gc-sections])
 
 
+AC_SUBST(required_private_libs)
+
 AC_CONFIG_HEADERS(config.h)
 AC_CONFIG_FILES([
        Makefile
@@ -115,5 +156,6 @@ AC_MSG_RESULT([
 
        tools:                  ${enable_tools}
        logging:                ${enable_logging}
+        zlib:                   ${enable_zlib}
        debug:                  ${enable_debug}
 ])
diff --git a/libkmod/libkmod-file.c b/libkmod/libkmod-file.c
new file mode 100644 (file)
index 0000000..13add12
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * libkmod - interface to kernel module operations
+ *
+ * Copyright (C) 2011  ProFUSION embedded systems
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "libkmod.h"
+#include "libkmod-private.h"
+
+#ifdef ENABLE_ZLIB
+#include <zlib.h>
+#endif
+
+struct kmod_file {
+#ifdef ENABLE_ZLIB
+       gzFile gzf;
+#else
+       int fd;
+#endif
+       off_t size;
+       void *memory;
+};
+
+#ifdef ENABLE_ZLIB
+#define READ_STEP (4 * 1024 * 1024)
+static int zlip_file_open(struct kmod_file *file, const char *filename)
+{
+       int err = 0;
+       off_t did = 0, total = 0;
+       unsigned char *p = NULL;
+
+       errno = 0;
+       file->gzf = gzopen(filename, "rbe");
+       if (file->gzf == NULL)
+               return -errno;
+
+       for (;;) {
+               int r;
+
+               if (did == total) {
+                       void *tmp = realloc(p, total + READ_STEP);
+                       if (tmp == NULL) {
+                               err = -errno;
+                               goto error;
+                       }
+                       total += READ_STEP;
+                       p = tmp;
+               }
+
+               r = gzread(file->gzf, p + did, total - did);
+               if (r == 0)
+                       break;
+               else if (r < 0) {
+                       err = -errno;
+                       goto error;
+               }
+               did += r;
+       }
+
+       file->memory = p;
+       file->size = did;
+       return 0;
+error:
+       free(p);
+       gzclose(file->gzf);
+       return err;
+}
+#else
+static int reg_file_open(struct kmod_file *file, const char *filename)
+{
+       struct stat st;
+       int err = 0;
+
+       file->fd = open(filename, O_RDONLY|O_CLOEXEC);
+       if (file->fd < 0)
+               return -errno;
+
+       if (fstat(file->fd, &st) < 0) {
+               err = -errno;
+               goto error;
+       }
+
+       file->size = st.st_size;
+       file->memory = mmap(0, file->size, PROT_READ, MAP_PRIVATE, file->fd, 0);
+       if (file->memory == MAP_FAILED) {
+               err = -errno;
+               goto error;
+       }
+
+       return 0;
+error:
+       close(file->fd);
+       return err;
+}
+#endif
+
+struct kmod_file *kmod_file_open(const char *filename)
+{
+       struct kmod_file *file = calloc(1, sizeof(struct kmod_file));
+       int err;
+
+       if (file == NULL)
+               return NULL;
+
+#ifdef ENABLE_ZLIB
+       err = zlip_file_open(file, filename);
+#else
+       err = reg_file_open(file, filename);
+#endif
+
+       if (err < 0) {
+               free(file);
+               errno = -err;
+               return NULL;
+       }
+
+       return file;
+}
+
+void *kmod_file_get_contents(const struct kmod_file *file)
+{
+       return file->memory;
+}
+
+off_t kmod_file_get_size(const struct kmod_file *file)
+{
+       return file->size;
+}
+
+void kmod_file_unref(struct kmod_file *file)
+{
+#ifdef ENABLE_ZLIB
+       free(file->memory);
+       gzclose(file->gzf);
+#else
+       munmap(file->memory, file->size);
+       close(file->fd);
+#endif
+       free(file);
+}
index dd340ee..e6388f2 100644 (file)
@@ -693,9 +693,9 @@ KMOD_EXPORT int kmod_module_insert_module(struct kmod_module *mod,
                                                        const char *options)
 {
        int err;
-       void *mmaped_file;
-       struct stat st;
-       int fd;
+       void *mem;
+       off_t size;
+       struct kmod_file *file;
        const char *args = options ? options : "";
 
        if (mod == NULL)
@@ -709,25 +709,20 @@ KMOD_EXPORT int kmod_module_insert_module(struct kmod_module *mod,
        if (flags != 0)
                INFO(mod->ctx, "Flags are not implemented yet\n");
 
-       if ((fd = open(mod->path, O_RDONLY|O_CLOEXEC)) < 0) {
+       file = kmod_file_open(mod->path);
+       if (file == NULL) {
                err = -errno;
                return err;
        }
 
-       fstat(fd, &st);
-
-       if ((mmaped_file = mmap(0, st.st_size, PROT_READ,
-                                       MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
-               close(fd);
-               return -errno;
-       }
+       size = kmod_file_get_size(file);
+       mem = kmod_file_get_contents(file);
 
-       err = init_module(mmaped_file, st.st_size, args);
+       err = init_module(mem, size, args);
        if (err < 0)
                ERR(mod->ctx, "Failed to insert module '%s'\n", mod->path);
 
-       munmap(mmaped_file, st.st_size);
-       close(fd);
+       kmod_file_unref(file);
 
        return err;
 }
index c992129..b9a93d2 100644 (file)
@@ -121,6 +121,12 @@ int kmod_hash_add(struct kmod_hash *hash, const char *key, const void *value);
 int kmod_hash_del(struct kmod_hash *hash, const char *key);
 void *kmod_hash_find(const struct kmod_hash *hash, const char *key);
 
+/* libkmod-file.c */
+struct kmod_file *kmod_file_open(const char *filename) __must_check __attribute__((nonnull(1)));
+void *kmod_file_get_contents(const struct kmod_file *file) __must_check __attribute__((nonnull(1)));
+off_t kmod_file_get_size(const struct kmod_file *file) __must_check __attribute__((nonnull(1)));
+void kmod_file_unref(struct kmod_file *file) __attribute__((nonnull(1)));
+
 
 /* util functions */
 char *getline_wrapped(FILE *fp, unsigned int *linenum) __attribute__((nonnull(1)));
index b02e74a..b28b7c5 100644 (file)
@@ -7,5 +7,5 @@ Name: libkmod
 Description: Library to deal with kernel modules
 Version: @VERSION@
 Libs: -L${libdir} -lkmod
-Libs.private:
+Libs.private: @required_private_libs@
 Cflags: -I${includedir}