]> git.ipfire.org Git - thirdparty/kmod.git/blame - libkmod/libkmod-config.c
Move missing.h to shared directory
[thirdparty/kmod.git] / libkmod / libkmod-config.c
CommitLineData
7c2ab358
LDM
1/*
2 * libkmod - interface to kernel module operations
3 *
e6b0e49b 4 * Copyright (C) 2011-2013 ProFUSION embedded systems
342e9cea 5 * Copyright (C) 2013 Intel Corporation. All rights reserved.
7c2ab358
LDM
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
cb451f35
LDM
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
7c2ab358
LDM
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"
83b855a6 35#include "libkmod-internal.h"
7c2ab358 36
7c2ab358
LDM
37struct kmod_alias {
38 char *name;
43c29d10 39 char modname[];
7c2ab358
LDM
40};
41
615c42be
LDM
42struct kmod_options {
43 char *options;
44 char modname[];
45};
46
a5cce6d6
LDM
47struct kmod_command {
48 char *command;
49 char modname[];
50};
51
1c522600
GSB
52struct 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
c1c9c446
LDM
60const char *kmod_blacklist_get_modname(const struct kmod_list *l)
61{
62 return l->data;
63}
64
b0ef19f7 65const char *kmod_alias_get_name(const struct kmod_list *l) {
1ce08a56 66 const struct kmod_alias *alias = l->data;
b0ef19f7
LDM
67 return alias->name;
68}
69
70const char *kmod_alias_get_modname(const struct kmod_list *l) {
1ce08a56 71 const struct kmod_alias *alias = l->data;
b0ef19f7
LDM
72 return alias->modname;
73}
74
bd3f5535
GSB
75const char *kmod_option_get_options(const struct kmod_list *l) {
76 const struct kmod_options *alias = l->data;
77 return alias->options;
78}
79
80const char *kmod_option_get_modname(const struct kmod_list *l) {
81 const struct kmod_options *alias = l->data;
82 return alias->modname;
83}
84
85const char *kmod_command_get_command(const struct kmod_list *l) {
86 const struct kmod_command *alias = l->data;
87 return alias->command;
88}
89
90const char *kmod_command_get_modname(const struct kmod_list *l) {
91 const struct kmod_command *alias = l->data;
92 return alias->modname;
93}
94
1c522600
GSB
95const char *kmod_softdep_get_name(const struct kmod_list *l) {
96 const struct kmod_softdep *dep = l->data;
97 return dep->name;
98}
99
100const 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
106const 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
d30319e4
MF
112/*
113 * Replace dashes with underscores.
114 * Dashes inside character range patterns (e.g. [0-9]) are left unchanged.
115 */
116static 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
a5cce6d6
LDM
143static 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{
342e9cea 149 _cleanup_free_ struct kmod_command *cmd;
a5cce6d6
LDM
150 struct kmod_list *l;
151 size_t modnamelen = strlen(modname) + 1;
152 size_t commandlen = strlen(command) + 1;
153
e5a7f6ac 154 DBG(config->ctx, "modname='%s' cmd='%s %s'\n", modname, command_name,
a5cce6d6
LDM
155 command);
156
157 cmd = malloc(sizeof(*cmd) + modnamelen + commandlen);
342e9cea
LDM
158 if (!cmd)
159 return -ENOMEM;
a5cce6d6
LDM
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);
342e9cea
LDM
166 if (!l)
167 return -ENOMEM;
a5cce6d6
LDM
168
169 *list = l;
342e9cea 170 cmd = NULL;
a5cce6d6 171 return 0;
a5cce6d6
LDM
172}
173
174static 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
615c42be
LDM
184static int kmod_config_add_options(struct kmod_config *config,
185 const char *modname, const char *options)
186{
342e9cea 187 _cleanup_free_ struct kmod_options *opt;
615c42be
LDM
188 struct kmod_list *list;
189 size_t modnamelen = strlen(modname) + 1;
190 size_t optionslen = strlen(options) + 1;
191
23c0d012 192 DBG(config->ctx, "modname='%s' options='%s'\n", modname, options);
615c42be
LDM
193
194 opt = malloc(sizeof(*opt) + modnamelen + optionslen);
342e9cea
LDM
195 if (!opt)
196 return -ENOMEM;
615c42be
LDM
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);
342e9cea
LDM
205 if (!list)
206 return -ENOMEM;
615c42be 207
342e9cea 208 opt = NULL;
615c42be
LDM
209 config->options = list;
210 return 0;
615c42be
LDM
211}
212
c35347f1
LDM
213static void kmod_config_free_options(struct kmod_config *config,
214 struct kmod_list *l)
615c42be
LDM
215{
216 struct kmod_options *opt = l->data;
217
218 free(opt);
219
220 config->options = kmod_list_remove(l);
221}
222
d13e606f 223static int kmod_config_add_alias(struct kmod_config *config,
c35347f1 224 const char *name, const char *modname)
7c2ab358 225{
342e9cea 226 _cleanup_free_ struct kmod_alias *alias;
d13e606f 227 struct kmod_list *list;
43c29d10 228 size_t namelen = strlen(name) + 1, modnamelen = strlen(modname) + 1;
7c2ab358 229
d13e606f 230 DBG(config->ctx, "name=%s modname=%s\n", name, modname);
7c2ab358 231
43c29d10 232 alias = malloc(sizeof(*alias) + namelen + modnamelen);
d13e606f 233 if (!alias)
342e9cea 234 return -ENOMEM;
28c175ed 235
43c29d10
GSB
236 alias->name = sizeof(*alias) + modnamelen + (char *)alias;
237
238 memcpy(alias->modname, modname, modnamelen);
239 memcpy(alias->name, name, namelen);
7c2ab358 240
d13e606f
GSB
241 list = kmod_list_append(config->aliases, alias);
242 if (!list)
342e9cea 243 return -ENOMEM;
28c175ed 244
342e9cea 245 alias = NULL;
d13e606f
GSB
246 config->aliases = list;
247 return 0;
7c2ab358
LDM
248}
249
c35347f1
LDM
250static void kmod_config_free_alias(struct kmod_config *config,
251 struct kmod_list *l)
7c2ab358
LDM
252{
253 struct kmod_alias *alias = l->data;
254
7c2ab358
LDM
255 free(alias);
256
d13e606f 257 config->aliases = kmod_list_remove(l);
7c2ab358
LDM
258}
259
d13e606f 260static int kmod_config_add_blacklist(struct kmod_config *config,
c35347f1 261 const char *modname)
81cf2060 262{
342e9cea 263 _cleanup_free_ char *p;
d13e606f 264 struct kmod_list *list;
81cf2060 265
d13e606f 266 DBG(config->ctx, "modname=%s\n", modname);
81cf2060
LDM
267
268 p = strdup(modname);
d13e606f 269 if (!p)
342e9cea 270 return -ENOMEM;
d13e606f
GSB
271
272 list = kmod_list_append(config->blacklists, p);
273 if (!list)
342e9cea
LDM
274 return -ENOMEM;
275
276 p = NULL;
d13e606f
GSB
277 config->blacklists = list;
278 return 0;
81cf2060
LDM
279}
280
d13e606f 281static void kmod_config_free_blacklist(struct kmod_config *config,
81cf2060
LDM
282 struct kmod_list *l)
283{
284 free(l->data);
d13e606f 285 config->blacklists = kmod_list_remove(l);
81cf2060
LDM
286}
287
1c522600
GSB
288static 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
6b04ef32
LDM
424static 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
1c522600
GSB
493static 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
1684e440
LDM
500static void kcmdline_parse_result(struct kmod_config *config, char *modname,
501 char *param, char *value)
502{
493dc650 503 if (modname == NULL || param == NULL)
1684e440
LDM
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
522static int kmod_config_parse_kcmdline(struct kmod_config *config)
523{
524 char buf[KCMD_LINE_SIZE];
525 int fd, err;
aa878540 526 char *p, *modname, *param = NULL, *value = NULL, is_module = 1;
1684e440 527
79e5ea91 528 fd = open("/proc/cmdline", O_RDONLY|O_CLOEXEC);
dd1cf10f
LDM
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
1684e440
LDM
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';
aa878540
MM
547 if (is_module)
548 kcmdline_parse_result(config, modname, param, value);
1684e440
LDM
549 param = value = NULL;
550 modname = p + 1;
aa878540 551 is_module = 1;
1684e440
LDM
552 break;
553 case '.':
66f3228d
LDM
554 if (param == NULL) {
555 *p = '\0';
556 param = p + 1;
557 }
1684e440
LDM
558 break;
559 case '=':
135bffd6
LDM
560 if (param != NULL)
561 value = p + 1;
aa878540
MM
562 else
563 is_module = 0;
1684e440
LDM
564 break;
565 }
566 }
567
568 *p = '\0';
aa878540
MM
569 if (is_module)
570 kcmdline_parse_result(config, modname, param, value);
1684e440
LDM
571
572 return 0;
573}
574
b7b7ac29
LDM
575/*
576 * Take an fd and own it. It will be closed on return. filename is used only
577 * for debug messages
578 */
579static int kmod_config_parse(struct kmod_config *config, int fd,
580 const char *filename)
7c2ab358 581{
d13e606f 582 struct kmod_ctx *ctx = config->ctx;
7c2ab358
LDM
583 char *line;
584 FILE *fp;
759214fa 585 unsigned int linenum = 0;
b7b7ac29 586 int err;
7c2ab358 587
b7b7ac29
LDM
588 fp = fdopen(fd, "r");
589 if (fp == NULL) {
590 err = -errno;
050db08c 591 ERR(config->ctx, "fd %d: %m\n", fd);
b7b7ac29
LDM
592 close(fd);
593 return err;
594 }
7c2ab358
LDM
595
596 while ((line = getline_wrapped(fp, &linenum)) != NULL) {
c11e62bf 597 char *cmd, *saveptr;
7c2ab358
LDM
598
599 if (line[0] == '\0' || line[0] == '#')
600 goto done_next;
601
c11e62bf 602 cmd = strtok_r(line, "\t ", &saveptr);
7c2ab358
LDM
603 if (cmd == NULL)
604 goto done_next;
605
877e80cd 606 if (streq(cmd, "alias")) {
c11e62bf
LDM
607 char *alias = strtok_r(NULL, "\t ", &saveptr);
608 char *modname = strtok_r(NULL, "\t ", &saveptr);
7c2ab358
LDM
609
610 if (alias == NULL || modname == NULL)
611 goto syntax_error;
612
d13e606f 613 kmod_config_add_alias(config,
30be7513
LDM
614 underscores(ctx, alias),
615 underscores(ctx, modname));
877e80cd 616 } else if (streq(cmd, "blacklist")) {
c11e62bf 617 char *modname = strtok_r(NULL, "\t ", &saveptr);
81cf2060
LDM
618
619 if (modname == NULL)
620 goto syntax_error;
621
d13e606f 622 kmod_config_add_blacklist(config,
2295acc5 623 underscores(ctx, modname));
615c42be
LDM
624 } else if (streq(cmd, "options")) {
625 char *modname = strtok_r(NULL, "\t ", &saveptr);
83121fde 626 char *options = strtok_r(NULL, "\0", &saveptr);
615c42be 627
83121fde 628 if (modname == NULL || options == NULL)
615c42be
LDM
629 goto syntax_error;
630
631 kmod_config_add_options(config,
632 underscores(ctx, modname),
83121fde 633 options);
40ee8dad 634 } else if (streq(cmd, "install")) {
a5cce6d6 635 char *modname = strtok_r(NULL, "\t ", &saveptr);
83121fde 636 char *installcmd = strtok_r(NULL, "\0", &saveptr);
a5cce6d6 637
83121fde 638 if (modname == NULL || installcmd == NULL)
a5cce6d6
LDM
639 goto syntax_error;
640
641 kmod_config_add_command(config,
642 underscores(ctx, modname),
83121fde 643 installcmd,
a5cce6d6 644 cmd, &config->install_commands);
40ee8dad 645 } else if (streq(cmd, "remove")) {
a5cce6d6 646 char *modname = strtok_r(NULL, "\t ", &saveptr);
83121fde 647 char *removecmd = strtok_r(NULL, "\0", &saveptr);
a5cce6d6 648
83121fde 649 if (modname == NULL || removecmd == NULL)
a5cce6d6
LDM
650 goto syntax_error;
651
652 kmod_config_add_command(config,
653 underscores(ctx, modname),
83121fde 654 removecmd,
a5cce6d6 655 cmd, &config->remove_commands);
40ee8dad 656 } else if (streq(cmd, "softdep")) {
1c522600 657 char *modname = strtok_r(NULL, "\t ", &saveptr);
83121fde 658 char *softdeps = strtok_r(NULL, "\0", &saveptr);
1c522600 659
83121fde 660 if (modname == NULL || softdeps == NULL)
1c522600
GSB
661 goto syntax_error;
662
663 kmod_config_add_softdep(config,
664 underscores(ctx, modname),
83121fde 665 softdeps);
615c42be 666 } else if (streq(cmd, "include")
877e80cd 667 || streq(cmd, "config")) {
0ad5dd08 668 ERR(ctx, "%s: command %s is deprecated and not parsed anymore\n",
81cf2060 669 filename, cmd);
7c2ab358
LDM
670 } else {
671syntax_error:
672 ERR(ctx, "%s line %u: ignoring bad line starting with '%s'\n",
673 filename, linenum, cmd);
674 }
675
676done_next:
677 free(line);
678 }
679
680 fclose(fp);
681
682 return 0;
683}
684
d13e606f 685void kmod_config_free(struct kmod_config *config)
7c2ab358
LDM
686{
687 while (config->aliases)
d13e606f 688 kmod_config_free_alias(config, config->aliases);
81cf2060
LDM
689
690 while (config->blacklists)
d13e606f
GSB
691 kmod_config_free_blacklist(config, config->blacklists);
692
615c42be
LDM
693 while (config->options)
694 kmod_config_free_options(config, config->options);
695
a5cce6d6
LDM
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
1c522600
GSB
706 while (config->softdeps)
707 kmod_config_free_softdep(config, config->softdeps);
708
b6a4dfb1
LDM
709 for (; config->paths != NULL;
710 config->paths = kmod_list_remove(config->paths))
711 free(config->paths->data);
712
d13e606f 713 free(config);
7c2ab358
LDM
714}
715
98c80f44
LDM
716static bool conf_files_filter_out(struct kmod_ctx *ctx, DIR *d,
717 const char *path, const char *fn)
7c2ab358
LDM
718{
719 size_t len = strlen(fn);
98c80f44 720 struct stat st;
7c2ab358
LDM
721
722 if (fn[0] == '.')
8f767e2d 723 return true;
7c2ab358 724
877e80cd 725 if (len < 6 || (!streq(&fn[len - 5], ".conf")
9070b117 726 && !streq(&fn[len - 6], ".alias")))
8f767e2d 727 return true;
7c2ab358 728
98c80f44
LDM
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);
8f767e2d 734 return true;
98c80f44
LDM
735 }
736
8f767e2d 737 return false;
7c2ab358
LDM
738}
739
7fe5f7ab
LDM
740struct conf_file {
741 const char *path;
742 bool is_single;
743 char name[];
744};
745
746static 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
4782396c 801/*
7fe5f7ab 802 * Insert configuration files in @list, ignoring duplicates
4782396c 803 */
7fe5f7ab 804static int conf_files_list(struct kmod_ctx *ctx, struct kmod_list **list,
b6a4dfb1
LDM
805 const char *path,
806 unsigned long long *path_stamp)
7c2ab358 807{
7c2ab358
LDM
808 DIR *d;
809 int err;
7fe5f7ab 810 struct stat st;
7e0385c4 811 struct dirent *dent;
7c2ab358 812
7fe5f7ab
LDM
813 if (stat(path, &st) != 0) {
814 err = -errno;
815 DBG(ctx, "could not stat '%s': %m\n", path);
816 return err;
817 }
818
6068aaae 819 *path_stamp = stat_mstamp(&st);
b6a4dfb1 820
519d27de 821 if (!S_ISDIR(st.st_mode)) {
7fe5f7ab
LDM
822 conf_files_insert_sorted(ctx, list, path, NULL);
823 return 0;
7fe5f7ab 824 }
1c250ec1 825
7c2ab358
LDM
826 d = opendir(path);
827 if (d == NULL) {
dfa96f15 828 ERR(ctx, "opendir(%s): %m\n", path);
7fe5f7ab 829 return -EINVAL;
7c2ab358
LDM
830 }
831
7e0385c4
LDM
832 for (dent = readdir(d); dent != NULL; dent = readdir(d)) {
833 if (conf_files_filter_out(ctx, d, path, dent->d_name))
7c2ab358
LDM
834 continue;
835
7e0385c4 836 conf_files_insert_sorted(ctx, list, path, dent->d_name);
b7b7ac29 837 }
7c2ab358 838
7fe5f7ab
LDM
839 closedir(d);
840 return 0;
7c2ab358
LDM
841}
842
c35347f1
LDM
843int kmod_config_new(struct kmod_ctx *ctx, struct kmod_config **p_config,
844 const char * const *config_paths)
7c2ab358 845{
d13e606f 846 struct kmod_config *config;
7fe5f7ab 847 struct kmod_list *list = NULL;
b6a4dfb1 848 struct kmod_list *path_list = NULL;
b7b7ac29 849 size_t i;
7c2ab358 850
8240333b
TG
851 conf_files_insert_sorted(ctx, &list, kmod_get_dirname(ctx), "modules.softdep");
852
cb8d4d3e
GSB
853 for (i = 0; config_paths[i] != NULL; i++) {
854 const char *path = config_paths[i];
b6a4dfb1
LDM
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;
7c2ab358 867
b6a4dfb1
LDM
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;
7fe5f7ab 875 }
cb8d4d3e 876
b6a4dfb1
LDM
877 *p_config = config = calloc(1, sizeof(struct kmod_config));
878 if (config == NULL)
879 goto oom;
880
881 config->paths = path_list;
29b69c0b 882 config->ctx = ctx;
b6a4dfb1 883
7fe5f7ab
LDM
884 for (; list != NULL; list = kmod_list_remove(list)) {
885 char fn[PATH_MAX];
886 struct conf_file *cf = list->data;
887 int fd;
cb8d4d3e 888
7fe5f7ab
LDM
889 if (cf->is_single)
890 strcpy(fn, cf->path);
891 else
892 snprintf(fn, sizeof(fn),"%s/%s", cf->path,
893 cf->name);
7c2ab358 894
7fe5f7ab
LDM
895 fd = open(fn, O_RDONLY|O_CLOEXEC);
896 DBG(ctx, "parsing file '%s' fd=%d\n", fn, fd);
7c2ab358 897
7fe5f7ab
LDM
898 if (fd >= 0)
899 kmod_config_parse(config, fd, fn);
7c2ab358 900
7fe5f7ab 901 free(cf);
7c2ab358
LDM
902 }
903
1684e440
LDM
904 kmod_config_parse_kcmdline(config);
905
b7b7ac29 906 return 0;
b6a4dfb1
LDM
907
908oom:
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;
7c2ab358 916}
00178629
LDM
917
918/**********************************************************************
919 * struct kmod_config_iter functions
920 **********************************************************************/
921
922enum 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
931struct kmod_config_iter {
932 enum config_type type;
6b04ef32 933 bool intermediate;
00178629
LDM
934 const struct kmod_list *list;
935 const struct kmod_list *curr;
6b04ef32 936 void *data;
00178629
LDM
937 const char *(*get_key)(const struct kmod_list *l);
938 const char *(*get_value)(const struct kmod_list *l);
939};
940
6b04ef32
LDM
941static 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
00178629
LDM
947static 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));
e7fc2c86 951 const struct kmod_config *config = kmod_get_config(ctx);
00178629
LDM
952
953 if (iter == NULL)
954 return NULL;
955
956 iter->type = type;
957
958 switch (type) {
959 case CONFIG_TYPE_BLACKLIST:
e7fc2c86 960 iter->list = config->blacklists;
00178629
LDM
961 iter->get_key = kmod_blacklist_get_modname;
962 break;
963 case CONFIG_TYPE_INSTALL:
e7fc2c86 964 iter->list = config->install_commands;
00178629
LDM
965 iter->get_key = kmod_command_get_modname;
966 iter->get_value = kmod_command_get_command;
967 break;
968 case CONFIG_TYPE_REMOVE:
e7fc2c86 969 iter->list = config->remove_commands;
00178629
LDM
970 iter->get_key = kmod_command_get_modname;
971 iter->get_value = kmod_command_get_command;
972 break;
973 case CONFIG_TYPE_ALIAS:
e7fc2c86 974 iter->list = config->aliases;
00178629
LDM
975 iter->get_key = kmod_alias_get_name;
976 iter->get_value = kmod_alias_get_modname;
977 break;
978 case CONFIG_TYPE_OPTION:
e7fc2c86 979 iter->list = config->options;
00178629
LDM
980 iter->get_key = kmod_option_get_modname;
981 iter->get_value = kmod_option_get_options;
982 break;
983 case CONFIG_TYPE_SOFTDEP:
e7fc2c86 984 iter->list = config->softdeps;
00178629 985 iter->get_key = kmod_softdep_get_name;
6b04ef32
LDM
986 iter->get_value = softdep_get_plain_softdep;
987 iter->intermediate = true;
00178629
LDM
988 break;
989 }
990
991 return iter;
992}
993
2f47c7fa
LDM
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 *
883d8c42 1008 * Returns: a new iterator over the blacklists or NULL on failure. Free it
2f47c7fa
LDM
1009 * with kmod_config_iter_free_iter().
1010 */
00178629
LDM
1011KMOD_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
2f47c7fa
LDM
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 *
883d8c42 1028 * Returns: a new iterator over the install commands or NULL on failure. Free
2f47c7fa
LDM
1029 * it with kmod_config_iter_free_iter().
1030 */
00178629
LDM
1031KMOD_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
2f47c7fa
LDM
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 *
883d8c42 1048 * Returns: a new iterator over the remove commands or NULL on failure. Free
2f47c7fa
LDM
1049 * it with kmod_config_iter_free_iter().
1050 */
00178629
LDM
1051KMOD_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
2f47c7fa
LDM
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 *
883d8c42 1068 * Returns: a new iterator over the aliases or NULL on failure. Free it with
2f47c7fa
LDM
1069 * kmod_config_iter_free_iter().
1070 */
00178629
LDM
1071KMOD_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
2f47c7fa
LDM
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 *
883d8c42 1088 * Returns: a new iterator over the options or NULL on failure. Free it with
2f47c7fa
LDM
1089 * kmod_config_iter_free_iter().
1090 */
00178629
LDM
1091KMOD_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
2f47c7fa
LDM
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 *
883d8c42 1108 * Returns: a new iterator over the softdeps or NULL on failure. Free it with
2f47c7fa
LDM
1109 * kmod_config_iter_free_iter().
1110 */
00178629
LDM
1111KMOD_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
2f47c7fa
LDM
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 */
00178629
LDM
1129KMOD_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
2f47c7fa
LDM
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 */
00178629
LDM
1147KMOD_EXPORT const char *kmod_config_iter_get_value(const struct kmod_config_iter *iter)
1148{
6b04ef32
LDM
1149 const char *s;
1150
00178629
LDM
1151 if (iter == NULL || iter->curr == NULL)
1152 return NULL;
1153
1154 if (iter->get_value == NULL)
1155 return NULL;
1156
6b04ef32
LDM
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;
00178629
LDM
1166}
1167
2f47c7fa
LDM
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 */
00178629
LDM
1180KMOD_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
2f47c7fa
LDM
1195/**
1196 * kmod_config_iter_free_iter:
1197 * @iter: iterator over a certain configuration
1198 *
1199 * Free resources used by the iterator.
1200 */
00178629
LDM
1201KMOD_EXPORT void kmod_config_iter_free_iter(struct kmod_config_iter *iter)
1202{
6b04ef32 1203 free(iter->data);
00178629
LDM
1204 free(iter);
1205}