]> git.ipfire.org Git - thirdparty/kmod.git/blame - libkmod/libkmod.c
Clean 'no previous prototype' warning
[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"
9ba6f57b 33#include "libkmod-index.h"
ecd40ee4
LDM
34
35/**
586fc304
LDM
36 * SECTION:libkmod
37 * @short_description: libkmod context
ecd40ee4
LDM
38 *
39 * The context contains the default values for the library user,
40 * and is passed to all library operations.
41 */
42
43/**
586fc304 44 * kmod_ctx:
ecd40ee4
LDM
45 *
46 * Opaque object representing the library context.
47 */
586fc304 48struct kmod_ctx {
ecd40ee4 49 int refcount;
586fc304 50 void (*log_fn)(struct kmod_ctx *ctx,
e4351b05
LDM
51 int priority, const char *file, int line,
52 const char *fn, const char *format, va_list args);
ecd40ee4 53 void *userdata;
221631d5 54 const char *dirname;
ecd40ee4 55 int log_priority;
7c2ab358 56 struct kmod_config config;
ecd40ee4
LDM
57};
58
586fc304 59void kmod_log(struct kmod_ctx *ctx,
e4351b05
LDM
60 int priority, const char *file, int line, const char *fn,
61 const char *format, ...)
ecd40ee4
LDM
62{
63 va_list args;
64
65 va_start(args, format);
66 ctx->log_fn(ctx, priority, file, line, fn, format, args);
67 va_end(args);
68}
69
586fc304 70static void log_stderr(struct kmod_ctx *ctx,
e4351b05
LDM
71 int priority, const char *file, int line,
72 const char *fn, const char *format, va_list args)
ecd40ee4 73{
586fc304 74 fprintf(stderr, "libkmod: %s: ", fn);
ecd40ee4
LDM
75 vfprintf(stderr, format, args);
76}
77
221631d5
LDM
78const char *kmod_get_dirname(struct kmod_ctx *ctx)
79{
80 return ctx->dirname;
81}
82
ecd40ee4 83/**
586fc304
LDM
84 * kmod_get_userdata:
85 * @ctx: kmod library context
ecd40ee4
LDM
86 *
87 * Retrieve stored data pointer from library context. This might be useful
88 * to access from callbacks like a custom logging function.
89 *
90 * Returns: stored userdata
91 **/
6d177553 92KMOD_EXPORT void *kmod_get_userdata(const struct kmod_ctx *ctx)
ecd40ee4
LDM
93{
94 if (ctx == NULL)
95 return NULL;
96 return ctx->userdata;
97}
98
99/**
586fc304
LDM
100 * kmod_set_userdata:
101 * @ctx: kmod library context
ecd40ee4
LDM
102 * @userdata: data pointer
103 *
104 * Store custom @userdata in the library context.
105 **/
586fc304 106KMOD_EXPORT void kmod_set_userdata(struct kmod_ctx *ctx, void *userdata)
ecd40ee4
LDM
107{
108 if (ctx == NULL)
109 return;
110 ctx->userdata = userdata;
111}
112
113static int log_priority(const char *priority)
114{
115 char *endptr;
116 int prio;
117
118 prio = strtol(priority, &endptr, 10);
119 if (endptr[0] == '\0' || isspace(endptr[0]))
120 return prio;
121 if (strncmp(priority, "err", 3) == 0)
122 return LOG_ERR;
123 if (strncmp(priority, "info", 4) == 0)
124 return LOG_INFO;
125 if (strncmp(priority, "debug", 5) == 0)
126 return LOG_DEBUG;
127 return 0;
128}
129
904c63aa
LDM
130static const char *dirname_default_prefix = "/lib/modules";
131
132static const char *get_kernel_release(const char *dirname)
221631d5
LDM
133{
134 struct utsname u;
904c63aa
LDM
135 char *p;
136
137 if (dirname != NULL)
138 return strdup(dirname);
221631d5
LDM
139
140 if (uname(&u) < 0)
141 return NULL;
142
904c63aa
LDM
143 if (asprintf(&p, "%s/%s", dirname_default_prefix, u.release) < 0)
144 return NULL;
145
146 return p;
221631d5
LDM
147}
148
ecd40ee4 149/**
586fc304 150 * kmod_new:
ecd40ee4 151 *
586fc304 152 * Create kmod library context. This reads the kmod configuration
ecd40ee4
LDM
153 * and fills in the default values.
154 *
155 * The initial refcount is 1, and needs to be decremented to
586fc304 156 * release the resources of the kmod library context.
ecd40ee4 157 *
586fc304 158 * Returns: a new kmod library context
ecd40ee4 159 **/
221631d5 160KMOD_EXPORT struct kmod_ctx *kmod_new(const char *dirname)
ecd40ee4
LDM
161{
162 const char *env;
52a7704f 163 struct kmod_ctx *ctx;
ecd40ee4 164
52a7704f
LDM
165 ctx = calloc(1, sizeof(struct kmod_ctx));
166 if (!ctx)
167 return NULL;
ecd40ee4 168
52a7704f
LDM
169 ctx->refcount = 1;
170 ctx->log_fn = log_stderr;
171 ctx->log_priority = LOG_ERR;
ecd40ee4 172
904c63aa 173 ctx->dirname = get_kernel_release(dirname);
221631d5 174
ecd40ee4 175 /* environment overwrites config */
586fc304 176 env = getenv("KMOD_LOG");
ecd40ee4 177 if (env != NULL)
52a7704f 178 kmod_set_log_priority(ctx, log_priority(env));
ecd40ee4 179
7c2ab358
LDM
180 kmod_parse_config(ctx, &ctx->config);
181
ae6df84a
LDM
182 INFO(ctx, "ctx %p created\n", ctx);
183 DBG(ctx, "log_priority=%d\n", ctx->log_priority);
52a7704f
LDM
184
185 return ctx;
ecd40ee4
LDM
186}
187
188/**
586fc304
LDM
189 * kmod_ref:
190 * @ctx: kmod library context
ecd40ee4 191 *
586fc304 192 * Take a reference of the kmod library context.
ecd40ee4 193 *
586fc304 194 * Returns: the passed kmod library context
ecd40ee4 195 **/
586fc304 196KMOD_EXPORT struct kmod_ctx *kmod_ref(struct kmod_ctx *ctx)
ecd40ee4
LDM
197{
198 if (ctx == NULL)
199 return NULL;
200 ctx->refcount++;
201 return ctx;
202}
203
204/**
586fc304
LDM
205 * kmod_unref:
206 * @ctx: kmod library context
ecd40ee4 207 *
586fc304 208 * Drop a reference of the kmod library context. If the refcount
ecd40ee4
LDM
209 * reaches zero, the resources of the context will be released.
210 *
211 **/
586fc304 212KMOD_EXPORT struct kmod_ctx *kmod_unref(struct kmod_ctx *ctx)
ecd40ee4
LDM
213{
214 if (ctx == NULL)
215 return NULL;
4d1e689a
LDM
216
217 if (--ctx->refcount > 0)
ecd40ee4 218 return ctx;
ae6df84a 219 INFO(ctx, "context %p released\n", ctx);
221631d5 220 free((char *)ctx->dirname);
7c2ab358 221 kmod_free_config(ctx, &ctx->config);
ecd40ee4
LDM
222 free(ctx);
223 return NULL;
224}
225
226/**
586fc304
LDM
227 * kmod_set_log_fn:
228 * @ctx: kmod library context
ecd40ee4
LDM
229 * @log_fn: function to be called for logging messages
230 *
231 * The built-in logging writes to stderr. It can be
232 * overridden by a custom function, to plug log messages
233 * into the user's logging functionality.
234 *
235 **/
586fc304 236KMOD_EXPORT void kmod_set_log_fn(struct kmod_ctx *ctx,
e4351b05
LDM
237 void (*log_fn)(struct kmod_ctx *ctx,
238 int priority, const char *file,
239 int line, const char *fn,
240 const char *format, va_list args))
ecd40ee4
LDM
241{
242 ctx->log_fn = log_fn;
ae6df84a 243 INFO(ctx, "custom logging function %p registered\n", log_fn);
ecd40ee4
LDM
244}
245
246/**
586fc304
LDM
247 * kmod_get_log_priority:
248 * @ctx: kmod library context
ecd40ee4
LDM
249 *
250 * Returns: the current logging priority
251 **/
6d177553 252KMOD_EXPORT int kmod_get_log_priority(const struct kmod_ctx *ctx)
ecd40ee4
LDM
253{
254 return ctx->log_priority;
255}
256
257/**
586fc304
LDM
258 * kmod_set_log_priority:
259 * @ctx: kmod library context
ecd40ee4
LDM
260 * @priority: the new logging priority
261 *
262 * Set the current logging priority. The value controls which messages
263 * are logged.
264 **/
586fc304 265KMOD_EXPORT void kmod_set_log_priority(struct kmod_ctx *ctx, int priority)
ecd40ee4
LDM
266{
267 ctx->log_priority = priority;
268}
7f3eb0cc 269
9ba6f57b 270
a009482c
LDM
271static int kmod_lookup_alias_from_alias_bin(struct kmod_ctx *ctx,
272 const char *file,
7b30f4f4 273 const char *name,
9ba6f57b
LDM
274 struct kmod_list **list)
275{
276 char *fn;
23fc91c6 277 int err, nmatch = 0, i;
9ba6f57b
LDM
278 struct index_file *index;
279 struct index_value *realnames, *realname;
23fc91c6 280 struct kmod_list *l;
9ba6f57b 281
7b30f4f4 282 if (asprintf(&fn, "%s/%s.bin", ctx->dirname, file) < 0)
9ba6f57b
LDM
283 return -ENOMEM;
284
e915f92a 285 DBG(ctx, "file=%s name=%s\n", fn, name);
9ba6f57b
LDM
286
287 index = index_file_open(fn);
288 if (index == NULL) {
289 free(fn);
290 return -ENOSYS;
291 }
292
293 realnames = index_searchwild(index, name);
294 for (realname = realnames; realname; realname = realnames->next) {
295 struct kmod_module *mod;
296
297 err = kmod_module_new_from_name(ctx, realname->value, &mod);
298 if (err < 0) {
299 ERR(ctx, "%s\n", strerror(-err));
23fc91c6 300 goto fail;
9ba6f57b
LDM
301 }
302
303 *list = kmod_list_append(*list, mod);
23fc91c6 304 nmatch++;
9ba6f57b
LDM
305 }
306
9ba6f57b
LDM
307 index_values_free(realnames);
308 index_file_close(index);
309 free(fn);
310
23fc91c6
LDM
311 return nmatch;
312
313fail:
314 *list = kmod_list_remove_n_latest(*list, nmatch);
9ba6f57b 315 return err;
7b30f4f4
LDM
316
317}
318
319static const char *symbols_file = "modules.symbols";
320
321int kmod_lookup_alias_from_symbols_file(struct kmod_ctx *ctx, const char *name,
322 struct kmod_list **list)
323{
324 if (!startswith(name, "symbol:"))
325 return 0;
326
327 return kmod_lookup_alias_from_alias_bin(ctx, symbols_file, name, list);
9ba6f57b
LDM
328}
329
49e61ca3
LDM
330
331static const char *aliases_file = "modules.alias";
332
333int kmod_lookup_alias_from_aliases_file(struct kmod_ctx *ctx, const char *name,
334 struct kmod_list **list)
335{
336 return kmod_lookup_alias_from_alias_bin(ctx, aliases_file, name, list);
337}
338
64700e47
LDM
339static const char *moddep_file = "modules.dep";
340
341int kmod_lookup_alias_from_moddep_file(struct kmod_ctx *ctx, const char *name,
342 struct kmod_list **list)
343{
344 char *fn, *line, *p;
345 struct index_file *index;
346 int n = 0;
347
348 /*
349 * Module names do not contain ':'. Return early if we know it will
350 * not be found.
351 */
352 if (strchr(name, ':'))
353 return 0;
354
355 if (asprintf(&fn, "%s/%s.bin", ctx->dirname, moddep_file) < 0)
356 return -ENOMEM;
357
e915f92a 358 DBG(ctx, "file=%s modname=%s\n", fn, name);
64700e47
LDM
359
360 index = index_file_open(fn);
361 if (index == NULL) {
362 free(fn);
363 return -ENOSYS;
364 }
365
366 line = index_search(index, name);
367 if (line != NULL) {
368 struct kmod_module *mod;
369
370 n = kmod_module_new_from_name(ctx, name, &mod);
371 if (n < 0) {
372 ERR(ctx, "%s\n", strerror(-n));
373 goto finish;
374 }
375
376 *list = kmod_list_append(*list, mod);
4a3eb3a4 377 kmod_module_parse_dep(mod, line);
64700e47
LDM
378 }
379
380finish:
381 free(line);
382 index_file_close(index);
383 free(fn);
384
385 return n;
386}
387
7f3eb0cc
LDM
388int kmod_lookup_alias_from_config(struct kmod_ctx *ctx, const char *name,
389 struct kmod_list **list)
390{
391 struct kmod_config *config = &ctx->config;
392 struct kmod_list *l;
23fc91c6 393 int err, nmatch = 0;
7f3eb0cc
LDM
394
395 kmod_list_foreach(l, config->aliases) {
396 const char *aliasname = kmod_alias_get_name(l);
397 const char *modname = kmod_alias_get_modname(l);
398
399 if (fnmatch(aliasname, name, 0) == 0) {
400 struct kmod_module *mod;
401
402 err = kmod_module_new_from_name(ctx, modname, &mod);
403 if (err < 0) {
404 ERR(ctx, "%s", strerror(-err));
23fc91c6 405 goto fail;
7f3eb0cc
LDM
406 }
407
408 *list = kmod_list_append(*list, mod);
23fc91c6 409 nmatch++;
7f3eb0cc
LDM
410 }
411 }
412
23fc91c6
LDM
413 return nmatch;
414
415fail:
416 *list = kmod_list_remove_n_latest(*list, nmatch);
417 return err;
7f3eb0cc 418}