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