]> git.ipfire.org Git - thirdparty/kmod.git/blame - libkmod/libkmod.c
Add startswith() helper function
[thirdparty/kmod.git] / libkmod / libkmod.c
CommitLineData
ecd40ee4 1/*
586fc304
LDM
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011 ProFUSION embedded systems
586fc304
LDM
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation version 2.1.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
ecd40ee4
LDM
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <stddef.h>
23#include <stdarg.h>
24#include <unistd.h>
25#include <errno.h>
7f3eb0cc 26#include <fnmatch.h>
ecd40ee4
LDM
27#include <string.h>
28#include <ctype.h>
221631d5 29#include <sys/utsname.h>
ecd40ee4 30
586fc304
LDM
31#include "libkmod.h"
32#include "libkmod-private.h"
ecd40ee4
LDM
33
34/**
586fc304
LDM
35 * SECTION:libkmod
36 * @short_description: libkmod context
ecd40ee4
LDM
37 *
38 * The context contains the default values for the library user,
39 * and is passed to all library operations.
40 */
41
42/**
586fc304 43 * kmod_ctx:
ecd40ee4
LDM
44 *
45 * Opaque object representing the library context.
46 */
586fc304 47struct kmod_ctx {
ecd40ee4 48 int refcount;
586fc304 49 void (*log_fn)(struct kmod_ctx *ctx,
e4351b05
LDM
50 int priority, const char *file, int line,
51 const char *fn, const char *format, va_list args);
ecd40ee4 52 void *userdata;
221631d5 53 const char *dirname;
ecd40ee4 54 int log_priority;
7c2ab358 55 struct kmod_config config;
ecd40ee4
LDM
56};
57
586fc304 58void kmod_log(struct kmod_ctx *ctx,
e4351b05
LDM
59 int priority, const char *file, int line, const char *fn,
60 const char *format, ...)
ecd40ee4
LDM
61{
62 va_list args;
63
64 va_start(args, format);
65 ctx->log_fn(ctx, priority, file, line, fn, format, args);
66 va_end(args);
67}
68
586fc304 69static void log_stderr(struct kmod_ctx *ctx,
e4351b05
LDM
70 int priority, const char *file, int line,
71 const char *fn, const char *format, va_list args)
ecd40ee4 72{
586fc304 73 fprintf(stderr, "libkmod: %s: ", fn);
ecd40ee4
LDM
74 vfprintf(stderr, format, args);
75}
76
221631d5
LDM
77const char *kmod_get_dirname(struct kmod_ctx *ctx)
78{
79 return ctx->dirname;
80}
81
ecd40ee4 82/**
586fc304
LDM
83 * kmod_get_userdata:
84 * @ctx: kmod library context
ecd40ee4
LDM
85 *
86 * Retrieve stored data pointer from library context. This might be useful
87 * to access from callbacks like a custom logging function.
88 *
89 * Returns: stored userdata
90 **/
6d177553 91KMOD_EXPORT void *kmod_get_userdata(const struct kmod_ctx *ctx)
ecd40ee4
LDM
92{
93 if (ctx == NULL)
94 return NULL;
95 return ctx->userdata;
96}
97
98/**
586fc304
LDM
99 * kmod_set_userdata:
100 * @ctx: kmod library context
ecd40ee4
LDM
101 * @userdata: data pointer
102 *
103 * Store custom @userdata in the library context.
104 **/
586fc304 105KMOD_EXPORT void kmod_set_userdata(struct kmod_ctx *ctx, void *userdata)
ecd40ee4
LDM
106{
107 if (ctx == NULL)
108 return;
109 ctx->userdata = userdata;
110}
111
112static int log_priority(const char *priority)
113{
114 char *endptr;
115 int prio;
116
117 prio = strtol(priority, &endptr, 10);
118 if (endptr[0] == '\0' || isspace(endptr[0]))
119 return prio;
120 if (strncmp(priority, "err", 3) == 0)
121 return LOG_ERR;
122 if (strncmp(priority, "info", 4) == 0)
123 return LOG_INFO;
124 if (strncmp(priority, "debug", 5) == 0)
125 return LOG_DEBUG;
126 return 0;
127}
128
221631d5
LDM
129static const char *get_kernel_release(void)
130{
131 struct utsname u;
132
133 if (uname(&u) < 0)
134 return NULL;
135
136 return strdup(u.release);
137}
138
ecd40ee4 139/**
586fc304 140 * kmod_new:
ecd40ee4 141 *
586fc304 142 * Create kmod library context. This reads the kmod configuration
ecd40ee4
LDM
143 * and fills in the default values.
144 *
145 * The initial refcount is 1, and needs to be decremented to
586fc304 146 * release the resources of the kmod library context.
ecd40ee4 147 *
586fc304 148 * Returns: a new kmod library context
ecd40ee4 149 **/
221631d5 150KMOD_EXPORT struct kmod_ctx *kmod_new(const char *dirname)
ecd40ee4
LDM
151{
152 const char *env;
52a7704f 153 struct kmod_ctx *ctx;
ecd40ee4 154
52a7704f
LDM
155 ctx = calloc(1, sizeof(struct kmod_ctx));
156 if (!ctx)
157 return NULL;
ecd40ee4 158
52a7704f
LDM
159 ctx->refcount = 1;
160 ctx->log_fn = log_stderr;
161 ctx->log_priority = LOG_ERR;
ecd40ee4 162
221631d5
LDM
163 if (dirname != NULL)
164 ctx->dirname = strdup(dirname);
165 else
166 ctx->dirname = get_kernel_release();
167
ecd40ee4 168 /* environment overwrites config */
586fc304 169 env = getenv("KMOD_LOG");
ecd40ee4 170 if (env != NULL)
52a7704f 171 kmod_set_log_priority(ctx, log_priority(env));
ecd40ee4 172
7c2ab358
LDM
173 kmod_parse_config(ctx, &ctx->config);
174
ae6df84a
LDM
175 INFO(ctx, "ctx %p created\n", ctx);
176 DBG(ctx, "log_priority=%d\n", ctx->log_priority);
52a7704f
LDM
177
178 return ctx;
ecd40ee4
LDM
179}
180
181/**
586fc304
LDM
182 * kmod_ref:
183 * @ctx: kmod library context
ecd40ee4 184 *
586fc304 185 * Take a reference of the kmod library context.
ecd40ee4 186 *
586fc304 187 * Returns: the passed kmod library context
ecd40ee4 188 **/
586fc304 189KMOD_EXPORT struct kmod_ctx *kmod_ref(struct kmod_ctx *ctx)
ecd40ee4
LDM
190{
191 if (ctx == NULL)
192 return NULL;
193 ctx->refcount++;
194 return ctx;
195}
196
197/**
586fc304
LDM
198 * kmod_unref:
199 * @ctx: kmod library context
ecd40ee4 200 *
586fc304 201 * Drop a reference of the kmod library context. If the refcount
ecd40ee4
LDM
202 * reaches zero, the resources of the context will be released.
203 *
204 **/
586fc304 205KMOD_EXPORT struct kmod_ctx *kmod_unref(struct kmod_ctx *ctx)
ecd40ee4
LDM
206{
207 if (ctx == NULL)
208 return NULL;
4d1e689a
LDM
209
210 if (--ctx->refcount > 0)
ecd40ee4 211 return ctx;
ae6df84a 212 INFO(ctx, "context %p released\n", ctx);
221631d5 213 free((char *)ctx->dirname);
7c2ab358 214 kmod_free_config(ctx, &ctx->config);
ecd40ee4
LDM
215 free(ctx);
216 return NULL;
217}
218
219/**
586fc304
LDM
220 * kmod_set_log_fn:
221 * @ctx: kmod library context
ecd40ee4
LDM
222 * @log_fn: function to be called for logging messages
223 *
224 * The built-in logging writes to stderr. It can be
225 * overridden by a custom function, to plug log messages
226 * into the user's logging functionality.
227 *
228 **/
586fc304 229KMOD_EXPORT void kmod_set_log_fn(struct kmod_ctx *ctx,
e4351b05
LDM
230 void (*log_fn)(struct kmod_ctx *ctx,
231 int priority, const char *file,
232 int line, const char *fn,
233 const char *format, va_list args))
ecd40ee4
LDM
234{
235 ctx->log_fn = log_fn;
ae6df84a 236 INFO(ctx, "custom logging function %p registered\n", log_fn);
ecd40ee4
LDM
237}
238
239/**
586fc304
LDM
240 * kmod_get_log_priority:
241 * @ctx: kmod library context
ecd40ee4
LDM
242 *
243 * Returns: the current logging priority
244 **/
6d177553 245KMOD_EXPORT int kmod_get_log_priority(const struct kmod_ctx *ctx)
ecd40ee4
LDM
246{
247 return ctx->log_priority;
248}
249
250/**
586fc304
LDM
251 * kmod_set_log_priority:
252 * @ctx: kmod library context
ecd40ee4
LDM
253 * @priority: the new logging priority
254 *
255 * Set the current logging priority. The value controls which messages
256 * are logged.
257 **/
586fc304 258KMOD_EXPORT void kmod_set_log_priority(struct kmod_ctx *ctx, int priority)
ecd40ee4
LDM
259{
260 ctx->log_priority = priority;
261}
7f3eb0cc
LDM
262
263int kmod_lookup_alias_from_config(struct kmod_ctx *ctx, const char *name,
264 struct kmod_list **list)
265{
266 struct kmod_config *config = &ctx->config;
267 struct kmod_list *l;
268 int err;
269
270 kmod_list_foreach(l, config->aliases) {
271 const char *aliasname = kmod_alias_get_name(l);
272 const char *modname = kmod_alias_get_modname(l);
273
274 if (fnmatch(aliasname, name, 0) == 0) {
275 struct kmod_module *mod;
276
277 err = kmod_module_new_from_name(ctx, modname, &mod);
278 if (err < 0) {
279 ERR(ctx, "%s", strerror(-err));
280 return err;
281 }
282
283 *list = kmod_list_append(*list, mod);
284 }
285 }
286
287 return 0;
288}