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