• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libkmod - interface to kernel module operations
3  *
4  * Copyright (C) 2011-2013  ProFUSION embedded systems
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; either
9  * version 2.1 of the License, or (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <assert.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <fnmatch.h>
24 #include <limits.h>
25 #include <stdarg.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/stat.h>
32 #include <sys/utsname.h>
33 
34 #include <shared/hash.h>
35 #include <shared/util.h>
36 
37 #include "libkmod.h"
38 #include "libkmod-internal.h"
39 #include "libkmod-index.h"
40 
41 #define KMOD_HASH_SIZE (256)
42 #define KMOD_LRU_MAX (128)
43 #define _KMOD_INDEX_MODULES_SIZE KMOD_INDEX_MODULES_BUILTIN + 1
44 
45 /**
46  * SECTION:libkmod
47  * @short_description: libkmod context
48  *
49  * The context contains the default values for the library user,
50  * and is passed to all library operations.
51  */
52 
53 static struct _index_files {
54 	const char *fn;
55 	const char *prefix;
56 } index_files[] = {
57 	[KMOD_INDEX_MODULES_DEP] = { .fn = "modules.dep", .prefix = "" },
58 	[KMOD_INDEX_MODULES_ALIAS] = { .fn = "modules.alias", .prefix = "alias " },
59 	[KMOD_INDEX_MODULES_SYMBOL] = { .fn = "modules.symbols", .prefix = "alias "},
60 	[KMOD_INDEX_MODULES_BUILTIN_ALIAS] = { .fn = "modules.builtin.alias", .prefix = "" },
61 	[KMOD_INDEX_MODULES_BUILTIN] = { .fn = "modules.builtin", .prefix = ""},
62 };
63 
64 static const char *default_config_paths[] = {
65 	SYSCONFDIR "/modprobe.d",
66 	"/run/modprobe.d",
67 	"/usr/local/lib/modprobe.d",
68 	"/lib/modprobe.d",
69 	NULL
70 };
71 
72 /**
73  * kmod_ctx:
74  *
75  * Opaque object representing the library context.
76  */
77 struct kmod_ctx {
78 	int refcount;
79 	int log_priority;
80 	void (*log_fn)(void *data,
81 			int priority, const char *file, int line,
82 			const char *fn, const char *format, va_list args);
83 	void *log_data;
84 	const void *userdata;
85 	char *dirname;
86 	struct kmod_config *config;
87 	struct hash *modules_by_name;
88 	struct index_mm *indexes[_KMOD_INDEX_MODULES_SIZE];
89 	unsigned long long indexes_stamp[_KMOD_INDEX_MODULES_SIZE];
90 };
91 
kmod_log(const struct kmod_ctx * ctx,int priority,const char * file,int line,const char * fn,const char * format,...)92 void kmod_log(const struct kmod_ctx *ctx,
93 		int priority, const char *file, int line, const char *fn,
94 		const char *format, ...)
95 {
96 	va_list args;
97 
98 	if (ctx->log_fn == NULL)
99 		return;
100 
101 	va_start(args, format);
102 	ctx->log_fn(ctx->log_data, priority, file, line, fn, format, args);
103 	va_end(args);
104 }
105 
106 _printf_format_(6, 0)
log_filep(void * data,int priority,const char * file,int line,const char * fn,const char * format,va_list args)107 static void log_filep(void *data,
108 			int priority, const char *file, int line,
109 			const char *fn, const char *format, va_list args)
110 {
111 	FILE *fp = data;
112 #ifdef ENABLE_DEBUG
113 	char buf[16];
114 	const char *priname;
115 	switch (priority) {
116 	case LOG_EMERG:
117 		priname = "EMERGENCY";
118 		break;
119 	case LOG_ALERT:
120 		priname = "ALERT";
121 		break;
122 	case LOG_CRIT:
123 		priname = "CRITICAL";
124 		break;
125 	case LOG_ERR:
126 		priname = "ERROR";
127 		break;
128 	case LOG_WARNING:
129 		priname = "WARNING";
130 		break;
131 	case LOG_NOTICE:
132 		priname = "NOTICE";
133 		break;
134 	case LOG_INFO:
135 		priname = "INFO";
136 		break;
137 	case LOG_DEBUG:
138 		priname = "DEBUG";
139 		break;
140 	default:
141 		snprintf(buf, sizeof(buf), "L:%d", priority);
142 		priname = buf;
143 	}
144 	fprintf(fp, "libkmod: %s %s:%d %s: ", priname, file, line, fn);
145 #else
146 	fprintf(fp, "libkmod: %s: ", fn);
147 #endif
148 	vfprintf(fp, format, args);
149 }
150 
151 
152 /**
153  * kmod_get_dirname:
154  * @ctx: kmod library context
155  *
156  * Retrieve the absolute path used for linux modules in this context. The path
157  * is computed from the arguments to kmod_new().
158  */
kmod_get_dirname(const struct kmod_ctx * ctx)159 KMOD_EXPORT const char *kmod_get_dirname(const struct kmod_ctx *ctx)
160 {
161 	return ctx->dirname;
162 }
163 
164 /**
165  * kmod_get_userdata:
166  * @ctx: kmod library context
167  *
168  * Retrieve stored data pointer from library context. This might be useful
169  * to access from callbacks.
170  *
171  * Returns: stored userdata
172  */
kmod_get_userdata(const struct kmod_ctx * ctx)173 KMOD_EXPORT void *kmod_get_userdata(const struct kmod_ctx *ctx)
174 {
175 	if (ctx == NULL)
176 		return NULL;
177 	return (void *)ctx->userdata;
178 }
179 
180 /**
181  * kmod_set_userdata:
182  * @ctx: kmod library context
183  * @userdata: data pointer
184  *
185  * Store custom @userdata in the library context.
186  */
kmod_set_userdata(struct kmod_ctx * ctx,const void * userdata)187 KMOD_EXPORT void kmod_set_userdata(struct kmod_ctx *ctx, const void *userdata)
188 {
189 	if (ctx == NULL)
190 		return;
191 	ctx->userdata = userdata;
192 }
193 
log_priority(const char * priority)194 static int log_priority(const char *priority)
195 {
196 	char *endptr;
197 	int prio;
198 
199 	prio = strtol(priority, &endptr, 10);
200 	if (endptr[0] == '\0' || isspace(endptr[0]))
201 		return prio;
202 	if (strncmp(priority, "err", 3) == 0)
203 		return LOG_ERR;
204 	if (strncmp(priority, "info", 4) == 0)
205 		return LOG_INFO;
206 	if (strncmp(priority, "debug", 5) == 0)
207 		return LOG_DEBUG;
208 	return 0;
209 }
210 
211 static const char *dirname_default_prefix = "/lib/modules";
212 
get_kernel_release(const char * dirname)213 static char *get_kernel_release(const char *dirname)
214 {
215 	struct utsname u;
216 	char *p;
217 
218 	if (dirname != NULL)
219 		return path_make_absolute_cwd(dirname);
220 
221 	if (uname(&u) < 0)
222 		return NULL;
223 
224 	if (asprintf(&p, "%s/%s", dirname_default_prefix, u.release) < 0)
225 		return NULL;
226 
227 	return p;
228 }
229 
230 /**
231  * kmod_new:
232  * @dirname: what to consider as linux module's directory, if NULL
233  *           defaults to /lib/modules/`uname -r`. If it's relative,
234  *           it's treated as relative to the current working directory.
235  *           Otherwise, give an absolute dirname.
236  * @config_paths: ordered array of paths (directories or files) where
237  *                to load from user-defined configuration parameters such as
238  *                alias, blacklists, commands (install, remove). If NULL
239  *                defaults to /etc/modprobe.d, /run/modprobe.d,
240  *                /usr/local/lib/modprobe.d and /lib/modprobe.d. Give an empty
241  *                vector if configuration should not be read. This array must
242  *                be null terminated.
243  *
244  * Create kmod library context. This reads the kmod configuration
245  * and fills in the default values.
246  *
247  * The initial refcount is 1, and needs to be decremented to
248  * release the resources of the kmod library context.
249  *
250  * Returns: a new kmod library context
251  */
kmod_new(const char * dirname,const char * const * config_paths)252 KMOD_EXPORT struct kmod_ctx *kmod_new(const char *dirname,
253 					const char * const *config_paths)
254 {
255 	const char *env;
256 	struct kmod_ctx *ctx;
257 	int err;
258 
259 	ctx = calloc(1, sizeof(struct kmod_ctx));
260 	if (!ctx)
261 		return NULL;
262 
263 	ctx->refcount = 1;
264 	ctx->log_fn = log_filep;
265 	ctx->log_data = stderr;
266 	ctx->log_priority = LOG_ERR;
267 
268 	ctx->dirname = get_kernel_release(dirname);
269 
270 	/* environment overwrites config */
271 	env = secure_getenv("KMOD_LOG");
272 	if (env != NULL)
273 		kmod_set_log_priority(ctx, log_priority(env));
274 
275 	if (config_paths == NULL)
276 		config_paths = default_config_paths;
277 	err = kmod_config_new(ctx, &ctx->config, config_paths);
278 	if (err < 0) {
279 		ERR(ctx, "could not create config\n");
280 		goto fail;
281 	}
282 
283 	ctx->modules_by_name = hash_new(KMOD_HASH_SIZE, NULL);
284 	if (ctx->modules_by_name == NULL) {
285 		ERR(ctx, "could not create by-name hash\n");
286 		goto fail;
287 	}
288 
289 	INFO(ctx, "ctx %p created\n", ctx);
290 	DBG(ctx, "log_priority=%d\n", ctx->log_priority);
291 
292 	return ctx;
293 
294 fail:
295 	free(ctx->modules_by_name);
296 	free(ctx->dirname);
297 	free(ctx);
298 	return NULL;
299 }
300 
301 /**
302  * kmod_ref:
303  * @ctx: kmod library context
304  *
305  * Take a reference of the kmod library context.
306  *
307  * Returns: the passed kmod library context
308  */
kmod_ref(struct kmod_ctx * ctx)309 KMOD_EXPORT struct kmod_ctx *kmod_ref(struct kmod_ctx *ctx)
310 {
311 	if (ctx == NULL)
312 		return NULL;
313 	ctx->refcount++;
314 	return ctx;
315 }
316 
317 /**
318  * kmod_unref:
319  * @ctx: kmod library context
320  *
321  * Drop a reference of the kmod library context. If the refcount
322  * reaches zero, the resources of the context will be released.
323  *
324  * Returns: the passed kmod library context or NULL if it's freed
325  */
kmod_unref(struct kmod_ctx * ctx)326 KMOD_EXPORT struct kmod_ctx *kmod_unref(struct kmod_ctx *ctx)
327 {
328 	if (ctx == NULL)
329 		return NULL;
330 
331 	if (--ctx->refcount > 0)
332 		return ctx;
333 
334 	INFO(ctx, "context %p released\n", ctx);
335 
336 	kmod_unload_resources(ctx);
337 	hash_free(ctx->modules_by_name);
338 	free(ctx->dirname);
339 	if (ctx->config)
340 		kmod_config_free(ctx->config);
341 
342 	free(ctx);
343 	return NULL;
344 }
345 
346 /**
347  * kmod_set_log_fn:
348  * @ctx: kmod library context
349  * @log_fn: function to be called for logging messages
350  * @data: data to pass to log function
351  *
352  * The built-in logging writes to stderr. It can be
353  * overridden by a custom function, to plug log messages
354  * into the user's logging functionality.
355  */
kmod_set_log_fn(struct kmod_ctx * ctx,void (* log_fn)(void * data,int priority,const char * file,int line,const char * fn,const char * format,va_list args),const void * data)356 KMOD_EXPORT void kmod_set_log_fn(struct kmod_ctx *ctx,
357 					void (*log_fn)(void *data,
358 						int priority, const char *file,
359 						int line, const char *fn,
360 						const char *format, va_list args),
361 					const void *data)
362 {
363 	if (ctx == NULL)
364 		return;
365 	ctx->log_fn = log_fn;
366 	ctx->log_data = (void *)data;
367 	INFO(ctx, "custom logging function %p registered\n", log_fn);
368 }
369 
370 /**
371  * kmod_get_log_priority:
372  * @ctx: kmod library context
373  *
374  * Returns: the current logging priority
375  */
kmod_get_log_priority(const struct kmod_ctx * ctx)376 KMOD_EXPORT int kmod_get_log_priority(const struct kmod_ctx *ctx)
377 {
378 	if (ctx == NULL)
379 		return -1;
380 	return ctx->log_priority;
381 }
382 
383 /**
384  * kmod_set_log_priority:
385  * @ctx: kmod library context
386  * @priority: the new logging priority
387  *
388  * Set the current logging priority. The value controls which messages
389  * are logged.
390  */
kmod_set_log_priority(struct kmod_ctx * ctx,int priority)391 KMOD_EXPORT void kmod_set_log_priority(struct kmod_ctx *ctx, int priority)
392 {
393 	if (ctx == NULL)
394 		return;
395 	ctx->log_priority = priority;
396 }
397 
kmod_pool_get_module(struct kmod_ctx * ctx,const char * key)398 struct kmod_module *kmod_pool_get_module(struct kmod_ctx *ctx,
399 							const char *key)
400 {
401 	struct kmod_module *mod;
402 
403 	mod = hash_find(ctx->modules_by_name, key);
404 
405 	DBG(ctx, "get module name='%s' found=%p\n", key, mod);
406 
407 	return mod;
408 }
409 
kmod_pool_add_module(struct kmod_ctx * ctx,struct kmod_module * mod,const char * key)410 void kmod_pool_add_module(struct kmod_ctx *ctx, struct kmod_module *mod,
411 							const char *key)
412 {
413 	DBG(ctx, "add %p key='%s'\n", mod, key);
414 
415 	hash_add(ctx->modules_by_name, key, mod);
416 }
417 
kmod_pool_del_module(struct kmod_ctx * ctx,struct kmod_module * mod,const char * key)418 void kmod_pool_del_module(struct kmod_ctx *ctx, struct kmod_module *mod,
419 							const char *key)
420 {
421 	DBG(ctx, "del %p key='%s'\n", mod, key);
422 
423 	hash_del(ctx->modules_by_name, key);
424 }
425 
kmod_lookup_alias_from_alias_bin(struct kmod_ctx * ctx,enum kmod_index index_number,const char * name,struct kmod_list ** list)426 static int kmod_lookup_alias_from_alias_bin(struct kmod_ctx *ctx,
427 						enum kmod_index index_number,
428 						const char *name,
429 						struct kmod_list **list)
430 {
431 	int err, nmatch = 0;
432 	struct index_file *idx;
433 	struct index_value *realnames, *realname;
434 
435 	if (ctx->indexes[index_number] != NULL) {
436 		DBG(ctx, "use mmaped index '%s' for name=%s\n",
437 			index_files[index_number].fn, name);
438 		realnames = index_mm_searchwild(ctx->indexes[index_number],
439 									name);
440 	} else {
441 		char fn[PATH_MAX];
442 
443 		snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname,
444 					index_files[index_number].fn);
445 
446 		DBG(ctx, "file=%s name=%s\n", fn, name);
447 
448 		idx = index_file_open(fn);
449 		if (idx == NULL)
450 			return -ENOSYS;
451 
452 		realnames = index_searchwild(idx, name);
453 		index_file_close(idx);
454 	}
455 
456 	for (realname = realnames; realname; realname = realname->next) {
457 		struct kmod_module *mod;
458 
459 		err = kmod_module_new_from_alias(ctx, name, realname->value, &mod);
460 		if (err < 0) {
461 			ERR(ctx, "Could not create module for alias=%s realname=%s: %s\n",
462 			    name, realname->value, strerror(-err));
463 			goto fail;
464 		}
465 
466 		*list = kmod_list_append(*list, mod);
467 		nmatch++;
468 	}
469 
470 	index_values_free(realnames);
471 	return nmatch;
472 
473 fail:
474 	*list = kmod_list_remove_n_latest(*list, nmatch);
475 	index_values_free(realnames);
476 	return err;
477 
478 }
479 
kmod_lookup_alias_from_symbols_file(struct kmod_ctx * ctx,const char * name,struct kmod_list ** list)480 int kmod_lookup_alias_from_symbols_file(struct kmod_ctx *ctx, const char *name,
481 						struct kmod_list **list)
482 {
483 	if (!strstartswith(name, "symbol:"))
484 		return 0;
485 
486 	return kmod_lookup_alias_from_alias_bin(ctx, KMOD_INDEX_MODULES_SYMBOL,
487 								name, list);
488 }
489 
kmod_lookup_alias_from_aliases_file(struct kmod_ctx * ctx,const char * name,struct kmod_list ** list)490 int kmod_lookup_alias_from_aliases_file(struct kmod_ctx *ctx, const char *name,
491 						struct kmod_list **list)
492 {
493 	return kmod_lookup_alias_from_alias_bin(ctx, KMOD_INDEX_MODULES_ALIAS,
494 								name, list);
495 }
496 
lookup_builtin_file(struct kmod_ctx * ctx,const char * name)497 static char *lookup_builtin_file(struct kmod_ctx *ctx, const char *name)
498 {
499 	char *line;
500 
501 	if (ctx->indexes[KMOD_INDEX_MODULES_BUILTIN]) {
502 		DBG(ctx, "use mmaped index '%s' modname=%s\n",
503 				index_files[KMOD_INDEX_MODULES_BUILTIN].fn,
504 				name);
505 		line = index_mm_search(ctx->indexes[KMOD_INDEX_MODULES_BUILTIN],
506 									name);
507 	} else {
508 		struct index_file *idx;
509 		char fn[PATH_MAX];
510 
511 		snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname,
512 				index_files[KMOD_INDEX_MODULES_BUILTIN].fn);
513 		DBG(ctx, "file=%s modname=%s\n", fn, name);
514 
515 		idx = index_file_open(fn);
516 		if (idx == NULL) {
517 			DBG(ctx, "could not open builtin file '%s'\n", fn);
518 			return NULL;
519 		}
520 
521 		line = index_search(idx, name);
522 		index_file_close(idx);
523 	}
524 
525 	return line;
526 }
527 
kmod_lookup_alias_from_kernel_builtin_file(struct kmod_ctx * ctx,const char * name,struct kmod_list ** list)528 int kmod_lookup_alias_from_kernel_builtin_file(struct kmod_ctx *ctx,
529 						const char *name,
530 						struct kmod_list **list)
531 {
532 	struct kmod_list *l;
533 	int ret;
534 
535 	assert(*list == NULL);
536 
537 	ret = kmod_lookup_alias_from_alias_bin(ctx,
538 					       KMOD_INDEX_MODULES_BUILTIN_ALIAS,
539 					       name, list);
540 
541 	kmod_list_foreach(l, *list) {
542 		struct kmod_module *mod = l->data;
543 		kmod_module_set_builtin(mod, true);
544 	}
545 
546 	return ret;
547 }
548 
kmod_lookup_alias_from_builtin_file(struct kmod_ctx * ctx,const char * name,struct kmod_list ** list)549 int kmod_lookup_alias_from_builtin_file(struct kmod_ctx *ctx, const char *name,
550 						struct kmod_list **list)
551 {
552 	char *line;
553 	int err = 0;
554 
555 	assert(*list == NULL);
556 
557 	line = lookup_builtin_file(ctx, name);
558 	if (line != NULL) {
559 		struct kmod_module *mod;
560 
561 		err = kmod_module_new_from_name(ctx, name, &mod);
562 		if (err < 0) {
563 			ERR(ctx, "Could not create module from name %s: %s\n",
564 							name, strerror(-err));
565 			goto finish;
566 		}
567 
568 		/* already mark it as builtin since it's being created from
569 		 * this index */
570 		kmod_module_set_builtin(mod, true);
571 		*list = kmod_list_append(*list, mod);
572 		if (*list == NULL)
573 			err = -ENOMEM;
574 	}
575 
576 finish:
577 	free(line);
578 	return err;
579 }
580 
kmod_lookup_alias_is_builtin(struct kmod_ctx * ctx,const char * name)581 bool kmod_lookup_alias_is_builtin(struct kmod_ctx *ctx, const char *name)
582 {
583 	_cleanup_free_ char *line;
584 
585 	line = lookup_builtin_file(ctx, name);
586 
587 	return line != NULL;
588 }
589 
kmod_search_moddep(struct kmod_ctx * ctx,const char * name)590 char *kmod_search_moddep(struct kmod_ctx *ctx, const char *name)
591 {
592 	struct index_file *idx;
593 	char fn[PATH_MAX];
594 	char *line;
595 
596 	if (ctx->indexes[KMOD_INDEX_MODULES_DEP]) {
597 		DBG(ctx, "use mmaped index '%s' modname=%s\n",
598 				index_files[KMOD_INDEX_MODULES_DEP].fn, name);
599 		return index_mm_search(ctx->indexes[KMOD_INDEX_MODULES_DEP],
600 									name);
601 	}
602 
603 	snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname,
604 					index_files[KMOD_INDEX_MODULES_DEP].fn);
605 
606 	DBG(ctx, "file=%s modname=%s\n", fn, name);
607 
608 	idx = index_file_open(fn);
609 	if (idx == NULL) {
610 		DBG(ctx, "could not open moddep file '%s'\n", fn);
611 		return NULL;
612 	}
613 
614 	line = index_search(idx, name);
615 	index_file_close(idx);
616 
617 	return line;
618 }
619 
kmod_lookup_alias_from_moddep_file(struct kmod_ctx * ctx,const char * name,struct kmod_list ** list)620 int kmod_lookup_alias_from_moddep_file(struct kmod_ctx *ctx, const char *name,
621 						struct kmod_list **list)
622 {
623 	char *line;
624 	int n = 0;
625 
626 	/*
627 	 * Module names do not contain ':'. Return early if we know it will
628 	 * not be found.
629 	 */
630 	if (strchr(name, ':'))
631 		return 0;
632 
633 	line = kmod_search_moddep(ctx, name);
634 	if (line != NULL) {
635 		struct kmod_module *mod;
636 
637 		n = kmod_module_new_from_name(ctx, name, &mod);
638 		if (n < 0) {
639 			ERR(ctx, "Could not create module from name %s: %s\n",
640 			    name, strerror(-n));
641 			goto finish;
642 		}
643 
644 		*list = kmod_list_append(*list, mod);
645 		kmod_module_parse_depline(mod, line);
646 	}
647 
648 finish:
649 	free(line);
650 
651 	return n;
652 }
653 
kmod_lookup_alias_from_config(struct kmod_ctx * ctx,const char * name,struct kmod_list ** list)654 int kmod_lookup_alias_from_config(struct kmod_ctx *ctx, const char *name,
655 						struct kmod_list **list)
656 {
657 	struct kmod_config *config = ctx->config;
658 	struct kmod_list *l;
659 	int err, nmatch = 0;
660 
661 	kmod_list_foreach(l, config->aliases) {
662 		const char *aliasname = kmod_alias_get_name(l);
663 		const char *modname = kmod_alias_get_modname(l);
664 
665 		if (fnmatch(aliasname, name, 0) == 0) {
666 			struct kmod_module *mod;
667 
668 			err = kmod_module_new_from_alias(ctx, aliasname,
669 								modname, &mod);
670 			if (err < 0) {
671 				ERR(ctx, "Could not create module for alias=%s modname=%s: %s\n",
672 				    name, modname, strerror(-err));
673 				goto fail;
674 			}
675 
676 			*list = kmod_list_append(*list, mod);
677 			nmatch++;
678 		}
679 	}
680 
681 	return nmatch;
682 
683 fail:
684 	*list = kmod_list_remove_n_latest(*list, nmatch);
685 	return err;
686 }
687 
kmod_lookup_alias_from_commands(struct kmod_ctx * ctx,const char * name,struct kmod_list ** list)688 int kmod_lookup_alias_from_commands(struct kmod_ctx *ctx, const char *name,
689 						struct kmod_list **list)
690 {
691 	struct kmod_config *config = ctx->config;
692 	struct kmod_list *l, *node;
693 	int err, nmatch = 0;
694 
695 	kmod_list_foreach(l, config->install_commands) {
696 		const char *modname = kmod_command_get_modname(l);
697 
698 		if (streq(modname, name)) {
699 			const char *cmd = kmod_command_get_command(l);
700 			struct kmod_module *mod;
701 
702 			err = kmod_module_new_from_name(ctx, modname, &mod);
703 			if (err < 0) {
704 				ERR(ctx, "Could not create module from name %s: %s\n",
705 				    modname, strerror(-err));
706 				return err;
707 			}
708 
709 			node = kmod_list_append(*list, mod);
710 			if (node == NULL) {
711 				ERR(ctx, "out of memory\n");
712 				return -ENOMEM;
713 			}
714 
715 			*list = node;
716 			nmatch = 1;
717 
718 			kmod_module_set_install_commands(mod, cmd);
719 
720 			/*
721 			 * match only the first one, like modprobe from
722 			 * module-init-tools does
723 			 */
724 			break;
725 		}
726 	}
727 
728 	if (nmatch)
729 		return nmatch;
730 
731 	kmod_list_foreach(l, config->remove_commands) {
732 		const char *modname = kmod_command_get_modname(l);
733 
734 		if (streq(modname, name)) {
735 			const char *cmd = kmod_command_get_command(l);
736 			struct kmod_module *mod;
737 
738 			err = kmod_module_new_from_name(ctx, modname, &mod);
739 			if (err < 0) {
740 				ERR(ctx, "Could not create module from name %s: %s\n",
741 				    modname, strerror(-err));
742 				return err;
743 			}
744 
745 			node = kmod_list_append(*list, mod);
746 			if (node == NULL) {
747 				ERR(ctx, "out of memory\n");
748 				return -ENOMEM;
749 			}
750 
751 			*list = node;
752 			nmatch = 1;
753 
754 			kmod_module_set_remove_commands(mod, cmd);
755 
756 			/*
757 			 * match only the first one, like modprobe from
758 			 * module-init-tools does
759 			 */
760 			break;
761 		}
762 	}
763 
764 	return nmatch;
765 }
766 
kmod_set_modules_visited(struct kmod_ctx * ctx,bool visited)767 void kmod_set_modules_visited(struct kmod_ctx *ctx, bool visited)
768 {
769 	struct hash_iter iter;
770 	const void *v;
771 
772 	hash_iter_init(ctx->modules_by_name, &iter);
773 	while (hash_iter_next(&iter, NULL, &v))
774 		kmod_module_set_visited((struct kmod_module *)v, visited);
775 }
776 
kmod_set_modules_required(struct kmod_ctx * ctx,bool required)777 void kmod_set_modules_required(struct kmod_ctx *ctx, bool required)
778 {
779 	struct hash_iter iter;
780 	const void *v;
781 
782 	hash_iter_init(ctx->modules_by_name, &iter);
783 	while (hash_iter_next(&iter, NULL, &v))
784 		kmod_module_set_required((struct kmod_module *)v, required);
785 }
786 
is_cache_invalid(const char * path,unsigned long long stamp)787 static bool is_cache_invalid(const char *path, unsigned long long stamp)
788 {
789 	struct stat st;
790 
791 	if (stat(path, &st) < 0)
792 		return true;
793 
794 	if (stamp != stat_mstamp(&st))
795 		return true;
796 
797 	return false;
798 }
799 
800 /**
801  * kmod_validate_resources:
802  * @ctx: kmod library context
803  *
804  * Check if indexes and configuration files changed on disk and the current
805  * context is not valid anymore.
806  *
807  * Returns: KMOD_RESOURCES_OK if resources are still valid,
808  * KMOD_RESOURCES_MUST_RELOAD if it's sufficient to call
809  * kmod_unload_resources() and kmod_load_resources() or
810  * KMOD_RESOURCES_MUST_RECREATE if @ctx must be re-created.
811  */
kmod_validate_resources(struct kmod_ctx * ctx)812 KMOD_EXPORT int kmod_validate_resources(struct kmod_ctx *ctx)
813 {
814 	struct kmod_list *l;
815 	size_t i;
816 
817 	if (ctx == NULL || ctx->config == NULL)
818 		return KMOD_RESOURCES_MUST_RECREATE;
819 
820 	kmod_list_foreach(l, ctx->config->paths) {
821 		struct kmod_config_path *cf = l->data;
822 
823 		if (is_cache_invalid(cf->path, cf->stamp))
824 			return KMOD_RESOURCES_MUST_RECREATE;
825 	}
826 
827 	for (i = 0; i < _KMOD_INDEX_MODULES_SIZE; i++) {
828 		char path[PATH_MAX];
829 
830 		if (ctx->indexes[i] == NULL)
831 			continue;
832 
833 		snprintf(path, sizeof(path), "%s/%s.bin", ctx->dirname,
834 						index_files[i].fn);
835 
836 		if (is_cache_invalid(path, ctx->indexes_stamp[i]))
837 			return KMOD_RESOURCES_MUST_RELOAD;
838 	}
839 
840 	return KMOD_RESOURCES_OK;
841 }
842 
843 /**
844  * kmod_load_resources:
845  * @ctx: kmod library context
846  *
847  * Load indexes and keep them open in @ctx. This way it's faster to lookup
848  * information within the indexes. If this function is not called before a
849  * search, the necessary index is always opened and closed.
850  *
851  * If user will do more than one or two lookups, insertions, deletions, most
852  * likely it's good to call this function first. Particularly in a daemon like
853  * udev that on bootup issues hundreds of calls to lookup the index, calling
854  * this function will speedup the searches.
855  *
856  * Returns: 0 on success or < 0 otherwise.
857  */
kmod_load_resources(struct kmod_ctx * ctx)858 KMOD_EXPORT int kmod_load_resources(struct kmod_ctx *ctx)
859 {
860 	int ret = 0;
861 	size_t i;
862 
863 	if (ctx == NULL)
864 		return -ENOENT;
865 
866 	for (i = 0; i < _KMOD_INDEX_MODULES_SIZE; i++) {
867 		char path[PATH_MAX];
868 
869 		if (ctx->indexes[i] != NULL) {
870 			INFO(ctx, "Index %s already loaded\n",
871 							index_files[i].fn);
872 			continue;
873 		}
874 
875 		snprintf(path, sizeof(path), "%s/%s.bin", ctx->dirname,
876 							index_files[i].fn);
877 		ret = index_mm_open(ctx, path, &ctx->indexes_stamp[i],
878 				    &ctx->indexes[i]);
879 
880 		/*
881 		 * modules.builtin.alias are considered optional since it's
882 		 * recently added and older installations may not have it;
883 		 * we allow failing for any reason
884 		 */
885 		if (ret) {
886 			if (i != KMOD_INDEX_MODULES_BUILTIN_ALIAS)
887 				break;
888 			ret = 0;
889 		}
890 	}
891 
892 	if (ret)
893 		kmod_unload_resources(ctx);
894 
895 	return ret;
896 }
897 
898 /**
899  * kmod_unload_resources:
900  * @ctx: kmod library context
901  *
902  * Unload all the indexes. This will free the resources to maintain the index
903  * open and all subsequent searches will need to open and close the index.
904  *
905  * User is free to call kmod_load_resources() and kmod_unload_resources() as
906  * many times as wanted during the lifecycle of @ctx. For example, if a daemon
907  * knows that when starting up it will lookup a lot of modules, it could call
908  * kmod_load_resources() and after the first burst of searches is gone, it
909  * could free the resources by calling kmod_unload_resources().
910  *
911  * Returns: 0 on success or < 0 otherwise.
912  */
kmod_unload_resources(struct kmod_ctx * ctx)913 KMOD_EXPORT void kmod_unload_resources(struct kmod_ctx *ctx)
914 {
915 	size_t i;
916 
917 	if (ctx == NULL)
918 		return;
919 
920 	for (i = 0; i < _KMOD_INDEX_MODULES_SIZE; i++) {
921 		if (ctx->indexes[i] != NULL) {
922 			index_mm_close(ctx->indexes[i]);
923 			ctx->indexes[i] = NULL;
924 			ctx->indexes_stamp[i] = 0;
925 		}
926 	}
927 }
928 
929 /**
930  * kmod_dump_index:
931  * @ctx: kmod library context
932  * @type: index to dump, valid indexes are
933  * KMOD_INDEX_MODULES_DEP: index of module dependencies;
934  * KMOD_INDEX_MODULES_ALIAS: index of module aliases;
935  * KMOD_INDEX_MODULES_SYMBOL: index of symbol aliases;
936  * KMOD_INDEX_MODULES_BUILTIN: index of builtin module.
937  * @fd: file descriptor to dump index to
938  *
939  * Dump index to file descriptor. Note that this function doesn't use stdio.h
940  * so call fflush() before calling this function to be sure data is written in
941  * order.
942  *
943  * Returns: 0 on success or < 0 otherwise.
944  */
kmod_dump_index(struct kmod_ctx * ctx,enum kmod_index type,int fd)945 KMOD_EXPORT int kmod_dump_index(struct kmod_ctx *ctx, enum kmod_index type,
946 									int fd)
947 {
948 	if (ctx == NULL)
949 		return -ENOSYS;
950 
951 	if (type < 0 || type >= _KMOD_INDEX_MODULES_SIZE)
952 		return -ENOENT;
953 
954 	if (ctx->indexes[type] != NULL) {
955 		DBG(ctx, "use mmaped index '%s'\n", index_files[type].fn);
956 		index_mm_dump(ctx->indexes[type], fd,
957 						index_files[type].prefix);
958 	} else {
959 		char fn[PATH_MAX];
960 		struct index_file *idx;
961 
962 		snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname,
963 						index_files[type].fn);
964 
965 		DBG(ctx, "file=%s\n", fn);
966 
967 		idx = index_file_open(fn);
968 		if (idx == NULL)
969 			return -ENOSYS;
970 
971 		index_dump(idx, fd, index_files[type].prefix);
972 		index_file_close(idx);
973 	}
974 
975 	return 0;
976 }
977 
kmod_get_config(const struct kmod_ctx * ctx)978 const struct kmod_config *kmod_get_config(const struct kmod_ctx *ctx)
979 {
980 	return ctx->config;
981 }
982