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