]> git.ipfire.org Git - thirdparty/kmod.git/blame - libkmod/libkmod.c
ci: move compression variants further down
[thirdparty/kmod.git] / libkmod / libkmod.c
CommitLineData
b5a2cd07 1// SPDX-License-Identifier: LGPL-2.1-or-later
ecd40ee4 2/*
e6b0e49b 3 * Copyright (C) 2011-2013 ProFUSION embedded systems
586fc304 4 */
ecd40ee4 5
ee1d188f 6#include <assert.h>
c2e4286b 7#include <ctype.h>
ecd40ee4 8#include <errno.h>
7f3eb0cc 9#include <fnmatch.h>
c2e4286b
LDM
10#include <limits.h>
11#include <stdarg.h>
12#include <stddef.h>
13#include <stdio.h>
14#include <stdlib.h>
ecd40ee4 15#include <string.h>
c2e4286b 16#include <unistd.h>
c4dc3ca8 17#include <sys/stat.h>
c2e4286b 18#include <sys/utsname.h>
ecd40ee4 19
0db718ed 20#include <shared/hash.h>
96573a02
LDM
21#include <shared/util.h>
22
586fc304 23#include "libkmod.h"
83b855a6 24#include "libkmod-internal.h"
9ba6f57b 25#include "libkmod-index.h"
ecd40ee4 26
fd186ae9
LDM
27#define KMOD_HASH_SIZE (256)
28#define KMOD_LRU_MAX (128)
3805274b 29#define _KMOD_INDEX_MODULES_SIZE KMOD_INDEX_MODULES_BUILTIN + 1
fd186ae9 30
efc2e4b4 31static const struct {
63be91cb 32 const char *fn;
e9ef6032 33 bool alias_prefix;
63be91cb 34} index_files[] = {
7c7b6d69 35 // clang-format off
e9ef6032
EV
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" },
7c7b6d69 41 // clang-format on
a4a75029
LDM
42};
43
efc2e4b4 44static const char *const default_config_paths[] = {
7c7b6d69 45 // clang-format off
a308abec 46 SYSCONFDIR "/modprobe.d",
436da1e9 47 "/run/modprobe.d",
9319b0f4 48 "/usr/local/lib/modprobe.d",
8463809f 49 DISTCONFDIR "/modprobe.d",
c5b37dba 50 "/lib/modprobe.d",
b509ef77 51 NULL,
7c7b6d69 52 // clang-format on
cb8d4d3e
GSB
53};
54
586fc304 55struct kmod_ctx {
ecd40ee4 56 int refcount;
8d3f3ef8 57 int log_priority;
115bcd52
EV
58 void (*log_fn)(void *data, int priority, const char *file, int line,
59 const char *fn, const char *format, va_list args);
1bdd951e 60 void *log_data;
1ce08a56
GSB
61 const void *userdata;
62 char *dirname;
30077bf1 63 enum kmod_file_compression_type kernel_compression;
d13e606f 64 struct kmod_config *config;
822913d7 65 struct hash *modules_by_name;
b08314f7
LDM
66 struct index_mm *indexes[_KMOD_INDEX_MODULES_SIZE];
67 unsigned long long indexes_stamp[_KMOD_INDEX_MODULES_SIZE];
ecd40ee4
LDM
68};
69
115bcd52
EV
70void kmod_log(const struct kmod_ctx *ctx, int priority, const char *file, int line,
71 const char *fn, const char *format, ...)
ecd40ee4
LDM
72{
73 va_list args;
74
e5c60f1c
GSB
75 if (ctx->log_fn == NULL)
76 return;
77
ecd40ee4 78 va_start(args, format);
1bdd951e 79 ctx->log_fn(ctx->log_data, priority, file, line, fn, format, args);
ecd40ee4
LDM
80 va_end(args);
81}
82
115bcd52
EV
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)
ecd40ee4 86{
1bdd951e 87 FILE *fp = data;
e3cb0900
GSB
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 }
8c1c901e
EV
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);
1bdd951e 123 vfprintf(fp, format, args);
ecd40ee4
LDM
124}
125
f7f28510 126KMOD_EXPORT const char *kmod_get_dirname(const struct kmod_ctx *ctx)
221631d5 127{
3cb11a59
TS
128 if (ctx == NULL)
129 return NULL;
130
221631d5
LDM
131 return ctx->dirname;
132}
133
6d177553 134KMOD_EXPORT void *kmod_get_userdata(const struct kmod_ctx *ctx)
ecd40ee4
LDM
135{
136 if (ctx == NULL)
137 return NULL;
1ce08a56 138 return (void *)ctx->userdata;
ecd40ee4
LDM
139}
140
1ce08a56 141KMOD_EXPORT void kmod_set_userdata(struct kmod_ctx *ctx, const void *userdata)
ecd40ee4
LDM
142{
143 if (ctx == NULL)
144 return;
145 ctx->userdata = userdata;
146}
147
148static int log_priority(const char *priority)
149{
150 char *endptr;
dcd652b5 151 long prio;
ecd40ee4 152
dcd652b5 153 errno = 0;
ecd40ee4 154 prio = strtol(priority, &endptr, 10);
dcd652b5
TS
155 if (errno == ERANGE || prio < INT_MIN || prio > INT_MAX)
156 return 0;
ecd40ee4
LDM
157 if (endptr[0] == '\0' || isspace(endptr[0]))
158 return prio;
a3f9ae28 159 if (strstartswith(priority, "err"))
ecd40ee4 160 return LOG_ERR;
a3f9ae28 161 if (strstartswith(priority, "info"))
ecd40ee4 162 return LOG_INFO;
a3f9ae28 163 if (strstartswith(priority, "debug"))
ecd40ee4
LDM
164 return LOG_DEBUG;
165 return 0;
166}
167
9d1fb317 168static const char *dirname_default_prefix = MODULE_DIRECTORY;
904c63aa 169
1ce08a56 170static char *get_kernel_release(const char *dirname)
221631d5
LDM
171{
172 struct utsname u;
904c63aa
LDM
173 char *p;
174
175 if (dirname != NULL)
2e092e19 176 return path_make_absolute_cwd(dirname);
221631d5
LDM
177
178 if (uname(&u) < 0)
179 return NULL;
180
904c63aa
LDM
181 if (asprintf(&p, "%s/%s", dirname_default_prefix, u.release) < 0)
182 return NULL;
183
184 return p;
221631d5
LDM
185}
186
30077bf1
LDM
187static 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
115bcd52 194 fd = open(path, O_RDONLY | O_CLOEXEC);
30077bf1
LDM
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) {
115bcd52 204 ERR(ctx, "could not read from '%s': %s\n", path, strerror(-err));
30077bf1
LDM
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
115bcd52 220KMOD_EXPORT struct kmod_ctx *kmod_new(const char *dirname, const char *const *config_paths)
ecd40ee4
LDM
221{
222 const char *env;
52a7704f 223 struct kmod_ctx *ctx;
d13e606f 224 int err;
ecd40ee4 225
52a7704f
LDM
226 ctx = calloc(1, sizeof(struct kmod_ctx));
227 if (!ctx)
228 return NULL;
ecd40ee4 229
52a7704f 230 ctx->refcount = 1;
1bdd951e
GSB
231 ctx->log_fn = log_filep;
232 ctx->log_data = stderr;
52a7704f 233 ctx->log_priority = LOG_ERR;
ecd40ee4 234
904c63aa 235 ctx->dirname = get_kernel_release(dirname);
a5031e28
TS
236 if (ctx->dirname == NULL) {
237 ERR(ctx, "could not retrieve directory\n");
238 goto fail;
239 }
221631d5 240
ecd40ee4 241 /* environment overwrites config */
41a51c2a 242 env = secure_getenv("KMOD_LOG");
ecd40ee4 243 if (env != NULL)
52a7704f 244 kmod_set_log_priority(ctx, log_priority(env));
ecd40ee4 245
30077bf1
LDM
246 ctx->kernel_compression = get_kernel_compression(ctx);
247
cb8d4d3e
GSB
248 if (config_paths == NULL)
249 config_paths = default_config_paths;
250 err = kmod_config_new(ctx, &ctx->config, config_paths);
d13e606f 251 if (err < 0) {
fd186ae9
LDM
252 ERR(ctx, "could not create config\n");
253 goto fail;
254 }
255
822913d7 256 ctx->modules_by_name = hash_new(KMOD_HASH_SIZE, NULL);
fd186ae9
LDM
257 if (ctx->modules_by_name == NULL) {
258 ERR(ctx, "could not create by-name hash\n");
259 goto fail;
d13e606f 260 }
7c2ab358 261
ae6df84a
LDM
262 INFO(ctx, "ctx %p created\n", ctx);
263 DBG(ctx, "log_priority=%d\n", ctx->log_priority);
52a7704f
LDM
264
265 return ctx;
fd186ae9
LDM
266
267fail:
268 free(ctx->modules_by_name);
269 free(ctx->dirname);
270 free(ctx);
271 return NULL;
ecd40ee4
LDM
272}
273
586fc304 274KMOD_EXPORT struct kmod_ctx *kmod_ref(struct kmod_ctx *ctx)
ecd40ee4
LDM
275{
276 if (ctx == NULL)
277 return NULL;
278 ctx->refcount++;
279 return ctx;
280}
281
586fc304 282KMOD_EXPORT struct kmod_ctx *kmod_unref(struct kmod_ctx *ctx)
ecd40ee4
LDM
283{
284 if (ctx == NULL)
285 return NULL;
4d1e689a
LDM
286
287 if (--ctx->refcount > 0)
ecd40ee4 288 return ctx;
33bb69b9 289
ae6df84a 290 INFO(ctx, "context %p released\n", ctx);
33bb69b9
LDM
291
292 kmod_unload_resources(ctx);
822913d7 293 hash_free(ctx->modules_by_name);
1ce08a56 294 free(ctx->dirname);
d13e606f
GSB
295 if (ctx->config)
296 kmod_config_free(ctx->config);
33bb69b9 297
ecd40ee4
LDM
298 free(ctx);
299 return NULL;
300}
301
586fc304 302KMOD_EXPORT void kmod_set_log_fn(struct kmod_ctx *ctx,
115bcd52
EV
303 void (*log_fn)(void *data, int priority,
304 const char *file, int line, const char *fn,
1bdd951e 305 const char *format, va_list args),
115bcd52 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
6d177553 315KMOD_EXPORT int kmod_get_log_priority(const struct kmod_ctx *ctx)
ecd40ee4 316{
e5c60f1c
GSB
317 if (ctx == NULL)
318 return -1;
ecd40ee4
LDM
319 return ctx->log_priority;
320}
321
586fc304 322KMOD_EXPORT void kmod_set_log_priority(struct kmod_ctx *ctx, int priority)
ecd40ee4 323{
e5c60f1c
GSB
324 if (ctx == NULL)
325 return;
ecd40ee4
LDM
326 ctx->log_priority = priority;
327}
7f3eb0cc 328
115bcd52 329struct kmod_module *kmod_pool_get_module(struct kmod_ctx *ctx, const char *key)
fd186ae9
LDM
330{
331 struct kmod_module *mod;
332
822913d7 333 mod = hash_find(ctx->modules_by_name, key);
fd186ae9 334
8bdeca11 335 DBG(ctx, "get module name='%s' found=%p\n", key, mod);
fd186ae9
LDM
336
337 return mod;
338}
339
808eb4b8 340int kmod_pool_add_module(struct kmod_ctx *ctx, struct kmod_module *mod, const char *key)
fd186ae9 341{
8bdeca11 342 DBG(ctx, "add %p key='%s'\n", mod, key);
fd186ae9 343
808eb4b8 344 return hash_add(ctx->modules_by_name, key, mod);
fd186ae9
LDM
345}
346
115bcd52 347void kmod_pool_del_module(struct kmod_ctx *ctx, struct kmod_module *mod, const char *key)
fd186ae9 348{
8bdeca11 349 DBG(ctx, "del %p key='%s'\n", mod, key);
fd186ae9 350
822913d7 351 hash_del(ctx->modules_by_name, key);
fd186ae9 352}
9ba6f57b 353
a009482c 354static int kmod_lookup_alias_from_alias_bin(struct kmod_ctx *ctx,
115bcd52
EV
355 enum kmod_index index_number,
356 const char *name, struct kmod_list **list)
9ba6f57b 357{
6f1bc6e3 358 int err, nmatch = 0;
0fbdfef3 359 struct index_file *idx;
9ba6f57b
LDM
360 struct index_value *realnames, *realname;
361
ebd04769
TS
362 assert(*list == NULL);
363
65a84f55 364 if (ctx->indexes[index_number] != NULL) {
fcc367f9 365 DBG(ctx, "use mmapped index '%s' for name=%s\n",
115bcd52
EV
366 index_files[index_number].fn, name);
367 realnames = index_mm_searchwild(ctx->indexes[index_number], name);
9fd58f30 368 } else {
65a84f55
LDM
369 char fn[PATH_MAX];
370
3b209959 371 snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname,
115bcd52 372 index_files[index_number].fn);
9ba6f57b 373
65a84f55 374 DBG(ctx, "file=%s name=%s\n", fn, name);
9ba6f57b 375
65a84f55
LDM
376 idx = index_file_open(fn);
377 if (idx == NULL)
378 return -ENOSYS;
9ba6f57b 379
65a84f55
LDM
380 realnames = index_searchwild(idx, name);
381 index_file_close(idx);
382 }
4272d087 383
a955f71f 384 for (realname = realnames; realname; realname = realname->next) {
9ba6f57b 385 struct kmod_module *mod;
ebd04769 386 struct kmod_list *node;
9ba6f57b 387
ee3b3ff2 388 err = kmod_module_new_from_alias(ctx, name, realname->value, &mod);
9ba6f57b 389 if (err < 0) {
dfa96f15
GSB
390 ERR(ctx, "Could not create module for alias=%s realname=%s: %s\n",
391 name, realname->value, strerror(-err));
23fc91c6 392 goto fail;
9ba6f57b
LDM
393 }
394
ebd04769
TS
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;
23fc91c6 403 nmatch++;
9ba6f57b
LDM
404 }
405
9ba6f57b 406 index_values_free(realnames);
23fc91c6
LDM
407 return nmatch;
408
409fail:
ebd04769 410 kmod_list_release(*list, kmod_module_unref);
e84d912b 411 index_values_free(realnames);
9ba6f57b 412 return err;
7b30f4f4
LDM
413}
414
7b30f4f4 415int kmod_lookup_alias_from_symbols_file(struct kmod_ctx *ctx, const char *name,
115bcd52 416 struct kmod_list **list)
7b30f4f4 417{
0c010fae 418 if (!strstartswith(name, "symbol:"))
7b30f4f4
LDM
419 return 0;
420
115bcd52
EV
421 return kmod_lookup_alias_from_alias_bin(ctx, KMOD_INDEX_MODULES_SYMBOL, name,
422 list);
9ba6f57b
LDM
423}
424
49e61ca3 425int kmod_lookup_alias_from_aliases_file(struct kmod_ctx *ctx, const char *name,
115bcd52 426 struct kmod_list **list)
49e61ca3 427{
115bcd52 428 return kmod_lookup_alias_from_alias_bin(ctx, KMOD_INDEX_MODULES_ALIAS, name, list);
49e61ca3
LDM
429}
430
3489c2d0
EV
431static char *lookup_file(struct kmod_ctx *ctx, enum kmod_index index_number,
432 const char *name)
3805274b 433{
fd44a98a 434 char *line;
3805274b 435
3489c2d0 436 if (ctx->indexes[index_number]) {
fcc367f9 437 DBG(ctx, "use mmapped index '%s' modname=%s\n",
3489c2d0
EV
438 index_files[index_number].fn, name);
439 line = index_mm_search(ctx->indexes[index_number], name);
ee1d188f
LDM
440 } else {
441 struct index_file *idx;
442 char fn[PATH_MAX];
443
444 snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname,
3489c2d0 445 index_files[index_number].fn);
ee1d188f
LDM
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);
fd44a98a 451 return NULL;
ee1d188f
LDM
452 }
453
454 line = index_search(idx, name);
455 index_file_close(idx);
456 }
457
fd44a98a
HJ
458 return line;
459}
460
69a512f7 461static bool lookup_builtin_file(struct kmod_ctx *ctx, const char *name)
3489c2d0 462{
5322bb8f 463 _cleanup_free_ char *line = lookup_file(ctx, KMOD_INDEX_MODULES_BUILTIN, name);
69a512f7 464
5322bb8f 465 return line;
3489c2d0
EV
466}
467
115bcd52
EV
468int kmod_lookup_alias_from_kernel_builtin_file(struct kmod_ctx *ctx, const char *name,
469 struct kmod_list **list)
b866b216
AG
470{
471 struct kmod_list *l;
89443220
LDM
472 int ret;
473
115bcd52 474 ret = kmod_lookup_alias_from_alias_bin(ctx, KMOD_INDEX_MODULES_BUILTIN_ALIAS,
89443220
LDM
475 name, list);
476
477 kmod_list_foreach(l, *list) {
478 struct kmod_module *mod = l->data;
479 kmod_module_set_builtin(mod, true);
b866b216
AG
480 }
481
482 return ret;
483}
484
fd44a98a 485int kmod_lookup_alias_from_builtin_file(struct kmod_ctx *ctx, const char *name,
115bcd52 486 struct kmod_list **list)
fd44a98a 487{
fd44a98a
HJ
488 assert(*list == NULL);
489
69a512f7 490 if (lookup_builtin_file(ctx, name)) {
ee1d188f 491 struct kmod_module *mod;
ebd04769 492 struct kmod_list *node;
69a512f7 493 int err;
ee1d188f
LDM
494
495 err = kmod_module_new_from_name(ctx, name, &mod);
496 if (err < 0) {
115bcd52
EV
497 ERR(ctx, "Could not create module from name %s: %s\n", name,
498 strerror(-err));
69a512f7 499 return err;
ee1d188f
LDM
500 }
501
fd44a98a
HJ
502 /* already mark it as builtin since it's being created from
503 * this index */
ee1d188f 504 kmod_module_set_builtin(mod, true);
ebd04769
TS
505 node = kmod_list_append(*list, mod);
506 if (node == NULL) {
507 ERR(ctx, "out of memory\n");
508 kmod_module_unref(mod);
69a512f7 509 return -ENOMEM;
ebd04769
TS
510 }
511 *list = node;
3805274b
LDM
512 }
513
69a512f7 514 return 0;
3805274b
LDM
515}
516
fd44a98a
HJ
517bool kmod_lookup_alias_is_builtin(struct kmod_ctx *ctx, const char *name)
518{
69a512f7 519 return lookup_builtin_file(ctx, name);
fd44a98a
HJ
520}
521
671d4894 522char *kmod_search_moddep(struct kmod_ctx *ctx, const char *name)
1eb2ef69 523{
3489c2d0 524 return lookup_file(ctx, KMOD_INDEX_MODULES_DEP, name);
1eb2ef69
LDM
525}
526
64700e47 527int kmod_lookup_alias_from_moddep_file(struct kmod_ctx *ctx, const char *name,
115bcd52 528 struct kmod_list **list)
64700e47 529{
1eb2ef69 530 char *line;
64700e47
LDM
531 int n = 0;
532
ebd04769
TS
533 assert(*list == NULL);
534
64700e47
LDM
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
671d4894 542 line = kmod_search_moddep(ctx, name);
64700e47
LDM
543 if (line != NULL) {
544 struct kmod_module *mod;
ebd04769 545 struct kmod_list *node;
64700e47
LDM
546
547 n = kmod_module_new_from_name(ctx, name, &mod);
548 if (n < 0) {
115bcd52
EV
549 ERR(ctx, "Could not create module from name %s: %s\n", name,
550 strerror(-n));
64700e47
LDM
551 goto finish;
552 }
553
ebd04769
TS
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;
671d4894 562 kmod_module_parse_depline(mod, line);
64700e47
LDM
563 }
564
565finish:
566 free(line);
64700e47
LDM
567
568 return n;
569}
570
7f3eb0cc 571int kmod_lookup_alias_from_config(struct kmod_ctx *ctx, const char *name,
115bcd52 572 struct kmod_list **list)
7f3eb0cc 573{
d13e606f 574 struct kmod_config *config = ctx->config;
7f3eb0cc 575 struct kmod_list *l;
23fc91c6 576 int err, nmatch = 0;
7f3eb0cc 577
ebd04769
TS
578 assert(*list == NULL);
579
7f3eb0cc
LDM
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;
ebd04769 586 struct kmod_list *node;
7f3eb0cc 587
115bcd52 588 err = kmod_module_new_from_alias(ctx, aliasname, modname, &mod);
7f3eb0cc 589 if (err < 0) {
115bcd52
EV
590 ERR(ctx,
591 "Could not create module for alias=%s modname=%s: %s\n",
dfa96f15 592 name, modname, strerror(-err));
23fc91c6 593 goto fail;
7f3eb0cc
LDM
594 }
595
ebd04769
TS
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;
23fc91c6 604 nmatch++;
7f3eb0cc
LDM
605 }
606 }
607
23fc91c6
LDM
608 return nmatch;
609
610fail:
ebd04769 611 kmod_list_release(*list, kmod_module_unref);
23fc91c6 612 return err;
7f3eb0cc 613}
1487a64f 614
f4fc5523 615int kmod_lookup_alias_from_commands(struct kmod_ctx *ctx, const char *name,
115bcd52 616 struct kmod_list **list)
f4fc5523
LDM
617{
618 struct kmod_config *config = ctx->config;
619 struct kmod_list *l, *node;
620 int err, nmatch = 0;
621
ebd04769
TS
622 assert(*list == NULL);
623
f4fc5523
LDM
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) {
dfa96f15
GSB
633 ERR(ctx, "Could not create module from name %s: %s\n",
634 modname, strerror(-err));
f4fc5523
LDM
635 return err;
636 }
637
638 node = kmod_list_append(*list, mod);
639 if (node == NULL) {
640 ERR(ctx, "out of memory\n");
ebd04769 641 kmod_module_unref(mod);
f4fc5523
LDM
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) {
dfa96f15
GSB
670 ERR(ctx, "Could not create module from name %s: %s\n",
671 modname, strerror(-err));
f4fc5523
LDM
672 return err;
673 }
674
675 node = kmod_list_append(*list, mod);
676 if (node == NULL) {
677 ERR(ctx, "out of memory\n");
ebd04769 678 kmod_module_unref(mod);
f4fc5523
LDM
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
ece09aac
LDM
698void 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
450bd1b4
MM
708void 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
c4dc3ca8
LDM
718static 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
6068aaae 725 if (stamp != stat_mstamp(&st))
c4dc3ca8
LDM
726 return true;
727
728 return false;
729}
730
c4dc3ca8
LDM
731KMOD_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
b08314f7 746 for (i = 0; i < _KMOD_INDEX_MODULES_SIZE; i++) {
c4dc3ca8
LDM
747 char path[PATH_MAX];
748
749 if (ctx->indexes[i] == NULL)
750 continue;
751
115bcd52 752 snprintf(path, sizeof(path), "%s/%s.bin", ctx->dirname, index_files[i].fn);
c4dc3ca8
LDM
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
33bb69b9
LDM
761KMOD_EXPORT int kmod_load_resources(struct kmod_ctx *ctx)
762{
d8d1d540 763 int ret = 0;
33bb69b9
LDM
764 size_t i;
765
766 if (ctx == NULL)
767 return -ENOENT;
768
b08314f7 769 for (i = 0; i < _KMOD_INDEX_MODULES_SIZE; i++) {
6de8f6e9 770 char path[PATH_MAX];
3e676766 771
16ca3666 772 if (ctx->indexes[i] != NULL) {
115bcd52 773 INFO(ctx, "Index %s already loaded\n", index_files[i].fn);
3e676766
LDM
774 continue;
775 }
79d57fcb 776
115bcd52
EV
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]);
d8d1d540
LDM
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 }
33bb69b9
LDM
790 }
791
3bd7187f
LDM
792 if (ret)
793 kmod_unload_resources(ctx);
33bb69b9 794
3bd7187f 795 return ret;
33bb69b9
LDM
796}
797
798KMOD_EXPORT void kmod_unload_resources(struct kmod_ctx *ctx)
799{
800 size_t i;
801
802 if (ctx == NULL)
803 return;
804
b08314f7 805 for (i = 0; i < _KMOD_INDEX_MODULES_SIZE; i++) {
33bb69b9
LDM
806 if (ctx->indexes[i] != NULL) {
807 index_mm_close(ctx->indexes[i]);
808 ctx->indexes[i] = NULL;
9fd58f30 809 ctx->indexes_stamp[i] = 0;
33bb69b9
LDM
810 }
811 }
812}
bd3f5535 813
115bcd52 814KMOD_EXPORT int kmod_dump_index(struct kmod_ctx *ctx, enum kmod_index type, int fd)
758428a7
LDM
815{
816 if (ctx == NULL)
817 return -ENOSYS;
818
98f38c5d
EV
819#if defined(__clang__)
820#pragma clang diagnostic push
821#pragma clang diagnostic ignored "-Wtautological-unsigned-enum-zero-compare"
822#endif
758428a7
LDM
823 if (type < 0 || type >= _KMOD_INDEX_MODULES_SIZE)
824 return -ENOENT;
98f38c5d
EV
825#if defined(__clang__)
826#pragma clang diagnostic pop
827#endif
758428a7
LDM
828
829 if (ctx->indexes[type] != NULL) {
fcc367f9 830 DBG(ctx, "use mmapped index '%s'\n", index_files[type].fn);
e9ef6032 831 index_mm_dump(ctx->indexes[type], fd, index_files[type].alias_prefix);
758428a7
LDM
832 } else {
833 char fn[PATH_MAX];
834 struct index_file *idx;
835
115bcd52 836 snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname, index_files[type].fn);
758428a7
LDM
837
838 DBG(ctx, "file=%s\n", fn);
839
840 idx = index_file_open(fn);
841 if (idx == NULL)
842 return -ENOSYS;
843
e9ef6032 844 index_dump(idx, fd, index_files[type].alias_prefix);
758428a7
LDM
845 index_file_close(idx);
846 }
847
848 return 0;
849}
850
e7fc2c86 851const struct kmod_config *kmod_get_config(const struct kmod_ctx *ctx)
c1c9c446 852{
e7fc2c86 853 return ctx->config;
8b5ee618 854}
09c9f8c5
LDM
855
856enum kmod_file_compression_type kmod_get_kernel_compression(const struct kmod_ctx *ctx)
857{
858 return ctx->kernel_compression;
859}