/* * 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 version 2.1. * * 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 #include #include #include #include #include #include #include #include #include "libkmod.h" #include "libkmod-private.h" /** * SECTION:libkmod * @short_description: libkmod context * * The context contains the default values for the library user, * and is passed to all library operations. */ /** * kmod_ctx: * * Opaque object representing the library context. */ struct kmod_ctx { int refcount; void (*log_fn)(struct kmod_ctx *ctx, int priority, const char *file, int line, const char *fn, const char *format, va_list args); void *userdata; const char *dirname; int log_priority; struct kmod_config config; }; void kmod_log(struct kmod_ctx *ctx, int priority, const char *file, int line, const char *fn, const char *format, ...) { va_list args; va_start(args, format); ctx->log_fn(ctx, priority, file, line, fn, format, args); va_end(args); } static void log_stderr(struct kmod_ctx *ctx, int priority, const char *file, int line, const char *fn, const char *format, va_list args) { fprintf(stderr, "libkmod: %s: ", fn); vfprintf(stderr, format, args); } const char *kmod_get_dirname(struct kmod_ctx *ctx) { return ctx->dirname; } /** * kmod_get_userdata: * @ctx: kmod library context * * Retrieve stored data pointer from library context. This might be useful * to access from callbacks like a custom logging function. * * Returns: stored userdata **/ KMOD_EXPORT void *kmod_get_userdata(const struct kmod_ctx *ctx) { if (ctx == NULL) return NULL; return ctx->userdata; } /** * kmod_set_userdata: * @ctx: kmod library context * @userdata: data pointer * * Store custom @userdata in the library context. **/ KMOD_EXPORT void kmod_set_userdata(struct kmod_ctx *ctx, void *userdata) { if (ctx == NULL) return; ctx->userdata = userdata; } static int log_priority(const char *priority) { char *endptr; int prio; prio = strtol(priority, &endptr, 10); if (endptr[0] == '\0' || isspace(endptr[0])) return prio; if (strncmp(priority, "err", 3) == 0) return LOG_ERR; if (strncmp(priority, "info", 4) == 0) return LOG_INFO; if (strncmp(priority, "debug", 5) == 0) return LOG_DEBUG; return 0; } static const char *get_kernel_release(void) { struct utsname u; if (uname(&u) < 0) return NULL; return strdup(u.release); } /** * kmod_new: * * Create kmod library context. This reads the kmod configuration * and fills in the default values. * * The initial refcount is 1, and needs to be decremented to * release the resources of the kmod library context. * * Returns: a new kmod library context **/ KMOD_EXPORT struct kmod_ctx *kmod_new(const char *dirname) { const char *env; struct kmod_ctx *ctx; ctx = calloc(1, sizeof(struct kmod_ctx)); if (!ctx) return NULL; ctx->refcount = 1; ctx->log_fn = log_stderr; ctx->log_priority = LOG_ERR; if (dirname != NULL) ctx->dirname = strdup(dirname); else ctx->dirname = get_kernel_release(); /* environment overwrites config */ env = getenv("KMOD_LOG"); if (env != NULL) kmod_set_log_priority(ctx, log_priority(env)); kmod_parse_config(ctx, &ctx->config); INFO(ctx, "ctx %p created\n", ctx); DBG(ctx, "log_priority=%d\n", ctx->log_priority); return ctx; } /** * kmod_ref: * @ctx: kmod library context * * Take a reference of the kmod library context. * * Returns: the passed kmod library context **/ KMOD_EXPORT struct kmod_ctx *kmod_ref(struct kmod_ctx *ctx) { if (ctx == NULL) return NULL; ctx->refcount++; return ctx; } /** * kmod_unref: * @ctx: kmod library context * * Drop a reference of the kmod library context. If the refcount * reaches zero, the resources of the context will be released. * **/ KMOD_EXPORT struct kmod_ctx *kmod_unref(struct kmod_ctx *ctx) { if (ctx == NULL) return NULL; if (--ctx->refcount > 0) return ctx; INFO(ctx, "context %p released\n", ctx); free((char *)ctx->dirname); kmod_free_config(ctx, &ctx->config); free(ctx); return NULL; } /** * kmod_set_log_fn: * @ctx: kmod library context * @log_fn: function to be called for logging messages * * The built-in logging writes to stderr. It can be * overridden by a custom function, to plug log messages * into the user's logging functionality. * **/ KMOD_EXPORT void kmod_set_log_fn(struct kmod_ctx *ctx, void (*log_fn)(struct kmod_ctx *ctx, int priority, const char *file, int line, const char *fn, const char *format, va_list args)) { ctx->log_fn = log_fn; INFO(ctx, "custom logging function %p registered\n", log_fn); } /** * kmod_get_log_priority: * @ctx: kmod library context * * Returns: the current logging priority **/ KMOD_EXPORT int kmod_get_log_priority(const struct kmod_ctx *ctx) { return ctx->log_priority; } /** * kmod_set_log_priority: * @ctx: kmod library context * @priority: the new logging priority * * Set the current logging priority. The value controls which messages * are logged. **/ KMOD_EXPORT void kmod_set_log_priority(struct kmod_ctx *ctx, int priority) { ctx->log_priority = priority; }