]> git.ipfire.org Git - thirdparty/kmod.git/blame - libkmod/libkmod.c
Merge branch 'use-mmap'
[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>
1eb2ef69 24#include <limits.h>
ecd40ee4
LDM
25#include <unistd.h>
26#include <errno.h>
7f3eb0cc 27#include <fnmatch.h>
ecd40ee4
LDM
28#include <string.h>
29#include <ctype.h>
221631d5 30#include <sys/utsname.h>
ecd40ee4 31
586fc304
LDM
32#include "libkmod.h"
33#include "libkmod-private.h"
9ba6f57b 34#include "libkmod-index.h"
ecd40ee4 35
fd186ae9
LDM
36#define KMOD_HASH_SIZE (256)
37#define KMOD_LRU_MAX (128)
38
ecd40ee4 39/**
586fc304
LDM
40 * SECTION:libkmod
41 * @short_description: libkmod context
ecd40ee4
LDM
42 *
43 * The context contains the default values for the library user,
44 * and is passed to all library operations.
45 */
46
a4a75029
LDM
47enum kmod_index {
48 KMOD_INDEX_DEP = 0,
49 KMOD_INDEX_ALIAS,
50 KMOD_INDEX_SYMBOL,
51 _KMOD_INDEX_LAST,
52};
53
54static const char* index_files[] = {
55 [KMOD_INDEX_DEP] = "modules.dep",
56 [KMOD_INDEX_ALIAS] = "modules.alias",
57 [KMOD_INDEX_SYMBOL] = "modules.symbols",
58};
59
cb8d4d3e
GSB
60static const char *default_config_paths[] = {
61 "/run/modprobe.d",
62 "/etc/modprobe.d",
63 "/lib/modprobe.d",
64 NULL
65};
66
ecd40ee4 67/**
586fc304 68 * kmod_ctx:
ecd40ee4
LDM
69 *
70 * Opaque object representing the library context.
71 */
586fc304 72struct kmod_ctx {
ecd40ee4 73 int refcount;
8d3f3ef8 74 int log_priority;
1bdd951e 75 void (*log_fn)(void *data,
e4351b05
LDM
76 int priority, const char *file, int line,
77 const char *fn, const char *format, va_list args);
1bdd951e 78 void *log_data;
1ce08a56
GSB
79 const void *userdata;
80 char *dirname;
d13e606f 81 struct kmod_config *config;
fd186ae9 82 struct kmod_hash *modules_by_name;
33bb69b9 83 struct index_mm *indexes[_KMOD_INDEX_LAST];
ecd40ee4
LDM
84};
85
1bdd951e 86void kmod_log(const struct kmod_ctx *ctx,
e4351b05
LDM
87 int priority, const char *file, int line, const char *fn,
88 const char *format, ...)
ecd40ee4
LDM
89{
90 va_list args;
91
e5c60f1c
GSB
92 if (ctx->log_fn == NULL)
93 return;
94
ecd40ee4 95 va_start(args, format);
1bdd951e 96 ctx->log_fn(ctx->log_data, priority, file, line, fn, format, args);
ecd40ee4
LDM
97 va_end(args);
98}
99
1bdd951e 100static void log_filep(void *data,
e4351b05
LDM
101 int priority, const char *file, int line,
102 const char *fn, const char *format, va_list args)
ecd40ee4 103{
1bdd951e
GSB
104 FILE *fp = data;
105 fprintf(fp, "libkmod: %s: ", fn);
106 vfprintf(fp, format, args);
ecd40ee4
LDM
107}
108
1ce08a56 109const char *kmod_get_dirname(const struct kmod_ctx *ctx)
221631d5
LDM
110{
111 return ctx->dirname;
112}
113
ecd40ee4 114/**
586fc304
LDM
115 * kmod_get_userdata:
116 * @ctx: kmod library context
ecd40ee4
LDM
117 *
118 * Retrieve stored data pointer from library context. This might be useful
119 * to access from callbacks like a custom logging function.
120 *
121 * Returns: stored userdata
54ba8b34 122 */
6d177553 123KMOD_EXPORT void *kmod_get_userdata(const struct kmod_ctx *ctx)
ecd40ee4
LDM
124{
125 if (ctx == NULL)
126 return NULL;
1ce08a56 127 return (void *)ctx->userdata;
ecd40ee4
LDM
128}
129
130/**
586fc304
LDM
131 * kmod_set_userdata:
132 * @ctx: kmod library context
ecd40ee4
LDM
133 * @userdata: data pointer
134 *
135 * Store custom @userdata in the library context.
54ba8b34 136 */
1ce08a56 137KMOD_EXPORT void kmod_set_userdata(struct kmod_ctx *ctx, const void *userdata)
ecd40ee4
LDM
138{
139 if (ctx == NULL)
140 return;
141 ctx->userdata = userdata;
142}
143
144static int log_priority(const char *priority)
145{
146 char *endptr;
147 int prio;
148
149 prio = strtol(priority, &endptr, 10);
150 if (endptr[0] == '\0' || isspace(endptr[0]))
151 return prio;
152 if (strncmp(priority, "err", 3) == 0)
153 return LOG_ERR;
154 if (strncmp(priority, "info", 4) == 0)
155 return LOG_INFO;
156 if (strncmp(priority, "debug", 5) == 0)
157 return LOG_DEBUG;
158 return 0;
159}
160
904c63aa
LDM
161static const char *dirname_default_prefix = "/lib/modules";
162
1ce08a56 163static char *get_kernel_release(const char *dirname)
221631d5
LDM
164{
165 struct utsname u;
904c63aa
LDM
166 char *p;
167
168 if (dirname != NULL)
169 return strdup(dirname);
221631d5
LDM
170
171 if (uname(&u) < 0)
172 return NULL;
173
904c63aa
LDM
174 if (asprintf(&p, "%s/%s", dirname_default_prefix, u.release) < 0)
175 return NULL;
176
177 return p;
221631d5
LDM
178}
179
ecd40ee4 180/**
586fc304 181 * kmod_new:
ecd40ee4 182 *
586fc304 183 * Create kmod library context. This reads the kmod configuration
ecd40ee4
LDM
184 * and fills in the default values.
185 *
186 * The initial refcount is 1, and needs to be decremented to
586fc304 187 * release the resources of the kmod library context.
ecd40ee4 188 *
cb8d4d3e
GSB
189 * @dirname: what to consider as linux module's directory, if NULL
190 * defaults to /lib/modules/`uname -r`
191 * @config_paths: ordered array of paths (directories or files) where
192 * to load user-defined configuration parameters such as
193 * alias, blacklists, commands (install, remove). If
194 * NULL defaults to /run/modprobe.d, /etc/modprobe.d and
195 * /lib/modprobe.d. This array must be null terminated.
196 *
586fc304 197 * Returns: a new kmod library context
54ba8b34 198 */
cb8d4d3e 199KMOD_EXPORT struct kmod_ctx *kmod_new(const char *dirname, const char * const *config_paths)
ecd40ee4
LDM
200{
201 const char *env;
52a7704f 202 struct kmod_ctx *ctx;
d13e606f 203 int err;
ecd40ee4 204
52a7704f
LDM
205 ctx = calloc(1, sizeof(struct kmod_ctx));
206 if (!ctx)
207 return NULL;
ecd40ee4 208
52a7704f 209 ctx->refcount = 1;
1bdd951e
GSB
210 ctx->log_fn = log_filep;
211 ctx->log_data = stderr;
52a7704f 212 ctx->log_priority = LOG_ERR;
ecd40ee4 213
904c63aa 214 ctx->dirname = get_kernel_release(dirname);
221631d5 215
ecd40ee4 216 /* environment overwrites config */
586fc304 217 env = getenv("KMOD_LOG");
ecd40ee4 218 if (env != NULL)
52a7704f 219 kmod_set_log_priority(ctx, log_priority(env));
ecd40ee4 220
cb8d4d3e
GSB
221 if (config_paths == NULL)
222 config_paths = default_config_paths;
223 err = kmod_config_new(ctx, &ctx->config, config_paths);
d13e606f 224 if (err < 0) {
fd186ae9
LDM
225 ERR(ctx, "could not create config\n");
226 goto fail;
227 }
228
229 ctx->modules_by_name = kmod_hash_new(KMOD_HASH_SIZE, NULL);
230 if (ctx->modules_by_name == NULL) {
231 ERR(ctx, "could not create by-name hash\n");
232 goto fail;
d13e606f 233 }
7c2ab358 234
ae6df84a
LDM
235 INFO(ctx, "ctx %p created\n", ctx);
236 DBG(ctx, "log_priority=%d\n", ctx->log_priority);
52a7704f
LDM
237
238 return ctx;
fd186ae9
LDM
239
240fail:
241 free(ctx->modules_by_name);
242 free(ctx->dirname);
243 free(ctx);
244 return NULL;
ecd40ee4
LDM
245}
246
247/**
586fc304
LDM
248 * kmod_ref:
249 * @ctx: kmod library context
ecd40ee4 250 *
586fc304 251 * Take a reference of the kmod library context.
ecd40ee4 252 *
586fc304 253 * Returns: the passed kmod library context
54ba8b34 254 */
586fc304 255KMOD_EXPORT struct kmod_ctx *kmod_ref(struct kmod_ctx *ctx)
ecd40ee4
LDM
256{
257 if (ctx == NULL)
258 return NULL;
259 ctx->refcount++;
260 return ctx;
261}
262
263/**
586fc304
LDM
264 * kmod_unref:
265 * @ctx: kmod library context
ecd40ee4 266 *
586fc304 267 * Drop a reference of the kmod library context. If the refcount
ecd40ee4
LDM
268 * reaches zero, the resources of the context will be released.
269 *
54ba8b34 270 */
586fc304 271KMOD_EXPORT struct kmod_ctx *kmod_unref(struct kmod_ctx *ctx)
ecd40ee4
LDM
272{
273 if (ctx == NULL)
274 return NULL;
4d1e689a
LDM
275
276 if (--ctx->refcount > 0)
ecd40ee4 277 return ctx;
33bb69b9 278
ae6df84a 279 INFO(ctx, "context %p released\n", ctx);
33bb69b9
LDM
280
281 kmod_unload_resources(ctx);
fd186ae9 282 kmod_hash_free(ctx->modules_by_name);
1ce08a56 283 free(ctx->dirname);
d13e606f
GSB
284 if (ctx->config)
285 kmod_config_free(ctx->config);
33bb69b9 286
ecd40ee4
LDM
287 free(ctx);
288 return NULL;
289}
290
291/**
586fc304
LDM
292 * kmod_set_log_fn:
293 * @ctx: kmod library context
ecd40ee4
LDM
294 * @log_fn: function to be called for logging messages
295 *
296 * The built-in logging writes to stderr. It can be
297 * overridden by a custom function, to plug log messages
298 * into the user's logging functionality.
299 *
54ba8b34 300 */
586fc304 301KMOD_EXPORT void kmod_set_log_fn(struct kmod_ctx *ctx,
1bdd951e 302 void (*log_fn)(void *data,
e4351b05
LDM
303 int priority, const char *file,
304 int line, const char *fn,
1bdd951e
GSB
305 const char *format, va_list args),
306 const void *data)
ecd40ee4 307{
e5c60f1c
GSB
308 if (ctx == NULL)
309 return;
ecd40ee4 310 ctx->log_fn = log_fn;
1bdd951e 311 ctx->log_data = (void *)data;
ae6df84a 312 INFO(ctx, "custom logging function %p registered\n", log_fn);
ecd40ee4
LDM
313}
314
315/**
586fc304
LDM
316 * kmod_get_log_priority:
317 * @ctx: kmod library context
ecd40ee4
LDM
318 *
319 * Returns: the current logging priority
54ba8b34 320 */
6d177553 321KMOD_EXPORT int kmod_get_log_priority(const struct kmod_ctx *ctx)
ecd40ee4 322{
e5c60f1c
GSB
323 if (ctx == NULL)
324 return -1;
ecd40ee4
LDM
325 return ctx->log_priority;
326}
327
328/**
586fc304
LDM
329 * kmod_set_log_priority:
330 * @ctx: kmod library context
ecd40ee4
LDM
331 * @priority: the new logging priority
332 *
333 * Set the current logging priority. The value controls which messages
334 * are logged.
54ba8b34 335 */
586fc304 336KMOD_EXPORT void kmod_set_log_priority(struct kmod_ctx *ctx, int priority)
ecd40ee4 337{
e5c60f1c
GSB
338 if (ctx == NULL)
339 return;
ecd40ee4
LDM
340 ctx->log_priority = priority;
341}
7f3eb0cc 342
fd186ae9
LDM
343struct kmod_module *kmod_pool_get_module(struct kmod_ctx *ctx,
344 const char *name)
345{
346 struct kmod_module *mod;
347
348 mod = kmod_hash_find(ctx->modules_by_name, name);
349
350 DBG(ctx, "get module name='%s' found=%p\n", name, mod);
351
352 return mod;
353}
354
355void kmod_pool_add_module(struct kmod_ctx *ctx, struct kmod_module *mod)
356{
357 const char *name = kmod_module_get_name(mod);
358
359 DBG(ctx, "add %p name='%s'\n", mod, name);
360
361 kmod_hash_add(ctx->modules_by_name, name, mod);
362}
363
364void kmod_pool_del_module(struct kmod_ctx *ctx, struct kmod_module *mod)
365{
366 const char *name = kmod_module_get_name(mod);
367
368 DBG(ctx, "del %p name='%s'\n", mod, name);
369
370 kmod_hash_del(ctx->modules_by_name, name);
371}
9ba6f57b 372
a009482c 373static int kmod_lookup_alias_from_alias_bin(struct kmod_ctx *ctx,
810803db 374 enum kmod_index index_number,
7b30f4f4 375 const char *name,
9ba6f57b
LDM
376 struct kmod_list **list)
377{
6f1bc6e3 378 int err, nmatch = 0;
0fbdfef3 379 struct index_file *idx;
9ba6f57b
LDM
380 struct index_value *realnames, *realname;
381
65a84f55 382 if (ctx->indexes[index_number] != NULL) {
3e245be1
GSB
383 DBG(ctx, "use mmaped index '%s' for name=%s\n",
384 index_files[index_number], name);
65a84f55
LDM
385 realnames = index_mm_searchwild(ctx->indexes[index_number],
386 name);
387 } else{
388 char fn[PATH_MAX];
389
3b209959 390 snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname,
810803db 391 index_files[index_number]);
9ba6f57b 392
65a84f55 393 DBG(ctx, "file=%s name=%s\n", fn, name);
9ba6f57b 394
65a84f55
LDM
395 idx = index_file_open(fn);
396 if (idx == NULL)
397 return -ENOSYS;
9ba6f57b 398
65a84f55
LDM
399 realnames = index_searchwild(idx, name);
400 index_file_close(idx);
401 }
4272d087 402
9ba6f57b
LDM
403 for (realname = realnames; realname; realname = realnames->next) {
404 struct kmod_module *mod;
405
406 err = kmod_module_new_from_name(ctx, realname->value, &mod);
407 if (err < 0) {
408 ERR(ctx, "%s\n", strerror(-err));
23fc91c6 409 goto fail;
9ba6f57b
LDM
410 }
411
412 *list = kmod_list_append(*list, mod);
23fc91c6 413 nmatch++;
9ba6f57b
LDM
414 }
415
9ba6f57b 416 index_values_free(realnames);
23fc91c6
LDM
417 return nmatch;
418
419fail:
420 *list = kmod_list_remove_n_latest(*list, nmatch);
9ba6f57b 421 return err;
7b30f4f4
LDM
422
423}
424
7b30f4f4
LDM
425int kmod_lookup_alias_from_symbols_file(struct kmod_ctx *ctx, const char *name,
426 struct kmod_list **list)
427{
428 if (!startswith(name, "symbol:"))
429 return 0;
430
810803db
LDM
431 return kmod_lookup_alias_from_alias_bin(ctx, KMOD_INDEX_SYMBOL, name,
432 list);
9ba6f57b
LDM
433}
434
49e61ca3
LDM
435int kmod_lookup_alias_from_aliases_file(struct kmod_ctx *ctx, const char *name,
436 struct kmod_list **list)
437{
810803db
LDM
438 return kmod_lookup_alias_from_alias_bin(ctx, KMOD_INDEX_ALIAS, name,
439 list);
49e61ca3
LDM
440}
441
671d4894 442char *kmod_search_moddep(struct kmod_ctx *ctx, const char *name)
1eb2ef69
LDM
443{
444 struct index_file *idx;
445 char fn[PATH_MAX];
446 char *line;
447
85132101
GSB
448 if (ctx->indexes[KMOD_INDEX_DEP]) {
449 DBG(ctx, "use mmaped index '%s' modname=%s\n",
450 index_files[KMOD_INDEX_DEP], name);
451 return index_mm_search(ctx->indexes[KMOD_INDEX_DEP], name);
452 }
453
a4a75029
LDM
454 snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname,
455 index_files[KMOD_INDEX_DEP]);
1eb2ef69
LDM
456
457 DBG(ctx, "file=%s modname=%s\n", fn, name);
458
459 idx = index_file_open(fn);
460 if (idx == NULL) {
d01c67e3 461 ERR(ctx, "Could not open moddep file '%s'\n", fn);
1eb2ef69
LDM
462 return NULL;
463 }
464
465 line = index_search(idx, name);
466 index_file_close(idx);
467
468 return line;
469}
470
64700e47
LDM
471int kmod_lookup_alias_from_moddep_file(struct kmod_ctx *ctx, const char *name,
472 struct kmod_list **list)
473{
1eb2ef69 474 char *line;
64700e47
LDM
475 int n = 0;
476
477 /*
478 * Module names do not contain ':'. Return early if we know it will
479 * not be found.
480 */
481 if (strchr(name, ':'))
482 return 0;
483
671d4894 484 line = kmod_search_moddep(ctx, name);
64700e47
LDM
485 if (line != NULL) {
486 struct kmod_module *mod;
487
488 n = kmod_module_new_from_name(ctx, name, &mod);
489 if (n < 0) {
490 ERR(ctx, "%s\n", strerror(-n));
491 goto finish;
492 }
493
494 *list = kmod_list_append(*list, mod);
671d4894 495 kmod_module_parse_depline(mod, line);
64700e47
LDM
496 }
497
498finish:
499 free(line);
64700e47
LDM
500
501 return n;
502}
503
7f3eb0cc
LDM
504int kmod_lookup_alias_from_config(struct kmod_ctx *ctx, const char *name,
505 struct kmod_list **list)
506{
d13e606f 507 struct kmod_config *config = ctx->config;
7f3eb0cc 508 struct kmod_list *l;
23fc91c6 509 int err, nmatch = 0;
7f3eb0cc
LDM
510
511 kmod_list_foreach(l, config->aliases) {
512 const char *aliasname = kmod_alias_get_name(l);
513 const char *modname = kmod_alias_get_modname(l);
514
515 if (fnmatch(aliasname, name, 0) == 0) {
516 struct kmod_module *mod;
517
518 err = kmod_module_new_from_name(ctx, modname, &mod);
519 if (err < 0) {
d01c67e3 520 ERR(ctx, "%s\n", strerror(-err));
23fc91c6 521 goto fail;
7f3eb0cc
LDM
522 }
523
524 *list = kmod_list_append(*list, mod);
23fc91c6 525 nmatch++;
7f3eb0cc
LDM
526 }
527 }
528
23fc91c6
LDM
529 return nmatch;
530
531fail:
532 *list = kmod_list_remove_n_latest(*list, nmatch);
533 return err;
7f3eb0cc 534}
1487a64f 535
54ba8b34
LDM
536/**
537 * kmod_module_get_filtered_blacklist:
538 * @ctx: kmod library context
539 * @input: list to be filtered with blacklist
540 * @output: where to save the new list
541 *
542 * Given a list @input, this function filter it out with config's blacklist
543 * ans save it in @output.
544 *
545 * Returns: 0 on success or < 0 otherwise. @output is saved with the updated
546 * list.
547 */
1487a64f
GSB
548KMOD_EXPORT int kmod_module_get_filtered_blacklist(const struct kmod_ctx *ctx, const struct kmod_list *input, struct kmod_list **output)
549{
550 const struct kmod_config *config;
551 const struct kmod_list *li;
552
553 if (ctx == NULL || output == NULL)
554 return -ENOENT;
555
556 *output = NULL;
557 if (input == NULL)
558 return 0;
559
560 config = ctx->config;
561 kmod_list_foreach(li, input) {
562 struct kmod_module *mod = li->data;
563 const struct kmod_list *lb;
564 struct kmod_list *node;
565 bool filtered = false;
566 kmod_list_foreach(lb, config->blacklists) {
567 const char *name = lb->data;
568 if (streq(name, kmod_module_get_name(mod))) {
569 filtered = true;
570 break;
571 }
572 }
573 if (filtered)
574 continue;
575
576 node = kmod_list_append(*output, mod);
577 if (node == NULL)
578 goto fail;
579 *output = node;
580 kmod_module_ref(mod);
581 }
582 return 0;
583
584fail:
585 kmod_module_unref_list(*output);
586 *output = NULL;
587 return -ENOMEM;
588}
33bb69b9
LDM
589
590KMOD_EXPORT int kmod_load_resources(struct kmod_ctx *ctx)
591{
79d57fcb 592 char path[PATH_MAX];
33bb69b9
LDM
593 size_t i;
594
595 if (ctx == NULL)
596 return -ENOENT;
597
598 for (i = 0; i < ARRAY_SIZE(index_files); i++) {
599 if (ctx->indexes[i] == NULL) {
600 const char *fn = index_files[i];
79d57fcb
GSB
601 size_t fnlen = strlen(fn);
602 const char *prefix = "";
603 const char *suffix = "";
604
605 if (fn[0] != '/')
606 prefix = ctx->dirname;
607
608 if (fnlen < 4 || !streq(fn + fnlen - 4, ".bin"))
609 suffix = ".bin";
610
611 snprintf(path, sizeof(path), "%s/%s%s",
612 prefix, fn, suffix);
613 fn = path;
33bb69b9
LDM
614
615 ctx->indexes[i] = index_mm_open(ctx, fn, true);
616 if (ctx->indexes[i] == NULL)
617 goto fail;
618 }
619 }
620
621 return 0;
622
623fail:
624 kmod_unload_resources(ctx);
625 return -ENOMEM;
626}
627
628KMOD_EXPORT void kmod_unload_resources(struct kmod_ctx *ctx)
629{
630 size_t i;
631
632 if (ctx == NULL)
633 return;
634
635 for (i = 0; i < ARRAY_SIZE(index_files); i++) {
636 if (ctx->indexes[i] != NULL) {
637 index_mm_close(ctx->indexes[i]);
638 ctx->indexes[i] = NULL;
639 }
640 }
641}
bd3f5535 642
d917f274 643KMOD_EXPORT int kmod_resolve_alias_options(struct kmod_ctx *ctx, const char *given_alias, char **options)
bd3f5535
GSB
644{
645 struct kmod_list *modules = NULL, *l;
d917f274 646 char alias[NAME_MAX];
bd3f5535
GSB
647 char *opts = NULL;
648 size_t optslen = 0;
649 int err;
650
651 if (ctx == NULL || options == NULL)
652 return -ENOENT;
653
d917f274
GSB
654 modname_normalize(given_alias, alias, NULL);
655
bd3f5535
GSB
656 err = kmod_module_new_from_lookup(ctx, alias, &modules);
657 if (err >= 0) {
658 kmod_list_foreach(l, modules) {
659 const char *str = kmod_module_get_options(l->data);
660 size_t len;
661 void *tmp;
662
663 if (str == NULL)
664 continue;
665 len = strlen(str);
666
667 tmp = realloc(opts, optslen + len + 2);
668 if (tmp == NULL)
669 goto failed;
670 opts = tmp;
671 if (optslen > 0) {
672 opts[optslen] = ' ';
673 optslen++;
674 }
675 memcpy(opts + optslen, str, len);
676 optslen += len;
677 opts[optslen] = '\0';
678 }
679 }
680
681 kmod_list_foreach(l, ctx->config->options) {
682 const struct kmod_list *ml;
683 const char *modname = kmod_option_get_modname(l);
684 const char *str;
685 bool already_done = false;
686 size_t len;
687 void *tmp;
688
689 if (fnmatch(modname, alias, 0) != 0)
690 continue;
691
692 kmod_list_foreach(ml, modules) {
693 const char *mln = kmod_module_get_name(ml->data);
694 if (fnmatch(modname, mln, 0) == 0) {
695 already_done = true;
696 break;
697 }
698 }
699 if (already_done)
700 continue;
701
702 str = kmod_option_get_options(l);
703 len = strlen(str);
704 tmp = realloc(opts, optslen + len + 2);
705 if (tmp == NULL)
706 goto failed;
707 opts = tmp;
708 if (optslen > 0) {
709 opts[optslen] = ' ';
710 optslen++;
711 }
712 memcpy(opts + optslen, str, len);
713 optslen += len;
714 opts[optslen] = '\0';
715 }
716
717 DBG(ctx, "alias=%s options='%s'\n", alias, opts);
718 kmod_module_unref_list(modules);
719 *options = opts;
720 return 0;
721
722failed:
723 kmod_module_unref_list(modules);
724 free(opts);
725 ERR(ctx, "out of memory\n");
726 *options = NULL;
727 return -ENOMEM;
728}
729
730const struct kmod_list *kmod_get_options(const struct kmod_ctx *ctx)
731{
732 return ctx->config->options;
733}
734
735const struct kmod_list *kmod_get_install_commands(const struct kmod_ctx *ctx)
736{
737 return ctx->config->install_commands;
738}
739
740const struct kmod_list *kmod_get_remove_commands(const struct kmod_ctx *ctx)
741{
742 return ctx->config->remove_commands;
743}