]>
git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod-config.c
a5c6d114eb247f26dccc04405b2c6200618e7f27
2 * libkmod - interface to kernel module operations
4 * Copyright (C) 2011-2012 ProFUSION embedded systems
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include <sys/types.h>
34 #include "libkmod-private.h"
59 const char *kmod_blacklist_get_modname(const struct kmod_list
*l
)
64 const char *kmod_alias_get_name(const struct kmod_list
*l
) {
65 const struct kmod_alias
*alias
= l
->data
;
69 const char *kmod_alias_get_modname(const struct kmod_list
*l
) {
70 const struct kmod_alias
*alias
= l
->data
;
71 return alias
->modname
;
74 const char *kmod_option_get_options(const struct kmod_list
*l
) {
75 const struct kmod_options
*alias
= l
->data
;
76 return alias
->options
;
79 const char *kmod_option_get_modname(const struct kmod_list
*l
) {
80 const struct kmod_options
*alias
= l
->data
;
81 return alias
->modname
;
84 const char *kmod_command_get_command(const struct kmod_list
*l
) {
85 const struct kmod_command
*alias
= l
->data
;
86 return alias
->command
;
89 const char *kmod_command_get_modname(const struct kmod_list
*l
) {
90 const struct kmod_command
*alias
= l
->data
;
91 return alias
->modname
;
94 const char *kmod_softdep_get_name(const struct kmod_list
*l
) {
95 const struct kmod_softdep
*dep
= l
->data
;
99 const char * const *kmod_softdep_get_pre(const struct kmod_list
*l
, unsigned int *count
) {
100 const struct kmod_softdep
*dep
= l
->data
;
105 const char * const *kmod_softdep_get_post(const struct kmod_list
*l
, unsigned int *count
) {
106 const struct kmod_softdep
*dep
= l
->data
;
107 *count
= dep
->n_post
;
111 static int kmod_config_add_command(struct kmod_config
*config
,
114 const char *command_name
,
115 struct kmod_list
**list
)
117 struct kmod_command
*cmd
;
119 size_t modnamelen
= strlen(modname
) + 1;
120 size_t commandlen
= strlen(command
) + 1;
122 DBG(config
->ctx
, "modname='%s' cmd='%s %s'\n", modname
, command_name
,
125 cmd
= malloc(sizeof(*cmd
) + modnamelen
+ commandlen
);
129 cmd
->command
= sizeof(*cmd
) + modnamelen
+ (char *)cmd
;
130 memcpy(cmd
->modname
, modname
, modnamelen
);
131 memcpy(cmd
->command
, command
, commandlen
);
133 l
= kmod_list_append(*list
, cmd
);
143 ERR(config
->ctx
, "out-of-memory\n");
147 static void kmod_config_free_command(struct kmod_config
*config
,
149 struct kmod_list
**list
)
151 struct kmod_command
*cmd
= l
->data
;
154 *list
= kmod_list_remove(l
);
157 static int kmod_config_add_options(struct kmod_config
*config
,
158 const char *modname
, const char *options
)
160 struct kmod_options
*opt
;
161 struct kmod_list
*list
;
162 size_t modnamelen
= strlen(modname
) + 1;
163 size_t optionslen
= strlen(options
) + 1;
165 DBG(config
->ctx
, "modname='%s' options='%s'\n", modname
, options
);
167 opt
= malloc(sizeof(*opt
) + modnamelen
+ optionslen
);
171 opt
->options
= sizeof(*opt
) + modnamelen
+ (char *)opt
;
173 memcpy(opt
->modname
, modname
, modnamelen
);
174 memcpy(opt
->options
, options
, optionslen
);
175 strchr_replace(opt
->options
, '\t', ' ');
177 list
= kmod_list_append(config
->options
, opt
);
181 config
->options
= list
;
187 ERR(config
->ctx
, "out-of-memory\n");
191 static void kmod_config_free_options(struct kmod_config
*config
,
194 struct kmod_options
*opt
= l
->data
;
198 config
->options
= kmod_list_remove(l
);
201 static int kmod_config_add_alias(struct kmod_config
*config
,
202 const char *name
, const char *modname
)
204 struct kmod_alias
*alias
;
205 struct kmod_list
*list
;
206 size_t namelen
= strlen(name
) + 1, modnamelen
= strlen(modname
) + 1;
208 DBG(config
->ctx
, "name=%s modname=%s\n", name
, modname
);
210 alias
= malloc(sizeof(*alias
) + namelen
+ modnamelen
);
214 alias
->name
= sizeof(*alias
) + modnamelen
+ (char *)alias
;
216 memcpy(alias
->modname
, modname
, modnamelen
);
217 memcpy(alias
->name
, name
, namelen
);
219 list
= kmod_list_append(config
->aliases
, alias
);
223 config
->aliases
= list
;
229 ERR(config
->ctx
, "out-of-memory name=%s modname=%s\n", name
, modname
);
233 static void kmod_config_free_alias(struct kmod_config
*config
,
236 struct kmod_alias
*alias
= l
->data
;
240 config
->aliases
= kmod_list_remove(l
);
243 static int kmod_config_add_blacklist(struct kmod_config
*config
,
247 struct kmod_list
*list
;
249 DBG(config
->ctx
, "modname=%s\n", modname
);
255 list
= kmod_list_append(config
->blacklists
, p
);
258 config
->blacklists
= list
;
264 ERR(config
->ctx
, "out-of-memory modname=%s\n", modname
);
268 static void kmod_config_free_blacklist(struct kmod_config
*config
,
272 config
->blacklists
= kmod_list_remove(l
);
275 static int kmod_config_add_softdep(struct kmod_config
*config
,
279 struct kmod_list
*list
;
280 struct kmod_softdep
*dep
;
283 unsigned int n_pre
= 0, n_post
= 0;
284 size_t modnamelen
= strlen(modname
) + 1;
286 bool was_space
= false;
287 enum { S_NONE
, S_PRE
, S_POST
} mode
= S_NONE
;
289 DBG(config
->ctx
, "modname=%s\n", modname
);
291 /* analyze and count */
292 for (p
= s
= line
; ; s
++) {
312 if (plen
== sizeof("pre:") - 1 &&
313 memcmp(p
, "pre:", sizeof("pre:") - 1) == 0)
315 else if (plen
== sizeof("post:") - 1 &&
316 memcmp(p
, "post:", sizeof("post:") - 1) == 0)
318 else if (*s
!= '\0' || (*s
== '\0' && !was_space
)) {
322 } else if (mode
== S_POST
) {
332 DBG(config
->ctx
, "%u pre, %u post\n", n_pre
, n_post
);
334 dep
= malloc(sizeof(struct kmod_softdep
) + modnamelen
+
335 n_pre
* sizeof(const char *) +
336 n_post
* sizeof(const char *) +
339 ERR(config
->ctx
, "out-of-memory modname=%s\n", modname
);
343 dep
->n_post
= n_post
;
344 dep
->pre
= (const char **)((char *)dep
+ sizeof(struct kmod_softdep
));
345 dep
->post
= dep
->pre
+ n_pre
;
346 dep
->name
= (char *)(dep
->post
+ n_post
);
348 memcpy(dep
->name
, modname
, modnamelen
);
351 itr
= dep
->name
+ modnamelen
;
355 for (p
= s
= line
; ; s
++) {
375 if (plen
== sizeof("pre:") - 1 &&
376 memcmp(p
, "pre:", sizeof("pre:") - 1) == 0)
378 else if (plen
== sizeof("post:") - 1 &&
379 memcmp(p
, "post:", sizeof("post:") - 1) == 0)
381 else if (*s
!= '\0' || (*s
== '\0' && !was_space
)) {
383 dep
->pre
[n_pre
] = itr
;
384 memcpy(itr
, p
, plen
);
388 } else if (mode
== S_POST
) {
389 dep
->post
[n_post
] = itr
;
390 memcpy(itr
, p
, plen
);
401 list
= kmod_list_append(config
->softdeps
, dep
);
406 config
->softdeps
= list
;
411 static void kmod_config_free_softdep(struct kmod_config
*config
,
415 config
->softdeps
= kmod_list_remove(l
);
418 static void kcmdline_parse_result(struct kmod_config
*config
, char *modname
,
419 char *param
, char *value
)
421 if (modname
== NULL
|| param
== NULL
|| value
== NULL
)
424 DBG(config
->ctx
, "%s %s\n", modname
, param
);
426 if (streq(modname
, "modprobe") && !strncmp(param
, "blacklist=", 10)) {
428 char *t
= strsep(&value
, ",");
432 kmod_config_add_blacklist(config
, t
);
435 kmod_config_add_options(config
,
436 underscores(config
->ctx
, modname
), param
);
440 static int kmod_config_parse_kcmdline(struct kmod_config
*config
)
442 char buf
[KCMD_LINE_SIZE
];
444 char *p
, *modname
, *param
= NULL
, *value
= NULL
;
446 fd
= open("/proc/cmdline", O_RDONLY
|O_CLOEXEC
);
449 DBG(config
->ctx
, "could not open '/proc/cmdline' for reading: %m\n");
453 err
= read_str_safe(fd
, buf
, sizeof(buf
));
456 ERR(config
->ctx
, "could not read from '/proc/cmdline': %s\n",
461 for (p
= buf
, modname
= buf
; *p
!= '\0' && *p
!= '\n'; p
++) {
465 kcmdline_parse_result(config
, modname
, param
, value
);
466 param
= value
= NULL
;
481 kcmdline_parse_result(config
, modname
, param
, value
);
487 * Take an fd and own it. It will be closed on return. filename is used only
490 static int kmod_config_parse(struct kmod_config
*config
, int fd
,
491 const char *filename
)
493 struct kmod_ctx
*ctx
= config
->ctx
;
496 unsigned int linenum
= 0;
499 fp
= fdopen(fd
, "r");
502 ERR(config
->ctx
, "fd %d: %m", fd
);
507 while ((line
= getline_wrapped(fp
, &linenum
)) != NULL
) {
510 if (line
[0] == '\0' || line
[0] == '#')
513 cmd
= strtok_r(line
, "\t ", &saveptr
);
517 if (streq(cmd
, "alias")) {
518 char *alias
= strtok_r(NULL
, "\t ", &saveptr
);
519 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
521 if (alias
== NULL
|| modname
== NULL
)
524 kmod_config_add_alias(config
,
525 underscores(ctx
, alias
),
526 underscores(ctx
, modname
));
527 } else if (streq(cmd
, "blacklist")) {
528 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
533 kmod_config_add_blacklist(config
,
534 underscores(ctx
, modname
));
535 } else if (streq(cmd
, "options")) {
536 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
537 char *options
= strtok_r(NULL
, "\0", &saveptr
);
539 if (modname
== NULL
|| options
== NULL
)
542 kmod_config_add_options(config
,
543 underscores(ctx
, modname
),
545 } else if (streq(cmd
, "install")) {
546 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
547 char *installcmd
= strtok_r(NULL
, "\0", &saveptr
);
549 if (modname
== NULL
|| installcmd
== NULL
)
552 kmod_config_add_command(config
,
553 underscores(ctx
, modname
),
555 cmd
, &config
->install_commands
);
556 } else if (streq(cmd
, "remove")) {
557 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
558 char *removecmd
= strtok_r(NULL
, "\0", &saveptr
);
560 if (modname
== NULL
|| removecmd
== NULL
)
563 kmod_config_add_command(config
,
564 underscores(ctx
, modname
),
566 cmd
, &config
->remove_commands
);
567 } else if (streq(cmd
, "softdep")) {
568 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
569 char *softdeps
= strtok_r(NULL
, "\0", &saveptr
);
571 if (modname
== NULL
|| softdeps
== NULL
)
574 kmod_config_add_softdep(config
,
575 underscores(ctx
, modname
),
577 } else if (streq(cmd
, "include")
578 || streq(cmd
, "config")) {
579 ERR(ctx
, "%s: command %s is deprecated and not parsed anymore\n",
583 ERR(ctx
, "%s line %u: ignoring bad line starting with '%s'\n",
584 filename
, linenum
, cmd
);
596 void kmod_config_free(struct kmod_config
*config
)
598 while (config
->aliases
)
599 kmod_config_free_alias(config
, config
->aliases
);
601 while (config
->blacklists
)
602 kmod_config_free_blacklist(config
, config
->blacklists
);
604 while (config
->options
)
605 kmod_config_free_options(config
, config
->options
);
607 while (config
->install_commands
) {
608 kmod_config_free_command(config
, config
->install_commands
,
609 &config
->install_commands
);
612 while (config
->remove_commands
) {
613 kmod_config_free_command(config
, config
->remove_commands
,
614 &config
->remove_commands
);
617 while (config
->softdeps
)
618 kmod_config_free_softdep(config
, config
->softdeps
);
620 for (; config
->paths
!= NULL
;
621 config
->paths
= kmod_list_remove(config
->paths
))
622 free(config
->paths
->data
);
627 static bool conf_files_filter_out(struct kmod_ctx
*ctx
, DIR *d
,
628 const char *path
, const char *fn
)
630 size_t len
= strlen(fn
);
636 if (len
< 6 || (!streq(&fn
[len
- 5], ".conf")
637 && !streq(&fn
[len
- 6], ".alias")))
640 fstatat(dirfd(d
), fn
, &st
, 0);
642 if (S_ISDIR(st
.st_mode
)) {
643 ERR(ctx
, "Directories inside directories are not supported: "
644 "%s/%s\n", path
, fn
);
657 static int conf_files_insert_sorted(struct kmod_ctx
*ctx
,
658 struct kmod_list
**list
,
659 const char *path
, const char *name
)
661 struct kmod_list
*lpos
, *tmp
;
662 struct conf_file
*cf
;
665 bool is_single
= false;
668 name
= basename(path
);
672 kmod_list_foreach(lpos
, *list
) {
675 if ((cmp
= strcmp(name
, cf
->name
)) <= 0)
680 DBG(ctx
, "Ignoring duplicate config file: %s/%s\n", path
,
685 namelen
= strlen(name
);
686 cf
= malloc(sizeof(*cf
) + namelen
+ 1);
690 memcpy(cf
->name
, name
, namelen
+ 1);
692 cf
->is_single
= is_single
;
695 tmp
= kmod_list_append(*list
, cf
);
696 else if (lpos
== *list
)
697 tmp
= kmod_list_prepend(*list
, cf
);
699 tmp
= kmod_list_insert_before(lpos
, cf
);
706 if (lpos
== NULL
|| lpos
== *list
)
713 * Insert configuration files in @list, ignoring duplicates
715 static int conf_files_list(struct kmod_ctx
*ctx
, struct kmod_list
**list
,
717 unsigned long long *path_stamp
)
723 if (stat(path
, &st
) != 0) {
725 DBG(ctx
, "could not stat '%s': %m\n", path
);
729 *path_stamp
= ts_usec(&st
.st_mtim
);
731 if (S_ISREG(st
.st_mode
)) {
732 conf_files_insert_sorted(ctx
, list
, path
, NULL
);
734 } if (!S_ISDIR(st
.st_mode
)) {
735 ERR(ctx
, "unsupported file mode %s: %#x\n",
747 struct dirent ent
, *entp
;
749 err
= readdir_r(d
, &ent
, &entp
);
751 ERR(ctx
, "reading entry %s\n", strerror(-err
));
758 if (conf_files_filter_out(ctx
, d
, path
, entp
->d_name
))
761 conf_files_insert_sorted(ctx
, list
, path
, entp
->d_name
);
772 int kmod_config_new(struct kmod_ctx
*ctx
, struct kmod_config
**p_config
,
773 const char * const *config_paths
)
775 struct kmod_config
*config
;
776 struct kmod_list
*list
= NULL
;
777 struct kmod_list
*path_list
= NULL
;
780 for (i
= 0; config_paths
[i
] != NULL
; i
++) {
781 const char *path
= config_paths
[i
];
782 unsigned long long path_stamp
= 0;
784 struct kmod_list
*tmp
;
785 struct kmod_config_path
*cf
;
787 if (conf_files_list(ctx
, &list
, path
, &path_stamp
) < 0)
790 pathlen
= strlen(path
) + 1;
791 cf
= malloc(sizeof(*cf
) + pathlen
);
795 cf
->stamp
= path_stamp
;
796 memcpy(cf
->path
, path
, pathlen
);
798 tmp
= kmod_list_append(path_list
, cf
);
804 *p_config
= config
= calloc(1, sizeof(struct kmod_config
));
808 config
->paths
= path_list
;
811 for (; list
!= NULL
; list
= kmod_list_remove(list
)) {
813 struct conf_file
*cf
= list
->data
;
817 strcpy(fn
, cf
->path
);
819 snprintf(fn
, sizeof(fn
),"%s/%s", cf
->path
,
822 fd
= open(fn
, O_RDONLY
|O_CLOEXEC
);
823 DBG(ctx
, "parsing file '%s' fd=%d\n", fn
, fd
);
826 kmod_config_parse(config
, fd
, fn
);
831 kmod_config_parse_kcmdline(config
);
836 for (; list
!= NULL
; list
= kmod_list_remove(list
))
839 for (; path_list
!= NULL
; path_list
= kmod_list_remove(path_list
))
840 free(path_list
->data
);