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