Home | History | Annotate | Download | only in libkmod
      1 /*
      2  * libkmod - interface to kernel module operations
      3  *
      4  * Copyright (C) 2011-2013  ProFUSION embedded systems
      5  * Copyright (C) 2013  Intel Corporation. All rights reserved.
      6  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Lesser General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2.1 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Lesser General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Lesser General Public
     18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     19  */
     20 
     21 #include <ctype.h>
     22 #include <dirent.h>
     23 #include <errno.h>
     24 #include <stdarg.h>
     25 #include <stddef.h>
     26 #include <stdio.h>
     27 #include <stdlib.h>
     28 #include <string.h>
     29 #include <unistd.h>
     30 #include <sys/stat.h>
     31 #include <sys/types.h>
     32 
     33 #include <shared/util.h>
     34 
     35 #include "libkmod.h"
     36 #include "libkmod-internal.h"
     37 
     38 struct kmod_alias {
     39 	char *name;
     40 	char modname[];
     41 };
     42 
     43 struct kmod_options {
     44 	char *options;
     45 	char modname[];
     46 };
     47 
     48 struct kmod_command {
     49 	char *command;
     50 	char modname[];
     51 };
     52 
     53 struct kmod_softdep {
     54 	char *name;
     55 	const char **pre;
     56 	const char **post;
     57 	unsigned int n_pre;
     58 	unsigned int n_post;
     59 };
     60 
     61 const char *kmod_blacklist_get_modname(const struct kmod_list *l)
     62 {
     63 	return l->data;
     64 }
     65 
     66 const char *kmod_alias_get_name(const struct kmod_list *l) {
     67 	const struct kmod_alias *alias = l->data;
     68 	return alias->name;
     69 }
     70 
     71 const char *kmod_alias_get_modname(const struct kmod_list *l) {
     72 	const struct kmod_alias *alias = l->data;
     73 	return alias->modname;
     74 }
     75 
     76 const char *kmod_option_get_options(const struct kmod_list *l) {
     77 	const struct kmod_options *alias = l->data;
     78 	return alias->options;
     79 }
     80 
     81 const char *kmod_option_get_modname(const struct kmod_list *l) {
     82 	const struct kmod_options *alias = l->data;
     83 	return alias->modname;
     84 }
     85 
     86 const char *kmod_command_get_command(const struct kmod_list *l) {
     87 	const struct kmod_command *alias = l->data;
     88 	return alias->command;
     89 }
     90 
     91 const char *kmod_command_get_modname(const struct kmod_list *l) {
     92 	const struct kmod_command *alias = l->data;
     93 	return alias->modname;
     94 }
     95 
     96 const char *kmod_softdep_get_name(const struct kmod_list *l) {
     97 	const struct kmod_softdep *dep = l->data;
     98 	return dep->name;
     99 }
    100 
    101 const char * const *kmod_softdep_get_pre(const struct kmod_list *l, unsigned int *count) {
    102 	const struct kmod_softdep *dep = l->data;
    103 	*count = dep->n_pre;
    104 	return dep->pre;
    105 }
    106 
    107 const char * const *kmod_softdep_get_post(const struct kmod_list *l, unsigned int *count) {
    108 	const struct kmod_softdep *dep = l->data;
    109 	*count = dep->n_post;
    110 	return dep->post;
    111 }
    112 
    113 static int kmod_config_add_command(struct kmod_config *config,
    114 						const char *modname,
    115 						const char *command,
    116 						const char *command_name,
    117 						struct kmod_list **list)
    118 {
    119 	_cleanup_free_ struct kmod_command *cmd;
    120 	struct kmod_list *l;
    121 	size_t modnamelen = strlen(modname) + 1;
    122 	size_t commandlen = strlen(command) + 1;
    123 
    124 	DBG(config->ctx, "modname='%s' cmd='%s %s'\n", modname, command_name,
    125 								command);
    126 
    127 	cmd = malloc(sizeof(*cmd) + modnamelen + commandlen);
    128 	if (!cmd)
    129 		return -ENOMEM;
    130 
    131 	cmd->command = sizeof(*cmd) + modnamelen + (char *)cmd;
    132 	memcpy(cmd->modname, modname, modnamelen);
    133 	memcpy(cmd->command, command, commandlen);
    134 
    135 	l = kmod_list_append(*list, cmd);
    136 	if (!l)
    137 		return -ENOMEM;
    138 
    139 	*list = l;
    140 	cmd = NULL;
    141 	return 0;
    142 }
    143 
    144 static void kmod_config_free_command(struct kmod_config *config,
    145 					struct kmod_list *l,
    146 					struct kmod_list **list)
    147 {
    148 	struct kmod_command *cmd = l->data;
    149 
    150 	free(cmd);
    151 	*list = kmod_list_remove(l);
    152 }
    153 
    154 static int kmod_config_add_options(struct kmod_config *config,
    155 				const char *modname, const char *options)
    156 {
    157 	_cleanup_free_ struct kmod_options *opt;
    158 	struct kmod_list *list;
    159 	size_t modnamelen = strlen(modname) + 1;
    160 	size_t optionslen = strlen(options) + 1;
    161 
    162 	DBG(config->ctx, "modname='%s' options='%s'\n", modname, options);
    163 
    164 	opt = malloc(sizeof(*opt) + modnamelen + optionslen);
    165 	if (!opt)
    166 		return -ENOMEM;
    167 
    168 	opt->options = sizeof(*opt) + modnamelen + (char *)opt;
    169 
    170 	memcpy(opt->modname, modname, modnamelen);
    171 	memcpy(opt->options, options, optionslen);
    172 	strchr_replace(opt->options, '\t', ' ');
    173 
    174 	list = kmod_list_append(config->options, opt);
    175 	if (!list)
    176 		return -ENOMEM;
    177 
    178 	opt = NULL;
    179 	config->options = list;
    180 	return 0;
    181 }
    182 
    183 static void kmod_config_free_options(struct kmod_config *config,
    184 							struct kmod_list *l)
    185 {
    186 	struct kmod_options *opt = l->data;
    187 
    188 	free(opt);
    189 
    190 	config->options = kmod_list_remove(l);
    191 }
    192 
    193 static int kmod_config_add_alias(struct kmod_config *config,
    194 					const char *name, const char *modname)
    195 {
    196 	_cleanup_free_ struct kmod_alias *alias;
    197 	struct kmod_list *list;
    198 	size_t namelen = strlen(name) + 1, modnamelen = strlen(modname) + 1;
    199 
    200 	DBG(config->ctx, "name=%s modname=%s\n", name, modname);
    201 
    202 	alias = malloc(sizeof(*alias) + namelen + modnamelen);
    203 	if (!alias)
    204 		return -ENOMEM;
    205 
    206 	alias->name = sizeof(*alias) + modnamelen + (char *)alias;
    207 
    208 	memcpy(alias->modname, modname, modnamelen);
    209 	memcpy(alias->name, name, namelen);
    210 
    211 	list = kmod_list_append(config->aliases, alias);
    212 	if (!list)
    213 		return -ENOMEM;
    214 
    215 	alias = NULL;
    216 	config->aliases = list;
    217 	return 0;
    218 }
    219 
    220 static void kmod_config_free_alias(struct kmod_config *config,
    221 							struct kmod_list *l)
    222 {
    223 	struct kmod_alias *alias = l->data;
    224 
    225 	free(alias);
    226 
    227 	config->aliases = kmod_list_remove(l);
    228 }
    229 
    230 static int kmod_config_add_blacklist(struct kmod_config *config,
    231 							const char *modname)
    232 {
    233 	_cleanup_free_ char *p;
    234 	struct kmod_list *list;
    235 
    236 	DBG(config->ctx, "modname=%s\n", modname);
    237 
    238 	p = strdup(modname);
    239 	if (!p)
    240 		return -ENOMEM;
    241 
    242 	list = kmod_list_append(config->blacklists, p);
    243 	if (!list)
    244 		return -ENOMEM;
    245 
    246 	p = NULL;
    247 	config->blacklists = list;
    248 	return 0;
    249 }
    250 
    251 static void kmod_config_free_blacklist(struct kmod_config *config,
    252 							struct kmod_list *l)
    253 {
    254 	free(l->data);
    255 	config->blacklists = kmod_list_remove(l);
    256 }
    257 
    258 static int kmod_config_add_softdep(struct kmod_config *config,
    259 							const char *modname,
    260 							const char *line)
    261 {
    262 	struct kmod_list *list;
    263 	struct kmod_softdep *dep;
    264 	const char *s, *p;
    265 	char *itr;
    266 	unsigned int n_pre = 0, n_post = 0;
    267 	size_t modnamelen = strlen(modname) + 1;
    268 	size_t buflen = 0;
    269 	bool was_space = false;
    270 	enum { S_NONE, S_PRE, S_POST } mode = S_NONE;
    271 
    272 	DBG(config->ctx, "modname=%s\n", modname);
    273 
    274 	/* analyze and count */
    275 	for (p = s = line; ; s++) {
    276 		size_t plen;
    277 
    278 		if (*s != '\0') {
    279 			if (!isspace(*s)) {
    280 				was_space = false;
    281 				continue;
    282 			}
    283 
    284 			if (was_space) {
    285 				p = s + 1;
    286 				continue;
    287 			}
    288 			was_space = true;
    289 
    290 			if (p >= s)
    291 				continue;
    292 		}
    293 		plen = s - p;
    294 
    295 		if (plen == sizeof("pre:") - 1 &&
    296 				memcmp(p, "pre:", sizeof("pre:") - 1) == 0)
    297 			mode = S_PRE;
    298 		else if (plen == sizeof("post:") - 1 &&
    299 				memcmp(p, "post:", sizeof("post:") - 1) == 0)
    300 			mode = S_POST;
    301 		else if (*s != '\0' || (*s == '\0' && !was_space)) {
    302 			if (mode == S_PRE) {
    303 				buflen += plen + 1;
    304 				n_pre++;
    305 			} else if (mode == S_POST) {
    306 				buflen += plen + 1;
    307 				n_post++;
    308 			}
    309 		}
    310 		p = s + 1;
    311 		if (*s == '\0')
    312 			break;
    313 	}
    314 
    315 	DBG(config->ctx, "%u pre, %u post\n", n_pre, n_post);
    316 
    317 	dep = malloc(sizeof(struct kmod_softdep) + modnamelen +
    318 		     n_pre * sizeof(const char *) +
    319 		     n_post * sizeof(const char *) +
    320 		     buflen);
    321 	if (dep == NULL) {
    322 		ERR(config->ctx, "out-of-memory modname=%s\n", modname);
    323 		return -ENOMEM;
    324 	}
    325 	dep->n_pre = n_pre;
    326 	dep->n_post = n_post;
    327 	dep->pre = (const char **)((char *)dep + sizeof(struct kmod_softdep));
    328 	dep->post = dep->pre + n_pre;
    329 	dep->name = (char *)(dep->post + n_post);
    330 
    331 	memcpy(dep->name, modname, modnamelen);
    332 
    333 	/* copy strings */
    334 	itr = dep->name + modnamelen;
    335 	n_pre = 0;
    336 	n_post = 0;
    337 	mode = S_NONE;
    338 	for (p = s = line; ; s++) {
    339 		size_t plen;
    340 
    341 		if (*s != '\0') {
    342 			if (!isspace(*s)) {
    343 				was_space = false;
    344 				continue;
    345 			}
    346 
    347 			if (was_space) {
    348 				p = s + 1;
    349 				continue;
    350 			}
    351 			was_space = true;
    352 
    353 			if (p >= s)
    354 				continue;
    355 		}
    356 		plen = s - p;
    357 
    358 		if (plen == sizeof("pre:") - 1 &&
    359 				memcmp(p, "pre:", sizeof("pre:") - 1) == 0)
    360 			mode = S_PRE;
    361 		else if (plen == sizeof("post:") - 1 &&
    362 				memcmp(p, "post:", sizeof("post:") - 1) == 0)
    363 			mode = S_POST;
    364 		else if (*s != '\0' || (*s == '\0' && !was_space)) {
    365 			if (mode == S_PRE) {
    366 				dep->pre[n_pre] = itr;
    367 				memcpy(itr, p, plen);
    368 				itr[plen] = '\0';
    369 				itr += plen + 1;
    370 				n_pre++;
    371 			} else if (mode == S_POST) {
    372 				dep->post[n_post] = itr;
    373 				memcpy(itr, p, plen);
    374 				itr[plen] = '\0';
    375 				itr += plen + 1;
    376 				n_post++;
    377 			}
    378 		}
    379 		p = s + 1;
    380 		if (*s == '\0')
    381 			break;
    382 	}
    383 
    384 	list = kmod_list_append(config->softdeps, dep);
    385 	if (list == NULL) {
    386 		free(dep);
    387 		return -ENOMEM;
    388 	}
    389 	config->softdeps = list;
    390 
    391 	return 0;
    392 }
    393 
    394 static char *softdep_to_char(struct kmod_softdep *dep) {
    395 	const size_t sz_preprefix = sizeof("pre: ") - 1;
    396 	const size_t sz_postprefix = sizeof("post: ") - 1;
    397 	size_t sz = 1; /* at least '\0' */
    398 	size_t sz_pre, sz_post;
    399 	const char *start, *end;
    400 	char *s, *itr;
    401 
    402 	/*
    403 	 * Rely on the fact that dep->pre[] and dep->post[] are strv's that
    404 	 * point to a contiguous buffer
    405 	 */
    406 	if (dep->n_pre > 0) {
    407 		start = dep->pre[0];
    408 		end = dep->pre[dep->n_pre - 1]
    409 					+ strlen(dep->pre[dep->n_pre - 1]);
    410 		sz_pre = end - start;
    411 		sz += sz_pre + sz_preprefix;
    412 	} else
    413 		sz_pre = 0;
    414 
    415 	if (dep->n_post > 0) {
    416 		start = dep->post[0];
    417 		end = dep->post[dep->n_post - 1]
    418 					+ strlen(dep->post[dep->n_post - 1]);
    419 		sz_post = end - start;
    420 		sz += sz_post + sz_postprefix;
    421 	} else
    422 		sz_post = 0;
    423 
    424 	itr = s = malloc(sz);
    425 	if (s == NULL)
    426 		return NULL;
    427 
    428 	if (sz_pre) {
    429 		char *p;
    430 
    431 		memcpy(itr, "pre: ", sz_preprefix);
    432 		itr += sz_preprefix;
    433 
    434 		/* include last '\0' */
    435 		memcpy(itr, dep->pre[0], sz_pre + 1);
    436 		for (p = itr; p < itr + sz_pre; p++) {
    437 			if (*p == '\0')
    438 				*p = ' ';
    439 		}
    440 		itr = p;
    441 	}
    442 
    443 	if (sz_post) {
    444 		char *p;
    445 
    446 		memcpy(itr, "post: ", sz_postprefix);
    447 		itr += sz_postprefix;
    448 
    449 		/* include last '\0' */
    450 		memcpy(itr, dep->post[0], sz_post + 1);
    451 		for (p = itr; p < itr + sz_post; p++) {
    452 			if (*p == '\0')
    453 				*p = ' ';
    454 		}
    455 		itr = p;
    456 	}
    457 
    458 	*itr = '\0';
    459 
    460 	return s;
    461 }
    462 
    463 static void kmod_config_free_softdep(struct kmod_config *config,
    464 							struct kmod_list *l)
    465 {
    466 	free(l->data);
    467 	config->softdeps = kmod_list_remove(l);
    468 }
    469 
    470 static void kcmdline_parse_result(struct kmod_config *config, char *modname,
    471 						char *param, char *value)
    472 {
    473 	if (modname == NULL || param == NULL)
    474 		return;
    475 
    476 	DBG(config->ctx, "%s %s\n", modname, param);
    477 
    478 	if (streq(modname, "modprobe") && !strncmp(param, "blacklist=", 10)) {
    479 		for (;;) {
    480 			char *t = strsep(&value, ",");
    481 			if (t == NULL)
    482 				break;
    483 
    484 			kmod_config_add_blacklist(config, t);
    485 		}
    486 	} else {
    487 		if (underscores(modname) < 0) {
    488 			ERR(config->ctx, "Ignoring bad option on kernel command line while parsing module name: '%s'\n",
    489 			    modname);
    490 		}
    491 		kmod_config_add_options(config, modname, param);
    492 	}
    493 }
    494 
    495 static int kmod_config_parse_kcmdline(struct kmod_config *config)
    496 {
    497 	char buf[KCMD_LINE_SIZE];
    498 	int fd, err;
    499 	char *p, *modname,  *param = NULL, *value = NULL;
    500 	bool is_quoted = false, is_module = true;
    501 
    502 	fd = open("/proc/cmdline", O_RDONLY|O_CLOEXEC);
    503 	if (fd < 0) {
    504 		err = -errno;
    505 		DBG(config->ctx, "could not open '/proc/cmdline' for reading: %m\n");
    506 		return err;
    507 	}
    508 
    509 	err = read_str_safe(fd, buf, sizeof(buf));
    510 	close(fd);
    511 	if (err < 0) {
    512 		ERR(config->ctx, "could not read from '/proc/cmdline': %s\n",
    513 							strerror(-err));
    514 		return err;
    515 	}
    516 
    517 	for (p = buf, modname = buf; *p != '\0' && *p != '\n'; p++) {
    518 		if (*p == '"') {
    519 			is_quoted = !is_quoted;
    520 
    521 			if (is_quoted) {
    522 				/* don't consider a module until closing quotes */
    523 				is_module = false;
    524 			} else if (param != NULL && value != NULL) {
    525 				/*
    526 				 * If we are indeed expecting a value and
    527 				 * closing quotes, then this can be considered
    528 				 * a valid option for a module
    529 				 */
    530 				is_module = true;
    531 			}
    532 
    533 			continue;
    534 		}
    535 		if (is_quoted)
    536 			continue;
    537 
    538 		switch (*p) {
    539 		case ' ':
    540 			*p = '\0';
    541 			if (is_module)
    542 				kcmdline_parse_result(config, modname, param, value);
    543 			param = value = NULL;
    544 			modname = p + 1;
    545 			is_module = true;
    546 			break;
    547 		case '.':
    548 			if (param == NULL) {
    549 				*p = '\0';
    550 				param = p + 1;
    551 			}
    552 			break;
    553 		case '=':
    554 			if (param != NULL)
    555 				value = p + 1;
    556 			else
    557 				is_module = false;
    558 			break;
    559 		}
    560 	}
    561 
    562 	*p = '\0';
    563 	if (is_module)
    564 		kcmdline_parse_result(config, modname, param, value);
    565 
    566 	return 0;
    567 }
    568 
    569 /*
    570  * Take an fd and own it. It will be closed on return. filename is used only
    571  * for debug messages
    572  */
    573 static int kmod_config_parse(struct kmod_config *config, int fd,
    574 							const char *filename)
    575 {
    576 	struct kmod_ctx *ctx = config->ctx;
    577 	char *line;
    578 	FILE *fp;
    579 	unsigned int linenum = 0;
    580 	int err;
    581 
    582 	fp = fdopen(fd, "r");
    583 	if (fp == NULL) {
    584 		err = -errno;
    585 		ERR(config->ctx, "fd %d: %m\n", fd);
    586 		close(fd);
    587 		return err;
    588 	}
    589 
    590 	while ((line = freadline_wrapped(fp, &linenum)) != NULL) {
    591 		char *cmd, *saveptr;
    592 
    593 		if (line[0] == '\0' || line[0] == '#')
    594 			goto done_next;
    595 
    596 		cmd = strtok_r(line, "\t ", &saveptr);
    597 		if (cmd == NULL)
    598 			goto done_next;
    599 
    600 		if (streq(cmd, "alias")) {
    601 			char *alias = strtok_r(NULL, "\t ", &saveptr);
    602 			char *modname = strtok_r(NULL, "\t ", &saveptr);
    603 
    604 			if (underscores(alias) < 0 || underscores(modname) < 0)
    605 				goto syntax_error;
    606 
    607 			kmod_config_add_alias(config, alias, modname);
    608 		} else if (streq(cmd, "blacklist")) {
    609 			char *modname = strtok_r(NULL, "\t ", &saveptr);
    610 
    611 			if (underscores(modname) < 0)
    612 				goto syntax_error;
    613 
    614 			kmod_config_add_blacklist(config, modname);
    615 		} else if (streq(cmd, "options")) {
    616 			char *modname = strtok_r(NULL, "\t ", &saveptr);
    617 			char *options = strtok_r(NULL, "\0", &saveptr);
    618 
    619 			if (underscores(modname) < 0 || options == NULL)
    620 				goto syntax_error;
    621 
    622 			kmod_config_add_options(config, modname, options);
    623 		} else if (streq(cmd, "install")) {
    624 			char *modname = strtok_r(NULL, "\t ", &saveptr);
    625 			char *installcmd = strtok_r(NULL, "\0", &saveptr);
    626 
    627 			if (underscores(modname) < 0 || installcmd == NULL)
    628 				goto syntax_error;
    629 
    630 			kmod_config_add_command(config, modname, installcmd,
    631 					cmd, &config->install_commands);
    632 		} else if (streq(cmd, "remove")) {
    633 			char *modname = strtok_r(NULL, "\t ", &saveptr);
    634 			char *removecmd = strtok_r(NULL, "\0", &saveptr);
    635 
    636 			if (underscores(modname) < 0 || removecmd == NULL)
    637 				goto syntax_error;
    638 
    639 			kmod_config_add_command(config, modname, removecmd,
    640 					cmd, &config->remove_commands);
    641 		} else if (streq(cmd, "softdep")) {
    642 			char *modname = strtok_r(NULL, "\t ", &saveptr);
    643 			char *softdeps = strtok_r(NULL, "\0", &saveptr);
    644 
    645 			if (underscores(modname) < 0 || softdeps == NULL)
    646 				goto syntax_error;
    647 
    648 			kmod_config_add_softdep(config, modname, softdeps);
    649 		} else if (streq(cmd, "include")
    650 				|| streq(cmd, "config")) {
    651 			ERR(ctx, "%s: command %s is deprecated and not parsed anymore\n",
    652 								filename, cmd);
    653 		} else {
    654 syntax_error:
    655 			ERR(ctx, "%s line %u: ignoring bad line starting with '%s'\n",
    656 						filename, linenum, cmd);
    657 		}
    658 
    659 done_next:
    660 		free(line);
    661 	}
    662 
    663 	fclose(fp);
    664 
    665 	return 0;
    666 }
    667 
    668 void kmod_config_free(struct kmod_config *config)
    669 {
    670 	while (config->aliases)
    671 		kmod_config_free_alias(config, config->aliases);
    672 
    673 	while (config->blacklists)
    674 		kmod_config_free_blacklist(config, config->blacklists);
    675 
    676 	while (config->options)
    677 		kmod_config_free_options(config, config->options);
    678 
    679 	while (config->install_commands) {
    680 		kmod_config_free_command(config, config->install_commands,
    681 						&config->install_commands);
    682 	}
    683 
    684 	while (config->remove_commands) {
    685 		kmod_config_free_command(config, config->remove_commands,
    686 						&config->remove_commands);
    687 	}
    688 
    689 	while (config->softdeps)
    690 		kmod_config_free_softdep(config, config->softdeps);
    691 
    692 	for (; config->paths != NULL;
    693 				config->paths = kmod_list_remove(config->paths))
    694 		free(config->paths->data);
    695 
    696 	free(config);
    697 }
    698 
    699 static bool conf_files_filter_out(struct kmod_ctx *ctx, DIR *d,
    700 					const char *path, const char *fn)
    701 {
    702 	size_t len = strlen(fn);
    703 	struct stat st;
    704 
    705 	if (fn[0] == '.')
    706 		return true;
    707 
    708 	if (len < 6 || (!streq(&fn[len - 5], ".conf")
    709 				&& !streq(&fn[len - 6], ".alias")))
    710 		return true;
    711 
    712 	fstatat(dirfd(d), fn, &st, 0);
    713 
    714 	if (S_ISDIR(st.st_mode)) {
    715 		ERR(ctx, "Directories inside directories are not supported: "
    716 							"%s/%s\n", path, fn);
    717 		return true;
    718 	}
    719 
    720 	return false;
    721 }
    722 
    723 struct conf_file {
    724 	const char *path;
    725 	bool is_single;
    726 	char name[];
    727 };
    728 
    729 static int conf_files_insert_sorted(struct kmod_ctx *ctx,
    730 					struct kmod_list **list,
    731 					const char *path, const char *name)
    732 {
    733 	struct kmod_list *lpos, *tmp;
    734 	struct conf_file *cf;
    735 	size_t namelen;
    736 	int cmp = -1;
    737 	bool is_single = false;
    738 
    739 	if (name == NULL) {
    740 		name = basename(path);
    741 		is_single = true;
    742 	}
    743 
    744 	kmod_list_foreach(lpos, *list) {
    745 		cf = lpos->data;
    746 
    747 		if ((cmp = strcmp(name, cf->name)) <= 0)
    748 			break;
    749 	}
    750 
    751 	if (cmp == 0) {
    752 		DBG(ctx, "Ignoring duplicate config file: %s/%s\n", path,
    753 									name);
    754 		return -EEXIST;
    755 	}
    756 
    757 	namelen = strlen(name);
    758 	cf = malloc(sizeof(*cf) + namelen + 1);
    759 	if (cf == NULL)
    760 		return -ENOMEM;
    761 
    762 	memcpy(cf->name, name, namelen + 1);
    763 	cf->path = path;
    764 	cf->is_single = is_single;
    765 
    766 	if (lpos == NULL)
    767 		tmp = kmod_list_append(*list, cf);
    768 	else if (lpos == *list)
    769 		tmp = kmod_list_prepend(*list, cf);
    770 	else
    771 		tmp = kmod_list_insert_before(lpos, cf);
    772 
    773 	if (tmp == NULL) {
    774 		free(cf);
    775 		return -ENOMEM;
    776 	}
    777 
    778 	if (lpos == NULL || lpos == *list)
    779 		*list = tmp;
    780 
    781 	return 0;
    782 }
    783 
    784 /*
    785  * Insert configuration files in @list, ignoring duplicates
    786  */
    787 static int conf_files_list(struct kmod_ctx *ctx, struct kmod_list **list,
    788 						const char *path,
    789 						unsigned long long *path_stamp)
    790 {
    791 	DIR *d;
    792 	int err;
    793 	struct stat st;
    794 	struct dirent *dent;
    795 
    796 	if (stat(path, &st) != 0) {
    797 		err = -errno;
    798 		DBG(ctx, "could not stat '%s': %m\n", path);
    799 		return err;
    800 	}
    801 
    802 	*path_stamp = stat_mstamp(&st);
    803 
    804 	if (!S_ISDIR(st.st_mode)) {
    805 		conf_files_insert_sorted(ctx, list, path, NULL);
    806 		return 0;
    807 	}
    808 
    809 	d = opendir(path);
    810 	if (d == NULL) {
    811 		ERR(ctx, "opendir(%s): %m\n", path);
    812 		return -EINVAL;
    813 	}
    814 
    815 	for (dent = readdir(d); dent != NULL; dent = readdir(d)) {
    816 		if (conf_files_filter_out(ctx, d, path, dent->d_name))
    817 			continue;
    818 
    819 		conf_files_insert_sorted(ctx, list, path, dent->d_name);
    820 	}
    821 
    822 	closedir(d);
    823 	return 0;
    824 }
    825 
    826 int kmod_config_new(struct kmod_ctx *ctx, struct kmod_config **p_config,
    827 					const char * const *config_paths)
    828 {
    829 	struct kmod_config *config;
    830 	struct kmod_list *list = NULL;
    831 	struct kmod_list *path_list = NULL;
    832 	size_t i;
    833 
    834 	conf_files_insert_sorted(ctx, &list, kmod_get_dirname(ctx), "modules.softdep");
    835 
    836 	for (i = 0; config_paths[i] != NULL; i++) {
    837 		const char *path = config_paths[i];
    838 		unsigned long long path_stamp = 0;
    839 		size_t pathlen;
    840 		struct kmod_list *tmp;
    841 		struct kmod_config_path *cf;
    842 
    843 		if (conf_files_list(ctx, &list, path, &path_stamp) < 0)
    844 			continue;
    845 
    846 		pathlen = strlen(path) + 1;
    847 		cf = malloc(sizeof(*cf) + pathlen);
    848 		if (cf == NULL)
    849 			goto oom;
    850 
    851 		cf->stamp = path_stamp;
    852 		memcpy(cf->path, path, pathlen);
    853 
    854 		tmp = kmod_list_append(path_list, cf);
    855 		if (tmp == NULL)
    856 			goto oom;
    857 		path_list = tmp;
    858 	}
    859 
    860 	*p_config = config = calloc(1, sizeof(struct kmod_config));
    861 	if (config == NULL)
    862 		goto oom;
    863 
    864 	config->paths = path_list;
    865 	config->ctx = ctx;
    866 
    867 	for (; list != NULL; list = kmod_list_remove(list)) {
    868 		char buf[PATH_MAX];
    869 		const char *fn = buf;
    870 		struct conf_file *cf = list->data;
    871 		int fd;
    872 
    873 		if (cf->is_single) {
    874 			fn = cf->path;
    875 		} else if (snprintf(buf, sizeof(buf), "%s/%s",
    876 				    cf->path, cf->name) >= (int)sizeof(buf)) {
    877 			ERR(ctx, "Error parsing %s/%s: path too long\n",
    878 			    cf->path, cf->name);
    879 			free(cf);
    880 			continue;
    881 		}
    882 
    883 		fd = open(fn, O_RDONLY|O_CLOEXEC);
    884 		DBG(ctx, "parsing file '%s' fd=%d\n", fn, fd);
    885 
    886 		if (fd >= 0)
    887 			kmod_config_parse(config, fd, fn);
    888 
    889 		free(cf);
    890 	}
    891 
    892 	kmod_config_parse_kcmdline(config);
    893 
    894 	return 0;
    895 
    896 oom:
    897 	for (; list != NULL; list = kmod_list_remove(list))
    898 		free(list->data);
    899 
    900 	for (; path_list != NULL; path_list = kmod_list_remove(path_list))
    901 		free(path_list->data);
    902 
    903 	return -ENOMEM;
    904 }
    905 
    906 /**********************************************************************
    907  * struct kmod_config_iter functions
    908  **********************************************************************/
    909 
    910 enum config_type {
    911 	CONFIG_TYPE_BLACKLIST = 0,
    912 	CONFIG_TYPE_INSTALL,
    913 	CONFIG_TYPE_REMOVE,
    914 	CONFIG_TYPE_ALIAS,
    915 	CONFIG_TYPE_OPTION,
    916 	CONFIG_TYPE_SOFTDEP,
    917 };
    918 
    919 struct kmod_config_iter {
    920 	enum config_type type;
    921 	bool intermediate;
    922 	const struct kmod_list *list;
    923 	const struct kmod_list *curr;
    924 	void *data;
    925 	const char *(*get_key)(const struct kmod_list *l);
    926 	const char *(*get_value)(const struct kmod_list *l);
    927 };
    928 
    929 static const char *softdep_get_plain_softdep(const struct kmod_list *l)
    930 {
    931 	char *s = softdep_to_char(l->data);
    932 	return s;
    933 }
    934 
    935 static struct kmod_config_iter *kmod_config_iter_new(const struct kmod_ctx* ctx,
    936 							enum config_type type)
    937 {
    938 	struct kmod_config_iter *iter = calloc(1, sizeof(*iter));
    939 	const struct kmod_config *config = kmod_get_config(ctx);
    940 
    941 	if (iter == NULL)
    942 		return NULL;
    943 
    944 	iter->type = type;
    945 
    946 	switch (type) {
    947 	case CONFIG_TYPE_BLACKLIST:
    948 		iter->list = config->blacklists;
    949 		iter->get_key = kmod_blacklist_get_modname;
    950 		break;
    951 	case CONFIG_TYPE_INSTALL:
    952 		iter->list = config->install_commands;
    953 		iter->get_key = kmod_command_get_modname;
    954 		iter->get_value = kmod_command_get_command;
    955 		break;
    956 	case CONFIG_TYPE_REMOVE:
    957 		iter->list = config->remove_commands;
    958 		iter->get_key = kmod_command_get_modname;
    959 		iter->get_value = kmod_command_get_command;
    960 		break;
    961 	case CONFIG_TYPE_ALIAS:
    962 		iter->list = config->aliases;
    963 		iter->get_key = kmod_alias_get_name;
    964 		iter->get_value = kmod_alias_get_modname;
    965 		break;
    966 	case CONFIG_TYPE_OPTION:
    967 		iter->list = config->options;
    968 		iter->get_key = kmod_option_get_modname;
    969 		iter->get_value = kmod_option_get_options;
    970 		break;
    971 	case CONFIG_TYPE_SOFTDEP:
    972 		iter->list = config->softdeps;
    973 		iter->get_key = kmod_softdep_get_name;
    974 		iter->get_value = softdep_get_plain_softdep;
    975 		iter->intermediate = true;
    976 		break;
    977 	}
    978 
    979 	return iter;
    980 }
    981 
    982 /**
    983  * SECTION:libkmod-config
    984  * @short_description: retrieve current libkmod configuration
    985  */
    986 
    987 /**
    988  * kmod_config_get_blacklists:
    989  * @ctx: kmod library context
    990  *
    991  * Retrieve an iterator to deal with the blacklist maintained inside the
    992  * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
    993  * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
    994  * be made to initialize the iterator and check if it's valid.
    995  *
    996  * Returns: a new iterator over the blacklists or NULL on failure. Free it
    997  * with kmod_config_iter_free_iter().
    998  */
    999 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_blacklists(const struct kmod_ctx *ctx)
   1000 {
   1001 	if (ctx == NULL)
   1002 		return NULL;;
   1003 
   1004 	return kmod_config_iter_new(ctx, CONFIG_TYPE_BLACKLIST);
   1005 }
   1006 
   1007 /**
   1008  * kmod_config_get_install_commands:
   1009  * @ctx: kmod library context
   1010  *
   1011  * Retrieve an iterator to deal with the install commands maintained inside the
   1012  * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
   1013  * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
   1014  * be made to initialize the iterator and check if it's valid.
   1015  *
   1016  * Returns: a new iterator over the install commands or NULL on failure. Free
   1017  * it with kmod_config_iter_free_iter().
   1018  */
   1019 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_install_commands(const struct kmod_ctx *ctx)
   1020 {
   1021 	if (ctx == NULL)
   1022 		return NULL;;
   1023 
   1024 	return kmod_config_iter_new(ctx, CONFIG_TYPE_INSTALL);
   1025 }
   1026 
   1027 /**
   1028  * kmod_config_get_remove_commands:
   1029  * @ctx: kmod library context
   1030  *
   1031  * Retrieve an iterator to deal with the remove commands maintained inside the
   1032  * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
   1033  * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
   1034  * be made to initialize the iterator and check if it's valid.
   1035  *
   1036  * Returns: a new iterator over the remove commands or NULL on failure. Free
   1037  * it with kmod_config_iter_free_iter().
   1038  */
   1039 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_remove_commands(const struct kmod_ctx *ctx)
   1040 {
   1041 	if (ctx == NULL)
   1042 		return NULL;;
   1043 
   1044 	return kmod_config_iter_new(ctx, CONFIG_TYPE_REMOVE);
   1045 }
   1046 
   1047 /**
   1048  * kmod_config_get_aliases:
   1049  * @ctx: kmod library context
   1050  *
   1051  * Retrieve an iterator to deal with the aliases maintained inside the
   1052  * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
   1053  * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
   1054  * be made to initialize the iterator and check if it's valid.
   1055  *
   1056  * Returns: a new iterator over the aliases or NULL on failure. Free it with
   1057  * kmod_config_iter_free_iter().
   1058  */
   1059 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_aliases(const struct kmod_ctx *ctx)
   1060 {
   1061 	if (ctx == NULL)
   1062 		return NULL;;
   1063 
   1064 	return kmod_config_iter_new(ctx, CONFIG_TYPE_ALIAS);
   1065 }
   1066 
   1067 /**
   1068  * kmod_config_get_options:
   1069  * @ctx: kmod library context
   1070  *
   1071  * Retrieve an iterator to deal with the options maintained inside the
   1072  * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
   1073  * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
   1074  * be made to initialize the iterator and check if it's valid.
   1075  *
   1076  * Returns: a new iterator over the options or NULL on failure. Free it with
   1077  * kmod_config_iter_free_iter().
   1078  */
   1079 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_options(const struct kmod_ctx *ctx)
   1080 {
   1081 	if (ctx == NULL)
   1082 		return NULL;;
   1083 
   1084 	return kmod_config_iter_new(ctx, CONFIG_TYPE_OPTION);
   1085 }
   1086 
   1087 /**
   1088  * kmod_config_get_softdeps:
   1089  * @ctx: kmod library context
   1090  *
   1091  * Retrieve an iterator to deal with the softdeps maintained inside the
   1092  * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
   1093  * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
   1094  * be made to initialize the iterator and check if it's valid.
   1095  *
   1096  * Returns: a new iterator over the softdeps or NULL on failure. Free it with
   1097  * kmod_config_iter_free_iter().
   1098  */
   1099 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_softdeps(const struct kmod_ctx *ctx)
   1100 {
   1101 	if (ctx == NULL)
   1102 		return NULL;;
   1103 
   1104 	return kmod_config_iter_new(ctx, CONFIG_TYPE_SOFTDEP);
   1105 }
   1106 
   1107 /**
   1108  * kmod_config_iter_get_key:
   1109  * @iter: iterator over a certain configuration
   1110  *
   1111  * When using a new allocated iterator, user must perform a call to
   1112  * kmod_config_iter_next() to initialize iterator's position and check if it's
   1113  * valid.
   1114  *
   1115  * Returns: the key of the current configuration pointed by @iter.
   1116  */
   1117 KMOD_EXPORT const char *kmod_config_iter_get_key(const struct kmod_config_iter *iter)
   1118 {
   1119 	if (iter == NULL || iter->curr == NULL)
   1120 		return NULL;
   1121 
   1122 	return iter->get_key(iter->curr);
   1123 }
   1124 
   1125 /**
   1126  * kmod_config_iter_get_value:
   1127  * @iter: iterator over a certain configuration
   1128  *
   1129  * When using a new allocated iterator, user must perform a call to
   1130  * kmod_config_iter_next() to initialize iterator's position and check if it's
   1131  * valid.
   1132  *
   1133  * Returns: the value of the current configuration pointed by @iter.
   1134  */
   1135 KMOD_EXPORT const char *kmod_config_iter_get_value(const struct kmod_config_iter *iter)
   1136 {
   1137 	const char *s;
   1138 
   1139 	if (iter == NULL || iter->curr == NULL)
   1140 		return NULL;
   1141 
   1142 	if (iter->get_value == NULL)
   1143 		return NULL;
   1144 
   1145 	if (iter->intermediate) {
   1146 		struct kmod_config_iter *i = (struct kmod_config_iter *)iter;
   1147 
   1148 		free(i->data);
   1149 		s = i->data = (void *) iter->get_value(iter->curr);
   1150 	} else
   1151 		s = iter->get_value(iter->curr);
   1152 
   1153 	return s;
   1154 }
   1155 
   1156 /**
   1157  * kmod_config_iter_next:
   1158  * @iter: iterator over a certain configuration
   1159  *
   1160  * Make @iter point to the next item of a certain configuration. It's an
   1161  * automatically recycling iterator. When it reaches the end, false is
   1162  * returned; then if user wants to iterate again, it's sufficient to call this
   1163  * function once more.
   1164  *
   1165  * Returns: true if next position of @iter is valid or false if its end is
   1166  * reached.
   1167  */
   1168 KMOD_EXPORT bool kmod_config_iter_next(struct kmod_config_iter *iter)
   1169 {
   1170 	if (iter == NULL)
   1171 		return false;
   1172 
   1173 	if (iter->curr == NULL) {
   1174 		iter->curr = iter->list;
   1175 		return iter->curr != NULL;
   1176 	}
   1177 
   1178 	iter->curr = kmod_list_next(iter->list, iter->curr);
   1179 
   1180 	return iter->curr != NULL;
   1181 }
   1182 
   1183 /**
   1184  * kmod_config_iter_free_iter:
   1185  * @iter: iterator over a certain configuration
   1186  *
   1187  * Free resources used by the iterator.
   1188  */
   1189 KMOD_EXPORT void kmod_config_iter_free_iter(struct kmod_config_iter *iter)
   1190 {
   1191 	free(iter->data);
   1192 	free(iter);
   1193 }
   1194