summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am4
-rw-r--r--TODO2
-rw-r--r--configure.ac42
-rw-r--r--libkmod/libkmod-file.c163
-rw-r--r--libkmod/libkmod-module.c23
-rw-r--r--libkmod/libkmod-private.h6
-rw-r--r--libkmod/libkmod.pc.in2
7 files changed, 224 insertions, 18 deletions
diff --git a/Makefile.am b/Makefile.am
index 214f773..ca27139 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
--- 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:
===========
diff --git a/configure.ac b/configure.ac
index b992188..b3bb218 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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
index 0000000..13add12
--- /dev/null
+++ b/libkmod/libkmod-file.c
@@ -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);
+}
diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c
index dd340ee..e6388f2 100644
--- a/libkmod/libkmod-module.c
+++ b/libkmod/libkmod-module.c
@@ -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;
}
diff --git a/libkmod/libkmod-private.h b/libkmod/libkmod-private.h
index c992129..b9a93d2 100644
--- a/libkmod/libkmod-private.h
+++ b/libkmod/libkmod-private.h
@@ -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)));
diff --git a/libkmod/libkmod.pc.in b/libkmod/libkmod.pc.in
index b02e74a..b28b7c5 100644
--- a/libkmod/libkmod.pc.in
+++ b/libkmod/libkmod.pc.in
@@ -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}