]> git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod-config.c
python: module: fix versions -> info typo in Module._info_get() error message.
[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 for (i = 0; config_paths[i] != NULL; i++) {
852 const char *path = config_paths[i];
853 unsigned long long path_stamp = 0;
854 size_t pathlen;
855 struct kmod_list *tmp;
856 struct kmod_config_path *cf;
857
858 if (conf_files_list(ctx, &list, path, &path_stamp) < 0)
859 continue;
860
861 pathlen = strlen(path) + 1;
862 cf = malloc(sizeof(*cf) + pathlen);
863 if (cf == NULL)
864 goto oom;
865
866 cf->stamp = path_stamp;
867 memcpy(cf->path, path, pathlen);
868
869 tmp = kmod_list_append(path_list, cf);
870 if (tmp == NULL)
871 goto oom;
872 path_list = tmp;
873 }
874
875 *p_config = config = calloc(1, sizeof(struct kmod_config));
876 if (config == NULL)
877 goto oom;
878
879 config->paths = path_list;
880 config->ctx = ctx;
881
882 for (; list != NULL; list = kmod_list_remove(list)) {
883 char fn[PATH_MAX];
884 struct conf_file *cf = list->data;
885 int fd;
886
887 if (cf->is_single)
888 strcpy(fn, cf->path);
889 else
890 snprintf(fn, sizeof(fn),"%s/%s", cf->path,
891 cf->name);
892
893 fd = open(fn, O_RDONLY|O_CLOEXEC);
894 DBG(ctx, "parsing file '%s' fd=%d\n", fn, fd);
895
896 if (fd >= 0)
897 kmod_config_parse(config, fd, fn);
898
899 free(cf);
900 }
901
902 kmod_config_parse_kcmdline(config);
903
904 return 0;
905
906 oom:
907 for (; list != NULL; list = kmod_list_remove(list))
908 free(list->data);
909
910 for (; path_list != NULL; path_list = kmod_list_remove(path_list))
911 free(path_list->data);
912
913 return -ENOMEM;
914 }
915
916 /**********************************************************************
917 * struct kmod_config_iter functions
918 **********************************************************************/
919
920 enum config_type {
921 CONFIG_TYPE_BLACKLIST = 0,
922 CONFIG_TYPE_INSTALL,
923 CONFIG_TYPE_REMOVE,
924 CONFIG_TYPE_ALIAS,
925 CONFIG_TYPE_OPTION,
926 CONFIG_TYPE_SOFTDEP,
927 };
928
929 struct kmod_config_iter {
930 enum config_type type;
931 bool intermediate;
932 const struct kmod_list *list;
933 const struct kmod_list *curr;
934 void *data;
935 const char *(*get_key)(const struct kmod_list *l);
936 const char *(*get_value)(const struct kmod_list *l);
937 };
938
939 static const char *softdep_get_plain_softdep(const struct kmod_list *l)
940 {
941 char *s = softdep_to_char(l->data);
942 return s;
943 }
944
945 static struct kmod_config_iter *kmod_config_iter_new(const struct kmod_ctx* ctx,
946 enum config_type type)
947 {
948 struct kmod_config_iter *iter = calloc(1, sizeof(*iter));
949 const struct kmod_config *config = kmod_get_config(ctx);
950
951 if (iter == NULL)
952 return NULL;
953
954 iter->type = type;
955
956 switch (type) {
957 case CONFIG_TYPE_BLACKLIST:
958 iter->list = config->blacklists;
959 iter->get_key = kmod_blacklist_get_modname;
960 break;
961 case CONFIG_TYPE_INSTALL:
962 iter->list = config->install_commands;
963 iter->get_key = kmod_command_get_modname;
964 iter->get_value = kmod_command_get_command;
965 break;
966 case CONFIG_TYPE_REMOVE:
967 iter->list = config->remove_commands;
968 iter->get_key = kmod_command_get_modname;
969 iter->get_value = kmod_command_get_command;
970 break;
971 case CONFIG_TYPE_ALIAS:
972 iter->list = config->aliases;
973 iter->get_key = kmod_alias_get_name;
974 iter->get_value = kmod_alias_get_modname;
975 break;
976 case CONFIG_TYPE_OPTION:
977 iter->list = config->options;
978 iter->get_key = kmod_option_get_modname;
979 iter->get_value = kmod_option_get_options;
980 break;
981 case CONFIG_TYPE_SOFTDEP:
982 iter->list = config->softdeps;
983 iter->get_key = kmod_softdep_get_name;
984 iter->get_value = softdep_get_plain_softdep;
985 iter->intermediate = true;
986 break;
987 }
988
989 return iter;
990 }
991
992 /**
993 * SECTION:libkmod-config
994 * @short_description: retrieve current libkmod configuration
995 */
996
997 /**
998 * kmod_config_get_blacklists:
999 * @ctx: kmod library context
1000 *
1001 * Retrieve an iterator to deal with the blacklist maintained inside the
1002 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
1003 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
1004 * be made to initialize the iterator and check if it's valid.
1005 *
1006 * Returns: a new iterator over the blacklists or NULL on failure. Free it
1007 * with kmod_config_iter_free_iter().
1008 */
1009 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_blacklists(const struct kmod_ctx *ctx)
1010 {
1011 if (ctx == NULL)
1012 return NULL;;
1013
1014 return kmod_config_iter_new(ctx, CONFIG_TYPE_BLACKLIST);
1015 }
1016
1017 /**
1018 * kmod_config_get_install_commands:
1019 * @ctx: kmod library context
1020 *
1021 * Retrieve an iterator to deal with the install commands maintained inside the
1022 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
1023 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
1024 * be made to initialize the iterator and check if it's valid.
1025 *
1026 * Returns: a new iterator over the install commands or NULL on failure. Free
1027 * it with kmod_config_iter_free_iter().
1028 */
1029 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_install_commands(const struct kmod_ctx *ctx)
1030 {
1031 if (ctx == NULL)
1032 return NULL;;
1033
1034 return kmod_config_iter_new(ctx, CONFIG_TYPE_INSTALL);
1035 }
1036
1037 /**
1038 * kmod_config_get_remove_commands:
1039 * @ctx: kmod library context
1040 *
1041 * Retrieve an iterator to deal with the remove commands maintained inside the
1042 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
1043 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
1044 * be made to initialize the iterator and check if it's valid.
1045 *
1046 * Returns: a new iterator over the remove commands or NULL on failure. Free
1047 * it with kmod_config_iter_free_iter().
1048 */
1049 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_remove_commands(const struct kmod_ctx *ctx)
1050 {
1051 if (ctx == NULL)
1052 return NULL;;
1053
1054 return kmod_config_iter_new(ctx, CONFIG_TYPE_REMOVE);
1055 }
1056
1057 /**
1058 * kmod_config_get_aliases:
1059 * @ctx: kmod library context
1060 *
1061 * Retrieve an iterator to deal with the aliases maintained inside the
1062 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
1063 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
1064 * be made to initialize the iterator and check if it's valid.
1065 *
1066 * Returns: a new iterator over the aliases or NULL on failure. Free it with
1067 * kmod_config_iter_free_iter().
1068 */
1069 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_aliases(const struct kmod_ctx *ctx)
1070 {
1071 if (ctx == NULL)
1072 return NULL;;
1073
1074 return kmod_config_iter_new(ctx, CONFIG_TYPE_ALIAS);
1075 }
1076
1077 /**
1078 * kmod_config_get_options:
1079 * @ctx: kmod library context
1080 *
1081 * Retrieve an iterator to deal with the options maintained inside the
1082 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
1083 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
1084 * be made to initialize the iterator and check if it's valid.
1085 *
1086 * Returns: a new iterator over the options or NULL on failure. Free it with
1087 * kmod_config_iter_free_iter().
1088 */
1089 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_options(const struct kmod_ctx *ctx)
1090 {
1091 if (ctx == NULL)
1092 return NULL;;
1093
1094 return kmod_config_iter_new(ctx, CONFIG_TYPE_OPTION);
1095 }
1096
1097 /**
1098 * kmod_config_get_softdeps:
1099 * @ctx: kmod library context
1100 *
1101 * Retrieve an iterator to deal with the softdeps maintained inside the
1102 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
1103 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
1104 * be made to initialize the iterator and check if it's valid.
1105 *
1106 * Returns: a new iterator over the softdeps or NULL on failure. Free it with
1107 * kmod_config_iter_free_iter().
1108 */
1109 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_softdeps(const struct kmod_ctx *ctx)
1110 {
1111 if (ctx == NULL)
1112 return NULL;;
1113
1114 return kmod_config_iter_new(ctx, CONFIG_TYPE_SOFTDEP);
1115 }
1116
1117 /**
1118 * kmod_config_iter_get_key:
1119 * @iter: iterator over a certain configuration
1120 *
1121 * When using a new allocated iterator, user must perform a call to
1122 * kmod_config_iter_next() to initialize iterator's position and check if it's
1123 * valid.
1124 *
1125 * Returns: the key of the current configuration pointed by @iter.
1126 */
1127 KMOD_EXPORT const char *kmod_config_iter_get_key(const struct kmod_config_iter *iter)
1128 {
1129 if (iter == NULL || iter->curr == NULL)
1130 return NULL;
1131
1132 return iter->get_key(iter->curr);
1133 }
1134
1135 /**
1136 * kmod_config_iter_get_value:
1137 * @iter: iterator over a certain configuration
1138 *
1139 * When using a new allocated iterator, user must perform a call to
1140 * kmod_config_iter_next() to initialize iterator's position and check if it's
1141 * valid.
1142 *
1143 * Returns: the value of the current configuration pointed by @iter.
1144 */
1145 KMOD_EXPORT const char *kmod_config_iter_get_value(const struct kmod_config_iter *iter)
1146 {
1147 const char *s;
1148
1149 if (iter == NULL || iter->curr == NULL)
1150 return NULL;
1151
1152 if (iter->get_value == NULL)
1153 return NULL;
1154
1155 if (iter->intermediate) {
1156 struct kmod_config_iter *i = (struct kmod_config_iter *)iter;
1157
1158 free(i->data);
1159 s = i->data = (void *) iter->get_value(iter->curr);
1160 } else
1161 s = iter->get_value(iter->curr);
1162
1163 return s;
1164 }
1165
1166 /**
1167 * kmod_config_iter_next:
1168 * @iter: iterator over a certain configuration
1169 *
1170 * Make @iter point to the next item of a certain configuration. It's an
1171 * automatically recycling iterator. When it reaches the end, false is
1172 * returned; then if user wants to iterate again, it's sufficient to call this
1173 * function once more.
1174 *
1175 * Returns: true if next position of @iter is valid or false if its end is
1176 * reached.
1177 */
1178 KMOD_EXPORT bool kmod_config_iter_next(struct kmod_config_iter *iter)
1179 {
1180 if (iter == NULL)
1181 return false;
1182
1183 if (iter->curr == NULL) {
1184 iter->curr = iter->list;
1185 return iter->curr != NULL;
1186 }
1187
1188 iter->curr = kmod_list_next(iter->list, iter->curr);
1189
1190 return iter->curr != NULL;
1191 }
1192
1193 /**
1194 * kmod_config_iter_free_iter:
1195 * @iter: iterator over a certain configuration
1196 *
1197 * Free resources used by the iterator.
1198 */
1199 KMOD_EXPORT void kmod_config_iter_free_iter(struct kmod_config_iter *iter)
1200 {
1201 free(iter->data);
1202 free(iter);
1203 }