]>
git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod-config.c
2 * libkmod - interface to kernel module operations
4 * Copyright (C) 2011 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_alias_get_name(const struct kmod_list
*l
) {
60 const struct kmod_alias
*alias
= l
->data
;
64 const char *kmod_alias_get_modname(const struct kmod_list
*l
) {
65 const struct kmod_alias
*alias
= l
->data
;
66 return alias
->modname
;
69 const char *kmod_option_get_options(const struct kmod_list
*l
) {
70 const struct kmod_options
*alias
= l
->data
;
71 return alias
->options
;
74 const char *kmod_option_get_modname(const struct kmod_list
*l
) {
75 const struct kmod_options
*alias
= l
->data
;
76 return alias
->modname
;
79 const char *kmod_command_get_command(const struct kmod_list
*l
) {
80 const struct kmod_command
*alias
= l
->data
;
81 return alias
->command
;
84 const char *kmod_command_get_modname(const struct kmod_list
*l
) {
85 const struct kmod_command
*alias
= l
->data
;
86 return alias
->modname
;
89 const char *kmod_softdep_get_name(const struct kmod_list
*l
) {
90 const struct kmod_softdep
*dep
= l
->data
;
94 const char * const *kmod_softdep_get_pre(const struct kmod_list
*l
, unsigned int *count
) {
95 const struct kmod_softdep
*dep
= l
->data
;
100 const char * const *kmod_softdep_get_post(const struct kmod_list
*l
, unsigned int *count
) {
101 const struct kmod_softdep
*dep
= l
->data
;
102 *count
= dep
->n_post
;
106 static int kmod_config_add_command(struct kmod_config
*config
,
109 const char *command_name
,
110 struct kmod_list
**list
)
112 struct kmod_command
*cmd
;
114 size_t modnamelen
= strlen(modname
) + 1;
115 size_t commandlen
= strlen(command
) + 1;
117 DBG(config
->ctx
, "modname='%s' cmd='%s %s'\n", modname
, command_name
,
120 cmd
= malloc(sizeof(*cmd
) + modnamelen
+ commandlen
);
124 cmd
->command
= sizeof(*cmd
) + modnamelen
+ (char *)cmd
;
125 memcpy(cmd
->modname
, modname
, modnamelen
);
126 memcpy(cmd
->command
, command
, commandlen
);
128 l
= kmod_list_append(*list
, cmd
);
138 ERR(config
->ctx
, "out-of-memory\n");
142 static void kmod_config_free_command(struct kmod_config
*config
,
144 struct kmod_list
**list
)
146 struct kmod_command
*cmd
= l
->data
;
149 *list
= kmod_list_remove(l
);
152 static int kmod_config_add_options(struct kmod_config
*config
,
153 const char *modname
, const char *options
)
155 struct kmod_options
*opt
;
156 struct kmod_list
*list
;
157 size_t modnamelen
= strlen(modname
) + 1;
158 size_t optionslen
= strlen(options
) + 1;
160 DBG(config
->ctx
, "modname='%s' options='%s'\n", modname
, options
);
162 opt
= malloc(sizeof(*opt
) + modnamelen
+ optionslen
);
166 opt
->options
= sizeof(*opt
) + modnamelen
+ (char *)opt
;
168 memcpy(opt
->modname
, modname
, modnamelen
);
169 memcpy(opt
->options
, options
, optionslen
);
170 strchr_replace(opt
->options
, '\t', ' ');
172 list
= kmod_list_append(config
->options
, opt
);
176 config
->options
= list
;
182 ERR(config
->ctx
, "out-of-memory\n");
186 static void kmod_config_free_options(struct kmod_config
*config
,
189 struct kmod_options
*opt
= l
->data
;
193 config
->options
= kmod_list_remove(l
);
196 static int kmod_config_add_alias(struct kmod_config
*config
,
197 const char *name
, const char *modname
)
199 struct kmod_alias
*alias
;
200 struct kmod_list
*list
;
201 size_t namelen
= strlen(name
) + 1, modnamelen
= strlen(modname
) + 1;
203 DBG(config
->ctx
, "name=%s modname=%s\n", name
, modname
);
205 alias
= malloc(sizeof(*alias
) + namelen
+ modnamelen
);
209 alias
->name
= sizeof(*alias
) + modnamelen
+ (char *)alias
;
211 memcpy(alias
->modname
, modname
, modnamelen
);
212 memcpy(alias
->name
, name
, namelen
);
214 list
= kmod_list_append(config
->aliases
, alias
);
218 config
->aliases
= list
;
224 ERR(config
->ctx
, "out-of-memory name=%s modname=%s\n", name
, modname
);
228 static void kmod_config_free_alias(struct kmod_config
*config
,
231 struct kmod_alias
*alias
= l
->data
;
235 config
->aliases
= kmod_list_remove(l
);
238 static int kmod_config_add_blacklist(struct kmod_config
*config
,
242 struct kmod_list
*list
;
244 DBG(config
->ctx
, "modname=%s\n", modname
);
250 list
= kmod_list_append(config
->blacklists
, p
);
253 config
->blacklists
= list
;
259 ERR(config
->ctx
, "out-of-memory modname=%s\n", modname
);
263 static void kmod_config_free_blacklist(struct kmod_config
*config
,
267 config
->blacklists
= kmod_list_remove(l
);
270 static int kmod_config_add_softdep(struct kmod_config
*config
,
274 struct kmod_list
*list
;
275 struct kmod_softdep
*dep
;
278 unsigned int n_pre
= 0, n_post
= 0;
279 size_t modnamelen
= strlen(modname
) + 1;
281 bool was_space
= false;
282 enum { S_NONE
, S_PRE
, S_POST
} mode
= S_NONE
;
284 DBG(config
->ctx
, "modname=%s\n", modname
);
286 /* analyze and count */
287 for (p
= s
= line
; ; s
++) {
307 if (plen
== sizeof("pre:") - 1 &&
308 memcmp(p
, "pre:", sizeof("pre:") - 1) == 0)
310 else if (plen
== sizeof("post:") - 1 &&
311 memcmp(p
, "post:", sizeof("post:") - 1) == 0)
313 else if (*s
!= '\0' || (*s
== '\0' && !was_space
)) {
317 } else if (mode
== S_POST
) {
327 DBG(config
->ctx
, "%u pre, %u post\n", n_pre
, n_post
);
329 dep
= malloc(sizeof(struct kmod_softdep
) + modnamelen
+
330 n_pre
* sizeof(const char *) +
331 n_post
* sizeof(const char *) +
334 ERR(config
->ctx
, "out-of-memory modname=%s\n", modname
);
338 dep
->n_post
= n_post
;
339 dep
->pre
= (const char **)((char *)dep
+ sizeof(struct kmod_softdep
));
340 dep
->post
= dep
->pre
+ n_pre
;
341 dep
->name
= (char *)(dep
->post
+ n_post
);
343 memcpy(dep
->name
, modname
, modnamelen
);
346 itr
= dep
->name
+ modnamelen
;
350 for (p
= s
= line
; ; s
++) {
370 if (plen
== sizeof("pre:") - 1 &&
371 memcmp(p
, "pre:", sizeof("pre:") - 1) == 0)
373 else if (plen
== sizeof("post:") - 1 &&
374 memcmp(p
, "post:", sizeof("post:") - 1) == 0)
376 else if (*s
!= '\0' || (*s
== '\0' && !was_space
)) {
378 dep
->pre
[n_pre
] = itr
;
379 memcpy(itr
, p
, plen
);
383 } else if (mode
== S_POST
) {
384 dep
->post
[n_post
] = itr
;
385 memcpy(itr
, p
, plen
);
396 list
= kmod_list_append(config
->softdeps
, dep
);
401 config
->softdeps
= list
;
406 static void kmod_config_free_softdep(struct kmod_config
*config
,
410 config
->softdeps
= kmod_list_remove(l
);
413 static void kcmdline_parse_result(struct kmod_config
*config
, char *modname
,
414 char *param
, char *value
)
416 if (modname
== NULL
|| param
== NULL
|| value
== NULL
)
419 DBG(config
->ctx
, "%s %s\n", modname
, param
);
421 if (streq(modname
, "modprobe") && !strncmp(param
, "blacklist=", 10)) {
423 char *t
= strsep(&value
, ",");
427 kmod_config_add_blacklist(config
, t
);
430 kmod_config_add_options(config
,
431 underscores(config
->ctx
, modname
), param
);
435 static int kmod_config_parse_kcmdline(struct kmod_config
*config
)
437 char buf
[KCMD_LINE_SIZE
];
439 char *p
, *modname
, *param
= NULL
, *value
= NULL
;
441 fd
= open("/proc/cmdline", O_RDONLY
|O_CLOEXEC
);
442 err
= read_str_safe(fd
, buf
, sizeof(buf
));
445 ERR(config
->ctx
, "could not read from '/proc/cmdline': %s\n",
450 for (p
= buf
, modname
= buf
; *p
!= '\0' && *p
!= '\n'; p
++) {
454 kcmdline_parse_result(config
, modname
, param
, value
);
455 param
= value
= NULL
;
470 kcmdline_parse_result(config
, modname
, param
, value
);
476 * Take an fd and own it. It will be closed on return. filename is used only
479 static int kmod_config_parse(struct kmod_config
*config
, int fd
,
480 const char *filename
)
482 struct kmod_ctx
*ctx
= config
->ctx
;
485 unsigned int linenum
;
488 fp
= fdopen(fd
, "r");
491 ERR(config
->ctx
, "fd %d: %m", fd
);
496 while ((line
= getline_wrapped(fp
, &linenum
)) != NULL
) {
499 if (line
[0] == '\0' || line
[0] == '#')
502 cmd
= strtok_r(line
, "\t ", &saveptr
);
506 if (streq(cmd
, "alias")) {
507 char *alias
= strtok_r(NULL
, "\t ", &saveptr
);
508 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
510 if (alias
== NULL
|| modname
== NULL
)
513 kmod_config_add_alias(config
,
514 underscores(ctx
, alias
),
515 underscores(ctx
, modname
));
516 } else if (streq(cmd
, "blacklist")) {
517 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
522 kmod_config_add_blacklist(config
,
523 underscores(ctx
, modname
));
524 } else if (streq(cmd
, "options")) {
525 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
530 kmod_config_add_options(config
,
531 underscores(ctx
, modname
),
532 strtok_r(NULL
, "\0", &saveptr
));
533 } else if streq(cmd
, "install") {
534 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
539 kmod_config_add_command(config
,
540 underscores(ctx
, modname
),
541 strtok_r(NULL
, "\0", &saveptr
),
542 cmd
, &config
->install_commands
);
543 } else if streq(cmd
, "remove") {
544 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
549 kmod_config_add_command(config
,
550 underscores(ctx
, modname
),
551 strtok_r(NULL
, "\0", &saveptr
),
552 cmd
, &config
->remove_commands
);
553 } else if streq(cmd
, "softdep") {
554 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
559 kmod_config_add_softdep(config
,
560 underscores(ctx
, modname
),
561 strtok_r(NULL
, "\0", &saveptr
));
562 } else if (streq(cmd
, "include")
563 || streq(cmd
, "config")) {
564 INFO(ctx
, "%s: command %s not implemented yet\n",
568 ERR(ctx
, "%s line %u: ignoring bad line starting with '%s'\n",
569 filename
, linenum
, cmd
);
581 void kmod_config_free(struct kmod_config
*config
)
583 while (config
->aliases
)
584 kmod_config_free_alias(config
, config
->aliases
);
586 while (config
->blacklists
)
587 kmod_config_free_blacklist(config
, config
->blacklists
);
589 while (config
->options
)
590 kmod_config_free_options(config
, config
->options
);
592 while (config
->install_commands
) {
593 kmod_config_free_command(config
, config
->install_commands
,
594 &config
->install_commands
);
597 while (config
->remove_commands
) {
598 kmod_config_free_command(config
, config
->remove_commands
,
599 &config
->remove_commands
);
602 while (config
->softdeps
)
603 kmod_config_free_softdep(config
, config
->softdeps
);
608 static bool conf_files_filter_out(struct kmod_ctx
*ctx
, DIR *d
,
609 const char *path
, const char *fn
)
611 size_t len
= strlen(fn
);
617 if (len
< 6 || (!streq(&fn
[len
- 5], ".conf")
618 && !streq(&fn
[len
- 6], ".alias"))) {
619 INFO(ctx
, "All config files need .conf: %s/%s, "
620 "it will be ignored in a future release\n",
625 fstatat(dirfd(d
), fn
, &st
, 0);
627 if (S_ISDIR(st
.st_mode
)) {
628 ERR(ctx
, "Directories inside directories are not supported: "
629 "%s/%s\n", path
, fn
);
637 * Iterate over a directory (given by @path) and save the list of
638 * configuration files in @list.
640 static DIR *conf_files_list(struct kmod_ctx
*ctx
, struct kmod_list
**list
,
655 struct dirent ent
, *entp
;
656 struct kmod_list
*l
, *tmp
;
659 err
= readdir_r(d
, &ent
, &entp
);
661 ERR(ctx
, "reading entry %s\n", strerror(-err
));
668 if (conf_files_filter_out(ctx
, d
, path
, entp
->d_name
))
672 kmod_list_foreach(l
, *list
) {
673 if (strcmp(entp
->d_name
, l
->data
) < 0)
677 dname
= strdup(entp
->d_name
);
682 tmp
= kmod_list_append(*list
, dname
);
684 tmp
= kmod_list_prepend(*list
, dname
);
686 tmp
= kmod_list_insert_before(l
, dname
);
691 if (l
== NULL
|| l
== *list
)
698 ERR(ctx
, "out of memory while scanning '%s'\n", path
);
700 for (; *list
!= NULL
; *list
= kmod_list_remove(*list
))
706 int kmod_config_new(struct kmod_ctx
*ctx
, struct kmod_config
**p_config
,
707 const char * const *config_paths
)
709 struct kmod_config
*config
;
712 *p_config
= config
= calloc(1, sizeof(struct kmod_config
));
718 for (i
= 0; config_paths
[i
] != NULL
; i
++) {
719 const char *path
= config_paths
[i
];
720 struct kmod_list
*list
;
724 if (stat(path
, &st
) != 0) {
725 DBG(ctx
, "could not load '%s': %s\n",
726 path
, strerror(errno
));
730 if (S_ISREG(st
.st_mode
)) {
731 int fd
= open(path
, O_RDONLY
|O_CLOEXEC
);
732 DBG(ctx
, "parsing file '%s': %d\n", path
, fd
);
734 kmod_config_parse(config
, fd
, path
);
736 } else if (!S_ISDIR(st
.st_mode
)) {
737 ERR(ctx
, "unsupported file mode %s: %#x\n",
742 d
= conf_files_list(ctx
, &list
, path
);
744 for (; list
!= NULL
; list
= kmod_list_remove(list
)) {
745 int fd
= openat(dirfd(d
), list
->data
, O_RDONLY
|O_CLOEXEC
);
746 DBG(ctx
, "parsing file '%s/%s': %d\n", path
,
747 (const char *) list
->data
, fd
);
749 kmod_config_parse(config
, fd
, list
->data
);
757 kmod_config_parse_kcmdline(config
);