]> git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod.c
a62946dc0033b7a6ebf3580b47a021637e5aa0df
[thirdparty/kmod.git] / libkmod / libkmod.c
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /*
3 * Copyright (C) 2011-2013 ProFUSION embedded systems
4 */
5
6 #include <assert.h>
7 #include <ctype.h>
8 #include <errno.h>
9 #include <fnmatch.h>
10 #include <limits.h>
11 #include <stdarg.h>
12 #include <stddef.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <sys/stat.h>
18 #include <sys/utsname.h>
19
20 #include <shared/hash.h>
21 #include <shared/util.h>
22
23 #include "libkmod.h"
24 #include "libkmod-internal.h"
25 #include "libkmod-index.h"
26
27 #define KMOD_HASH_SIZE (256)
28 #define KMOD_LRU_MAX (128)
29 #define _KMOD_INDEX_MODULES_SIZE KMOD_INDEX_MODULES_BUILTIN + 1
30
31 static const struct {
32 const char *fn;
33 bool alias_prefix;
34 } index_files[] = {
35 // clang-format off
36 [KMOD_INDEX_MODULES_DEP] = { .fn = "modules.dep" },
37 [KMOD_INDEX_MODULES_ALIAS] = { .fn = "modules.alias", .alias_prefix = true },
38 [KMOD_INDEX_MODULES_SYMBOL] = { .fn = "modules.symbols", .alias_prefix = true },
39 [KMOD_INDEX_MODULES_BUILTIN_ALIAS] = { .fn = "modules.builtin.alias" },
40 [KMOD_INDEX_MODULES_BUILTIN] = { .fn = "modules.builtin" },
41 // clang-format on
42 };
43
44 static const char *const default_config_paths[] = {
45 // clang-format off
46 SYSCONFDIR "/modprobe.d",
47 "/run/modprobe.d",
48 "/usr/local/lib/modprobe.d",
49 DISTCONFDIR "/modprobe.d",
50 "/lib/modprobe.d",
51 NULL,
52 // clang-format on
53 };
54
55 struct kmod_ctx {
56 int refcount;
57 int log_priority;
58 void (*log_fn)(void *data, int priority, const char *file, int line,
59 const char *fn, const char *format, va_list args);
60 void *log_data;
61 const void *userdata;
62 char *dirname;
63 enum kmod_file_compression_type kernel_compression;
64 struct kmod_config *config;
65 struct hash *modules_by_name;
66 struct index_mm *indexes[_KMOD_INDEX_MODULES_SIZE];
67 unsigned long long indexes_stamp[_KMOD_INDEX_MODULES_SIZE];
68 };
69
70 void kmod_log(const struct kmod_ctx *ctx, int priority, const char *file, int line,
71 const char *fn, const char *format, ...)
72 {
73 va_list args;
74
75 if (ctx->log_fn == NULL)
76 return;
77
78 va_start(args, format);
79 ctx->log_fn(ctx->log_data, priority, file, line, fn, format, args);
80 va_end(args);
81 }
82
83 _printf_format_(6, 0) static void log_filep(void *data, int priority, const char *file,
84 int line, const char *fn, const char *format,
85 va_list args)
86 {
87 FILE *fp = data;
88 char buf[16];
89 const char *priname;
90 switch (priority) {
91 case LOG_EMERG:
92 priname = "EMERGENCY";
93 break;
94 case LOG_ALERT:
95 priname = "ALERT";
96 break;
97 case LOG_CRIT:
98 priname = "CRITICAL";
99 break;
100 case LOG_ERR:
101 priname = "ERROR";
102 break;
103 case LOG_WARNING:
104 priname = "WARNING";
105 break;
106 case LOG_NOTICE:
107 priname = "NOTICE";
108 break;
109 case LOG_INFO:
110 priname = "INFO";
111 break;
112 case LOG_DEBUG:
113 priname = "DEBUG";
114 break;
115 default:
116 snprintf(buf, sizeof(buf), "L:%d", priority);
117 priname = buf;
118 }
119 if (ENABLE_DEBUG == 1)
120 fprintf(fp, "libkmod: %s %s:%d %s: ", priname, file, line, fn);
121 else
122 fprintf(fp, "libkmod: %s: %s: ", priname, fn);
123 vfprintf(fp, format, args);
124 }
125
126 KMOD_EXPORT const char *kmod_get_dirname(const struct kmod_ctx *ctx)
127 {
128 if (ctx == NULL)
129 return NULL;
130
131 return ctx->dirname;
132 }
133
134 KMOD_EXPORT void *kmod_get_userdata(const struct kmod_ctx *ctx)
135 {
136 if (ctx == NULL)
137 return NULL;
138 return (void *)ctx->userdata;
139 }
140
141 KMOD_EXPORT void kmod_set_userdata(struct kmod_ctx *ctx, const void *userdata)
142 {
143 if (ctx == NULL)
144 return;
145 ctx->userdata = userdata;
146 }
147
148 static int log_priority(const char *priority)
149 {
150 char *endptr;
151 long prio;
152
153 errno = 0;
154 prio = strtol(priority, &endptr, 10);
155 if (errno == ERANGE || prio < INT_MIN || prio > INT_MAX)
156 return 0;
157 if (endptr[0] == '\0' || isspace(endptr[0]))
158 return prio;
159 if (strstartswith(priority, "err"))
160 return LOG_ERR;
161 if (strstartswith(priority, "info"))
162 return LOG_INFO;
163 if (strstartswith(priority, "debug"))
164 return LOG_DEBUG;
165 return 0;
166 }
167
168 static const char *dirname_default_prefix = MODULE_DIRECTORY;
169
170 static char *get_kernel_release(const char *dirname)
171 {
172 struct utsname u;
173 char *p;
174
175 if (dirname != NULL)
176 return path_make_absolute_cwd(dirname);
177
178 if (uname(&u) < 0)
179 return NULL;
180
181 if (asprintf(&p, "%s/%s", dirname_default_prefix, u.release) < 0)
182 return NULL;
183
184 return p;
185 }
186
187 static enum kmod_file_compression_type get_kernel_compression(struct kmod_ctx *ctx)
188 {
189 const char *path = "/sys/module/compression";
190 char buf[16];
191 int fd;
192 int err;
193
194 fd = open(path, O_RDONLY | O_CLOEXEC);
195 if (fd < 0) {
196 /* Not having the file is not an error: kernel may be too old */
197 DBG(ctx, "could not open '%s' for reading: %m\n", path);
198 return KMOD_FILE_COMPRESSION_NONE;
199 }
200
201 err = read_str_safe(fd, buf, sizeof(buf));
202 close(fd);
203 if (err < 0) {
204 ERR(ctx, "could not read from '%s': %s\n", path, strerror(-err));
205 return KMOD_FILE_COMPRESSION_NONE;
206 }
207
208 if (streq(buf, "zstd\n"))
209 return KMOD_FILE_COMPRESSION_ZSTD;
210 else if (streq(buf, "xz\n"))
211 return KMOD_FILE_COMPRESSION_XZ;
212 else if (streq(buf, "gzip\n"))
213 return KMOD_FILE_COMPRESSION_ZLIB;
214
215 ERR(ctx, "unknown kernel compression %s", buf);
216
217 return KMOD_FILE_COMPRESSION_NONE;
218 }
219
220 KMOD_EXPORT struct kmod_ctx *kmod_new(const char *dirname, const char *const *config_paths)
221 {
222 const char *env;
223 struct kmod_ctx *ctx;
224 int err;
225
226 ctx = calloc(1, sizeof(struct kmod_ctx));
227 if (!ctx)
228 return NULL;
229
230 ctx->refcount = 1;
231 ctx->log_fn = log_filep;
232 ctx->log_data = stderr;
233 ctx->log_priority = LOG_ERR;
234
235 ctx->dirname = get_kernel_release(dirname);
236 if (ctx->dirname == NULL) {
237 ERR(ctx, "could not retrieve directory\n");
238 goto fail;
239 }
240
241 /* environment overwrites config */
242 env = secure_getenv("KMOD_LOG");
243 if (env != NULL)
244 kmod_set_log_priority(ctx, log_priority(env));
245
246 ctx->kernel_compression = get_kernel_compression(ctx);
247
248 if (config_paths == NULL)
249 config_paths = default_config_paths;
250 err = kmod_config_new(ctx, &ctx->config, config_paths);
251 if (err < 0) {
252 ERR(ctx, "could not create config\n");
253 goto fail;
254 }
255
256 ctx->modules_by_name = hash_new(KMOD_HASH_SIZE, NULL);
257 if (ctx->modules_by_name == NULL) {
258 ERR(ctx, "could not create by-name hash\n");
259 goto fail;
260 }
261
262 INFO(ctx, "ctx %p created\n", ctx);
263 DBG(ctx, "log_priority=%d\n", ctx->log_priority);
264
265 return ctx;
266
267 fail:
268 free(ctx->modules_by_name);
269 free(ctx->dirname);
270 free(ctx);
271 return NULL;
272 }
273
274 KMOD_EXPORT struct kmod_ctx *kmod_ref(struct kmod_ctx *ctx)
275 {
276 if (ctx == NULL)
277 return NULL;
278 ctx->refcount++;
279 return ctx;
280 }
281
282 KMOD_EXPORT struct kmod_ctx *kmod_unref(struct kmod_ctx *ctx)
283 {
284 if (ctx == NULL)
285 return NULL;
286
287 if (--ctx->refcount > 0)
288 return ctx;
289
290 INFO(ctx, "context %p released\n", ctx);
291
292 kmod_unload_resources(ctx);
293 hash_free(ctx->modules_by_name);
294 free(ctx->dirname);
295 if (ctx->config)
296 kmod_config_free(ctx->config);
297
298 free(ctx);
299 return NULL;
300 }
301
302 KMOD_EXPORT void kmod_set_log_fn(struct kmod_ctx *ctx,
303 void (*log_fn)(void *data, int priority,
304 const char *file, int line, const char *fn,
305 const char *format, va_list args),
306 const void *data)
307 {
308 if (ctx == NULL)
309 return;
310 ctx->log_fn = log_fn;
311 ctx->log_data = (void *)data;
312 INFO(ctx, "custom logging function %p registered\n", log_fn);
313 }
314
315 KMOD_EXPORT int kmod_get_log_priority(const struct kmod_ctx *ctx)
316 {
317 if (ctx == NULL)
318 return -1;
319 return ctx->log_priority;
320 }
321
322 KMOD_EXPORT void kmod_set_log_priority(struct kmod_ctx *ctx, int priority)
323 {
324 if (ctx == NULL)
325 return;
326 ctx->log_priority = priority;
327 }
328
329 struct kmod_module *kmod_pool_get_module(struct kmod_ctx *ctx, const char *key)
330 {
331 struct kmod_module *mod;
332
333 mod = hash_find(ctx->modules_by_name, key);
334
335 DBG(ctx, "get module name='%s' found=%p\n", key, mod);
336
337 return mod;
338 }
339
340 int kmod_pool_add_module(struct kmod_ctx *ctx, struct kmod_module *mod, const char *key)
341 {
342 DBG(ctx, "add %p key='%s'\n", mod, key);
343
344 return hash_add(ctx->modules_by_name, key, mod);
345 }
346
347 void kmod_pool_del_module(struct kmod_ctx *ctx, struct kmod_module *mod, const char *key)
348 {
349 DBG(ctx, "del %p key='%s'\n", mod, key);
350
351 hash_del(ctx->modules_by_name, key);
352 }
353
354 static int kmod_lookup_alias_from_alias_bin(struct kmod_ctx *ctx,
355 enum kmod_index index_number,
356 const char *name, struct kmod_list **list)
357 {
358 int err, nmatch = 0;
359 struct index_file *idx;
360 struct index_value *realnames, *realname;
361
362 assert(*list == NULL);
363
364 if (ctx->indexes[index_number] != NULL) {
365 DBG(ctx, "use mmapped index '%s' for name=%s\n",
366 index_files[index_number].fn, name);
367 realnames = index_mm_searchwild(ctx->indexes[index_number], name);
368 } else {
369 char fn[PATH_MAX];
370
371 snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname,
372 index_files[index_number].fn);
373
374 DBG(ctx, "file=%s name=%s\n", fn, name);
375
376 idx = index_file_open(fn);
377 if (idx == NULL)
378 return -ENOSYS;
379
380 realnames = index_searchwild(idx, name);
381 index_file_close(idx);
382 }
383
384 for (realname = realnames; realname; realname = realname->next) {
385 struct kmod_module *mod;
386 struct kmod_list *node;
387
388 err = kmod_module_new_from_alias(ctx, name, realname->value, &mod);
389 if (err < 0) {
390 ERR(ctx, "Could not create module for alias=%s realname=%s: %s\n",
391 name, realname->value, strerror(-err));
392 goto fail;
393 }
394
395 node = kmod_list_append(*list, mod);
396 if (node == NULL) {
397 ERR(ctx, "out of memory\n");
398 kmod_module_unref(mod);
399 err = -ENOMEM;
400 goto fail;
401 }
402 *list = node;
403 nmatch++;
404 }
405
406 index_values_free(realnames);
407 return nmatch;
408
409 fail:
410 kmod_list_release(*list, kmod_module_unref);
411 index_values_free(realnames);
412 return err;
413 }
414
415 int kmod_lookup_alias_from_symbols_file(struct kmod_ctx *ctx, const char *name,
416 struct kmod_list **list)
417 {
418 if (!strstartswith(name, "symbol:"))
419 return 0;
420
421 return kmod_lookup_alias_from_alias_bin(ctx, KMOD_INDEX_MODULES_SYMBOL, name,
422 list);
423 }
424
425 int kmod_lookup_alias_from_aliases_file(struct kmod_ctx *ctx, const char *name,
426 struct kmod_list **list)
427 {
428 return kmod_lookup_alias_from_alias_bin(ctx, KMOD_INDEX_MODULES_ALIAS, name, list);
429 }
430
431 static char *lookup_file(struct kmod_ctx *ctx, enum kmod_index index_number,
432 const char *name)
433 {
434 char *line;
435
436 if (ctx->indexes[index_number]) {
437 DBG(ctx, "use mmapped index '%s' modname=%s\n",
438 index_files[index_number].fn, name);
439 line = index_mm_search(ctx->indexes[index_number], name);
440 } else {
441 struct index_file *idx;
442 char fn[PATH_MAX];
443
444 snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname,
445 index_files[index_number].fn);
446 DBG(ctx, "file=%s modname=%s\n", fn, name);
447
448 idx = index_file_open(fn);
449 if (idx == NULL) {
450 DBG(ctx, "could not open builtin file '%s'\n", fn);
451 return NULL;
452 }
453
454 line = index_search(idx, name);
455 index_file_close(idx);
456 }
457
458 return line;
459 }
460
461 static bool lookup_builtin_file(struct kmod_ctx *ctx, const char *name)
462 {
463 _cleanup_free_ char *line = lookup_file(ctx, KMOD_INDEX_MODULES_BUILTIN, name);
464
465 return line;
466 }
467
468 int kmod_lookup_alias_from_kernel_builtin_file(struct kmod_ctx *ctx, const char *name,
469 struct kmod_list **list)
470 {
471 struct kmod_list *l;
472 int ret;
473
474 ret = kmod_lookup_alias_from_alias_bin(ctx, KMOD_INDEX_MODULES_BUILTIN_ALIAS,
475 name, list);
476
477 kmod_list_foreach(l, *list) {
478 struct kmod_module *mod = l->data;
479 kmod_module_set_builtin(mod, true);
480 }
481
482 return ret;
483 }
484
485 int kmod_lookup_alias_from_builtin_file(struct kmod_ctx *ctx, const char *name,
486 struct kmod_list **list)
487 {
488 assert(*list == NULL);
489
490 if (lookup_builtin_file(ctx, name)) {
491 struct kmod_module *mod;
492 struct kmod_list *node;
493 int err;
494
495 err = kmod_module_new_from_name(ctx, name, &mod);
496 if (err < 0) {
497 ERR(ctx, "Could not create module from name %s: %s\n", name,
498 strerror(-err));
499 return err;
500 }
501
502 /* already mark it as builtin since it's being created from
503 * this index */
504 kmod_module_set_builtin(mod, true);
505 node = kmod_list_append(*list, mod);
506 if (node == NULL) {
507 ERR(ctx, "out of memory\n");
508 kmod_module_unref(mod);
509 return -ENOMEM;
510 }
511 *list = node;
512 }
513
514 return 0;
515 }
516
517 bool kmod_lookup_alias_is_builtin(struct kmod_ctx *ctx, const char *name)
518 {
519 return lookup_builtin_file(ctx, name);
520 }
521
522 char *kmod_search_moddep(struct kmod_ctx *ctx, const char *name)
523 {
524 return lookup_file(ctx, KMOD_INDEX_MODULES_DEP, name);
525 }
526
527 int kmod_lookup_alias_from_moddep_file(struct kmod_ctx *ctx, const char *name,
528 struct kmod_list **list)
529 {
530 char *line;
531 int n = 0;
532
533 assert(*list == NULL);
534
535 /*
536 * Module names do not contain ':'. Return early if we know it will
537 * not be found.
538 */
539 if (strchr(name, ':'))
540 return 0;
541
542 line = kmod_search_moddep(ctx, name);
543 if (line != NULL) {
544 struct kmod_module *mod;
545 struct kmod_list *node;
546
547 n = kmod_module_new_from_name(ctx, name, &mod);
548 if (n < 0) {
549 ERR(ctx, "Could not create module from name %s: %s\n", name,
550 strerror(-n));
551 goto finish;
552 }
553
554 node = kmod_list_append(*list, mod);
555 if (node == NULL) {
556 ERR(ctx, "out of memory\n");
557 kmod_module_unref(mod);
558 n = -ENOMEM;
559 goto finish;
560 }
561 *list = node;
562 kmod_module_parse_depline(mod, line);
563 }
564
565 finish:
566 free(line);
567
568 return n;
569 }
570
571 int kmod_lookup_alias_from_config(struct kmod_ctx *ctx, const char *name,
572 struct kmod_list **list)
573 {
574 struct kmod_config *config = ctx->config;
575 struct kmod_list *l;
576 int err, nmatch = 0;
577
578 assert(*list == NULL);
579
580 kmod_list_foreach(l, config->aliases) {
581 const char *aliasname = kmod_alias_get_name(l);
582 const char *modname = kmod_alias_get_modname(l);
583
584 if (fnmatch(aliasname, name, 0) == 0) {
585 struct kmod_module *mod;
586 struct kmod_list *node;
587
588 err = kmod_module_new_from_alias(ctx, aliasname, modname, &mod);
589 if (err < 0) {
590 ERR(ctx,
591 "Could not create module for alias=%s modname=%s: %s\n",
592 name, modname, strerror(-err));
593 goto fail;
594 }
595
596 node = kmod_list_append(*list, mod);
597 if (node == NULL) {
598 ERR(ctx, "out of memory\n");
599 kmod_module_unref(mod);
600 err = -ENOMEM;
601 goto fail;
602 }
603 *list = node;
604 nmatch++;
605 }
606 }
607
608 return nmatch;
609
610 fail:
611 kmod_list_release(*list, kmod_module_unref);
612 return err;
613 }
614
615 int kmod_lookup_alias_from_commands(struct kmod_ctx *ctx, const char *name,
616 struct kmod_list **list)
617 {
618 struct kmod_config *config = ctx->config;
619 struct kmod_list *l, *node;
620 int err, nmatch = 0;
621
622 assert(*list == NULL);
623
624 kmod_list_foreach(l, config->install_commands) {
625 const char *modname = kmod_command_get_modname(l);
626
627 if (streq(modname, name)) {
628 const char *cmd = kmod_command_get_command(l);
629 struct kmod_module *mod;
630
631 err = kmod_module_new_from_name(ctx, modname, &mod);
632 if (err < 0) {
633 ERR(ctx, "Could not create module from name %s: %s\n",
634 modname, strerror(-err));
635 return err;
636 }
637
638 node = kmod_list_append(*list, mod);
639 if (node == NULL) {
640 ERR(ctx, "out of memory\n");
641 kmod_module_unref(mod);
642 return -ENOMEM;
643 }
644
645 *list = node;
646 nmatch = 1;
647
648 kmod_module_set_install_commands(mod, cmd);
649
650 /*
651 * match only the first one, like modprobe from
652 * module-init-tools does
653 */
654 break;
655 }
656 }
657
658 if (nmatch)
659 return nmatch;
660
661 kmod_list_foreach(l, config->remove_commands) {
662 const char *modname = kmod_command_get_modname(l);
663
664 if (streq(modname, name)) {
665 const char *cmd = kmod_command_get_command(l);
666 struct kmod_module *mod;
667
668 err = kmod_module_new_from_name(ctx, modname, &mod);
669 if (err < 0) {
670 ERR(ctx, "Could not create module from name %s: %s\n",
671 modname, strerror(-err));
672 return err;
673 }
674
675 node = kmod_list_append(*list, mod);
676 if (node == NULL) {
677 ERR(ctx, "out of memory\n");
678 kmod_module_unref(mod);
679 return -ENOMEM;
680 }
681
682 *list = node;
683 nmatch = 1;
684
685 kmod_module_set_remove_commands(mod, cmd);
686
687 /*
688 * match only the first one, like modprobe from
689 * module-init-tools does
690 */
691 break;
692 }
693 }
694
695 return nmatch;
696 }
697
698 void kmod_set_modules_visited(struct kmod_ctx *ctx, bool visited)
699 {
700 struct hash_iter iter;
701 const void *v;
702
703 hash_iter_init(ctx->modules_by_name, &iter);
704 while (hash_iter_next(&iter, NULL, &v))
705 kmod_module_set_visited((struct kmod_module *)v, visited);
706 }
707
708 void kmod_set_modules_required(struct kmod_ctx *ctx, bool required)
709 {
710 struct hash_iter iter;
711 const void *v;
712
713 hash_iter_init(ctx->modules_by_name, &iter);
714 while (hash_iter_next(&iter, NULL, &v))
715 kmod_module_set_required((struct kmod_module *)v, required);
716 }
717
718 static bool is_cache_invalid(const char *path, unsigned long long stamp)
719 {
720 struct stat st;
721
722 if (stat(path, &st) < 0)
723 return true;
724
725 if (stamp != stat_mstamp(&st))
726 return true;
727
728 return false;
729 }
730
731 KMOD_EXPORT int kmod_validate_resources(struct kmod_ctx *ctx)
732 {
733 struct kmod_list *l;
734 size_t i;
735
736 if (ctx == NULL || ctx->config == NULL)
737 return KMOD_RESOURCES_MUST_RECREATE;
738
739 kmod_list_foreach(l, ctx->config->paths) {
740 struct kmod_config_path *cf = l->data;
741
742 if (is_cache_invalid(cf->path, cf->stamp))
743 return KMOD_RESOURCES_MUST_RECREATE;
744 }
745
746 for (i = 0; i < _KMOD_INDEX_MODULES_SIZE; i++) {
747 char path[PATH_MAX];
748
749 if (ctx->indexes[i] == NULL)
750 continue;
751
752 snprintf(path, sizeof(path), "%s/%s.bin", ctx->dirname, index_files[i].fn);
753
754 if (is_cache_invalid(path, ctx->indexes_stamp[i]))
755 return KMOD_RESOURCES_MUST_RELOAD;
756 }
757
758 return KMOD_RESOURCES_OK;
759 }
760
761 KMOD_EXPORT int kmod_load_resources(struct kmod_ctx *ctx)
762 {
763 int ret = 0;
764 size_t i;
765
766 if (ctx == NULL)
767 return -ENOENT;
768
769 for (i = 0; i < _KMOD_INDEX_MODULES_SIZE; i++) {
770 char path[PATH_MAX];
771
772 if (ctx->indexes[i] != NULL) {
773 INFO(ctx, "Index %s already loaded\n", index_files[i].fn);
774 continue;
775 }
776
777 snprintf(path, sizeof(path), "%s/%s.bin", ctx->dirname, index_files[i].fn);
778 ret = index_mm_open(ctx, path, &ctx->indexes_stamp[i], &ctx->indexes[i]);
779
780 /*
781 * modules.builtin.alias are considered optional since it's
782 * recently added and older installations may not have it;
783 * we allow failing for any reason
784 */
785 if (ret) {
786 if (i != KMOD_INDEX_MODULES_BUILTIN_ALIAS)
787 break;
788 ret = 0;
789 }
790 }
791
792 if (ret)
793 kmod_unload_resources(ctx);
794
795 return ret;
796 }
797
798 KMOD_EXPORT void kmod_unload_resources(struct kmod_ctx *ctx)
799 {
800 size_t i;
801
802 if (ctx == NULL)
803 return;
804
805 for (i = 0; i < _KMOD_INDEX_MODULES_SIZE; i++) {
806 if (ctx->indexes[i] != NULL) {
807 index_mm_close(ctx->indexes[i]);
808 ctx->indexes[i] = NULL;
809 ctx->indexes_stamp[i] = 0;
810 }
811 }
812 }
813
814 KMOD_EXPORT int kmod_dump_index(struct kmod_ctx *ctx, enum kmod_index type, int fd)
815 {
816 if (ctx == NULL)
817 return -ENOSYS;
818
819 #if defined(__clang__)
820 #pragma clang diagnostic push
821 #pragma clang diagnostic ignored "-Wtautological-unsigned-enum-zero-compare"
822 #endif
823 if (type < 0 || type >= _KMOD_INDEX_MODULES_SIZE)
824 return -ENOENT;
825 #if defined(__clang__)
826 #pragma clang diagnostic pop
827 #endif
828
829 if (ctx->indexes[type] != NULL) {
830 DBG(ctx, "use mmapped index '%s'\n", index_files[type].fn);
831 index_mm_dump(ctx->indexes[type], fd, index_files[type].alias_prefix);
832 } else {
833 char fn[PATH_MAX];
834 struct index_file *idx;
835
836 snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname, index_files[type].fn);
837
838 DBG(ctx, "file=%s\n", fn);
839
840 idx = index_file_open(fn);
841 if (idx == NULL)
842 return -ENOSYS;
843
844 index_dump(idx, fd, index_files[type].alias_prefix);
845 index_file_close(idx);
846 }
847
848 return 0;
849 }
850
851 const struct kmod_config *kmod_get_config(const struct kmod_ctx *ctx)
852 {
853 return ctx->config;
854 }
855
856 enum kmod_file_compression_type kmod_get_kernel_compression(const struct kmod_ctx *ctx)
857 {
858 return ctx->kernel_compression;
859 }