]>
git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod.c
2 * libkmod - interface to kernel module operations
4 * Copyright (C) 2011 ProFUSION embedded systems
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.
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.
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
30 #include <sys/utsname.h>
33 #include "libkmod-private.h"
34 #include "libkmod-index.h"
36 #define KMOD_HASH_SIZE (256)
37 #define KMOD_LRU_MAX (128)
41 * @short_description: libkmod context
43 * The context contains the default values for the library user,
44 * and is passed to all library operations.
54 static const char* index_files
[] = {
55 [KMOD_INDEX_DEP
] = "modules.dep",
56 [KMOD_INDEX_ALIAS
] = "modules.alias",
57 [KMOD_INDEX_SYMBOL
] = "modules.symbols",
63 * Opaque object representing the library context.
68 void (*log_fn
)(void *data
,
69 int priority
, const char *file
, int line
,
70 const char *fn
, const char *format
, va_list args
);
74 struct kmod_config
*config
;
75 struct kmod_hash
*modules_by_name
;
76 struct index_mm
*indexes
[_KMOD_INDEX_LAST
];
79 void kmod_log(const struct kmod_ctx
*ctx
,
80 int priority
, const char *file
, int line
, const char *fn
,
81 const char *format
, ...)
85 if (ctx
->log_fn
== NULL
)
88 va_start(args
, format
);
89 ctx
->log_fn(ctx
->log_data
, priority
, file
, line
, fn
, format
, args
);
93 static void log_filep(void *data
,
94 int priority
, const char *file
, int line
,
95 const char *fn
, const char *format
, va_list args
)
98 fprintf(fp
, "libkmod: %s: ", fn
);
99 vfprintf(fp
, format
, args
);
102 const char *kmod_get_dirname(const struct kmod_ctx
*ctx
)
109 * @ctx: kmod library context
111 * Retrieve stored data pointer from library context. This might be useful
112 * to access from callbacks like a custom logging function.
114 * Returns: stored userdata
116 KMOD_EXPORT
void *kmod_get_userdata(const struct kmod_ctx
*ctx
)
120 return (void *)ctx
->userdata
;
125 * @ctx: kmod library context
126 * @userdata: data pointer
128 * Store custom @userdata in the library context.
130 KMOD_EXPORT
void kmod_set_userdata(struct kmod_ctx
*ctx
, const void *userdata
)
134 ctx
->userdata
= userdata
;
137 static int log_priority(const char *priority
)
142 prio
= strtol(priority
, &endptr
, 10);
143 if (endptr
[0] == '\0' || isspace(endptr
[0]))
145 if (strncmp(priority
, "err", 3) == 0)
147 if (strncmp(priority
, "info", 4) == 0)
149 if (strncmp(priority
, "debug", 5) == 0)
154 static const char *dirname_default_prefix
= "/lib/modules";
156 static char *get_kernel_release(const char *dirname
)
162 return strdup(dirname
);
167 if (asprintf(&p
, "%s/%s", dirname_default_prefix
, u
.release
) < 0)
176 * Create kmod library context. This reads the kmod configuration
177 * and fills in the default values.
179 * The initial refcount is 1, and needs to be decremented to
180 * release the resources of the kmod library context.
182 * Returns: a new kmod library context
184 KMOD_EXPORT
struct kmod_ctx
*kmod_new(const char *dirname
)
187 struct kmod_ctx
*ctx
;
190 ctx
= calloc(1, sizeof(struct kmod_ctx
));
195 ctx
->log_fn
= log_filep
;
196 ctx
->log_data
= stderr
;
197 ctx
->log_priority
= LOG_ERR
;
199 ctx
->dirname
= get_kernel_release(dirname
);
201 /* environment overwrites config */
202 env
= getenv("KMOD_LOG");
204 kmod_set_log_priority(ctx
, log_priority(env
));
206 err
= kmod_config_new(ctx
, &ctx
->config
);
208 ERR(ctx
, "could not create config\n");
212 ctx
->modules_by_name
= kmod_hash_new(KMOD_HASH_SIZE
, NULL
);
213 if (ctx
->modules_by_name
== NULL
) {
214 ERR(ctx
, "could not create by-name hash\n");
218 INFO(ctx
, "ctx %p created\n", ctx
);
219 DBG(ctx
, "log_priority=%d\n", ctx
->log_priority
);
224 free(ctx
->modules_by_name
);
232 * @ctx: kmod library context
234 * Take a reference of the kmod library context.
236 * Returns: the passed kmod library context
238 KMOD_EXPORT
struct kmod_ctx
*kmod_ref(struct kmod_ctx
*ctx
)
248 * @ctx: kmod library context
250 * Drop a reference of the kmod library context. If the refcount
251 * reaches zero, the resources of the context will be released.
254 KMOD_EXPORT
struct kmod_ctx
*kmod_unref(struct kmod_ctx
*ctx
)
259 if (--ctx
->refcount
> 0)
262 INFO(ctx
, "context %p released\n", ctx
);
264 kmod_unload_resources(ctx
);
265 kmod_hash_free(ctx
->modules_by_name
);
268 kmod_config_free(ctx
->config
);
276 * @ctx: kmod library context
277 * @log_fn: function to be called for logging messages
279 * The built-in logging writes to stderr. It can be
280 * overridden by a custom function, to plug log messages
281 * into the user's logging functionality.
284 KMOD_EXPORT
void kmod_set_log_fn(struct kmod_ctx
*ctx
,
285 void (*log_fn
)(void *data
,
286 int priority
, const char *file
,
287 int line
, const char *fn
,
288 const char *format
, va_list args
),
293 ctx
->log_fn
= log_fn
;
294 ctx
->log_data
= (void *)data
;
295 INFO(ctx
, "custom logging function %p registered\n", log_fn
);
299 * kmod_get_log_priority:
300 * @ctx: kmod library context
302 * Returns: the current logging priority
304 KMOD_EXPORT
int kmod_get_log_priority(const struct kmod_ctx
*ctx
)
308 return ctx
->log_priority
;
312 * kmod_set_log_priority:
313 * @ctx: kmod library context
314 * @priority: the new logging priority
316 * Set the current logging priority. The value controls which messages
319 KMOD_EXPORT
void kmod_set_log_priority(struct kmod_ctx
*ctx
, int priority
)
323 ctx
->log_priority
= priority
;
326 struct kmod_module
*kmod_pool_get_module(struct kmod_ctx
*ctx
,
329 struct kmod_module
*mod
;
331 mod
= kmod_hash_find(ctx
->modules_by_name
, name
);
333 DBG(ctx
, "get module name='%s' found=%p\n", name
, mod
);
338 void kmod_pool_add_module(struct kmod_ctx
*ctx
, struct kmod_module
*mod
)
340 const char *name
= kmod_module_get_name(mod
);
342 DBG(ctx
, "add %p name='%s'\n", mod
, name
);
344 kmod_hash_add(ctx
->modules_by_name
, name
, mod
);
347 void kmod_pool_del_module(struct kmod_ctx
*ctx
, struct kmod_module
*mod
)
349 const char *name
= kmod_module_get_name(mod
);
351 DBG(ctx
, "del %p name='%s'\n", mod
, name
);
353 kmod_hash_del(ctx
->modules_by_name
, name
);
356 static int kmod_lookup_alias_from_alias_bin(struct kmod_ctx
*ctx
,
357 enum kmod_index index_number
,
359 struct kmod_list
**list
)
362 struct index_file
*idx
;
363 struct index_value
*realnames
, *realname
;
365 if (ctx
->indexes
[index_number
] != NULL
) {
366 DBG(ctx
, "use mmaped index '%s' for name=%s\n",
367 index_files
[index_number
], name
);
368 realnames
= index_mm_searchwild(ctx
->indexes
[index_number
],
373 snprintf(fn
, sizeof(fn
), "%s/%s.bin", ctx
->dirname
,
374 index_files
[index_number
]);
376 DBG(ctx
, "file=%s name=%s\n", fn
, name
);
378 idx
= index_file_open(fn
);
382 realnames
= index_searchwild(idx
, name
);
383 index_file_close(idx
);
386 for (realname
= realnames
; realname
; realname
= realnames
->next
) {
387 struct kmod_module
*mod
;
389 err
= kmod_module_new_from_name(ctx
, realname
->value
, &mod
);
391 ERR(ctx
, "%s\n", strerror(-err
));
395 *list
= kmod_list_append(*list
, mod
);
399 index_values_free(realnames
);
403 *list
= kmod_list_remove_n_latest(*list
, nmatch
);
408 int kmod_lookup_alias_from_symbols_file(struct kmod_ctx
*ctx
, const char *name
,
409 struct kmod_list
**list
)
411 if (!startswith(name
, "symbol:"))
414 return kmod_lookup_alias_from_alias_bin(ctx
, KMOD_INDEX_SYMBOL
, name
,
418 int kmod_lookup_alias_from_aliases_file(struct kmod_ctx
*ctx
, const char *name
,
419 struct kmod_list
**list
)
421 return kmod_lookup_alias_from_alias_bin(ctx
, KMOD_INDEX_ALIAS
, name
,
425 char *kmod_search_moddep(struct kmod_ctx
*ctx
, const char *name
)
427 struct index_file
*idx
;
431 if (ctx
->indexes
[KMOD_INDEX_DEP
]) {
432 DBG(ctx
, "use mmaped index '%s' modname=%s\n",
433 index_files
[KMOD_INDEX_DEP
], name
);
434 return index_mm_search(ctx
->indexes
[KMOD_INDEX_DEP
], name
);
437 snprintf(fn
, sizeof(fn
), "%s/%s.bin", ctx
->dirname
,
438 index_files
[KMOD_INDEX_DEP
]);
440 DBG(ctx
, "file=%s modname=%s\n", fn
, name
);
442 idx
= index_file_open(fn
);
444 ERR(ctx
, "Could not open moddep file '%s'\n", fn
);
448 line
= index_search(idx
, name
);
449 index_file_close(idx
);
454 int kmod_lookup_alias_from_moddep_file(struct kmod_ctx
*ctx
, const char *name
,
455 struct kmod_list
**list
)
461 * Module names do not contain ':'. Return early if we know it will
464 if (strchr(name
, ':'))
467 line
= kmod_search_moddep(ctx
, name
);
469 struct kmod_module
*mod
;
471 n
= kmod_module_new_from_name(ctx
, name
, &mod
);
473 ERR(ctx
, "%s\n", strerror(-n
));
477 *list
= kmod_list_append(*list
, mod
);
478 kmod_module_parse_depline(mod
, line
);
487 int kmod_lookup_alias_from_config(struct kmod_ctx
*ctx
, const char *name
,
488 struct kmod_list
**list
)
490 struct kmod_config
*config
= ctx
->config
;
494 kmod_list_foreach(l
, config
->aliases
) {
495 const char *aliasname
= kmod_alias_get_name(l
);
496 const char *modname
= kmod_alias_get_modname(l
);
498 if (fnmatch(aliasname
, name
, 0) == 0) {
499 struct kmod_module
*mod
;
501 err
= kmod_module_new_from_name(ctx
, modname
, &mod
);
503 ERR(ctx
, "%s\n", strerror(-err
));
507 *list
= kmod_list_append(*list
, mod
);
515 *list
= kmod_list_remove_n_latest(*list
, nmatch
);
520 * kmod_module_get_filtered_blacklist:
521 * @ctx: kmod library context
522 * @input: list to be filtered with blacklist
523 * @output: where to save the new list
525 * Given a list @input, this function filter it out with config's blacklist
526 * ans save it in @output.
528 * Returns: 0 on success or < 0 otherwise. @output is saved with the updated
531 KMOD_EXPORT
int kmod_module_get_filtered_blacklist(const struct kmod_ctx
*ctx
, const struct kmod_list
*input
, struct kmod_list
**output
)
533 const struct kmod_config
*config
;
534 const struct kmod_list
*li
;
536 if (ctx
== NULL
|| output
== NULL
)
543 config
= ctx
->config
;
544 kmod_list_foreach(li
, input
) {
545 struct kmod_module
*mod
= li
->data
;
546 const struct kmod_list
*lb
;
547 struct kmod_list
*node
;
548 bool filtered
= false;
549 kmod_list_foreach(lb
, config
->blacklists
) {
550 const char *name
= lb
->data
;
551 if (streq(name
, kmod_module_get_name(mod
))) {
559 node
= kmod_list_append(*output
, mod
);
563 kmod_module_ref(mod
);
568 kmod_module_unref_list(*output
);
573 KMOD_EXPORT
int kmod_load_resources(struct kmod_ctx
*ctx
)
581 for (i
= 0; i
< ARRAY_SIZE(index_files
); i
++) {
582 if (ctx
->indexes
[i
] == NULL
) {
583 const char *fn
= index_files
[i
];
584 size_t fnlen
= strlen(fn
);
585 const char *prefix
= "";
586 const char *suffix
= "";
589 prefix
= ctx
->dirname
;
591 if (fnlen
< 4 || !streq(fn
+ fnlen
- 4, ".bin"))
594 snprintf(path
, sizeof(path
), "%s/%s%s",
598 ctx
->indexes
[i
] = index_mm_open(ctx
, fn
, true);
599 if (ctx
->indexes
[i
] == NULL
)
607 kmod_unload_resources(ctx
);
611 KMOD_EXPORT
void kmod_unload_resources(struct kmod_ctx
*ctx
)
618 for (i
= 0; i
< ARRAY_SIZE(index_files
); i
++) {
619 if (ctx
->indexes
[i
] != NULL
) {
620 index_mm_close(ctx
->indexes
[i
]);
621 ctx
->indexes
[i
] = NULL
;
626 KMOD_EXPORT
int kmod_resolve_alias_options(struct kmod_ctx
*ctx
, const char *given_alias
, char **options
)
628 struct kmod_list
*modules
= NULL
, *l
;
629 char alias
[NAME_MAX
];
634 if (ctx
== NULL
|| options
== NULL
)
637 modname_normalize(given_alias
, alias
, NULL
);
639 err
= kmod_module_new_from_lookup(ctx
, alias
, &modules
);
641 kmod_list_foreach(l
, modules
) {
642 const char *str
= kmod_module_get_options(l
->data
);
650 tmp
= realloc(opts
, optslen
+ len
+ 2);
658 memcpy(opts
+ optslen
, str
, len
);
660 opts
[optslen
] = '\0';
664 kmod_list_foreach(l
, ctx
->config
->options
) {
665 const struct kmod_list
*ml
;
666 const char *modname
= kmod_option_get_modname(l
);
668 bool already_done
= false;
672 if (fnmatch(modname
, alias
, 0) != 0)
675 kmod_list_foreach(ml
, modules
) {
676 const char *mln
= kmod_module_get_name(ml
->data
);
677 if (fnmatch(modname
, mln
, 0) == 0) {
685 str
= kmod_option_get_options(l
);
687 tmp
= realloc(opts
, optslen
+ len
+ 2);
695 memcpy(opts
+ optslen
, str
, len
);
697 opts
[optslen
] = '\0';
700 DBG(ctx
, "alias=%s options='%s'\n", alias
, opts
);
701 kmod_module_unref_list(modules
);
706 kmod_module_unref_list(modules
);
708 ERR(ctx
, "out of memory\n");
713 const struct kmod_list
*kmod_get_options(const struct kmod_ctx
*ctx
)
715 return ctx
->config
->options
;
718 const struct kmod_list
*kmod_get_install_commands(const struct kmod_ctx
*ctx
)
720 return ctx
->config
->install_commands
;
723 const struct kmod_list
*kmod_get_remove_commands(const struct kmod_ctx
*ctx
)
725 return ctx
->config
->remove_commands
;