diff options
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | configure.ac | 42 | ||||
-rw-r--r-- | libkmod/libkmod-file.c | 163 | ||||
-rw-r--r-- | libkmod/libkmod-module.c | 23 | ||||
-rw-r--r-- | libkmod/libkmod-private.h | 6 | ||||
-rw-r--r-- | libkmod/libkmod.pc.in | 2 |
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 @@ -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} |