]>
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"
51 const char *kmod_alias_get_name(const struct kmod_list
*l
) {
52 const struct kmod_alias
*alias
= l
->data
;
56 const char *kmod_alias_get_modname(const struct kmod_list
*l
) {
57 const struct kmod_alias
*alias
= l
->data
;
58 return alias
->modname
;
61 const char *kmod_option_get_options(const struct kmod_list
*l
) {
62 const struct kmod_options
*alias
= l
->data
;
63 return alias
->options
;
66 const char *kmod_option_get_modname(const struct kmod_list
*l
) {
67 const struct kmod_options
*alias
= l
->data
;
68 return alias
->modname
;
71 const char *kmod_command_get_command(const struct kmod_list
*l
) {
72 const struct kmod_command
*alias
= l
->data
;
73 return alias
->command
;
76 const char *kmod_command_get_modname(const struct kmod_list
*l
) {
77 const struct kmod_command
*alias
= l
->data
;
78 return alias
->modname
;
81 static int kmod_config_add_command(struct kmod_config
*config
,
84 const char *command_name
,
85 struct kmod_list
**list
)
87 struct kmod_command
*cmd
;
89 size_t modnamelen
= strlen(modname
) + 1;
90 size_t commandlen
= strlen(command
) + 1;
92 DBG(config
->ctx
, "modname'%s' cmd='%s %s'\n", modname
, command_name
,
95 cmd
= malloc(sizeof(*cmd
) + modnamelen
+ commandlen
);
99 cmd
->command
= sizeof(*cmd
) + modnamelen
+ (char *)cmd
;
100 memcpy(cmd
->modname
, modname
, modnamelen
);
101 memcpy(cmd
->command
, command
, commandlen
);
103 l
= kmod_list_append(*list
, cmd
);
113 ERR(config
->ctx
, "out-of-memory\n");
117 static void kmod_config_free_command(struct kmod_config
*config
,
119 struct kmod_list
**list
)
121 struct kmod_command
*cmd
= l
->data
;
124 *list
= kmod_list_remove(l
);
127 static int kmod_config_add_options(struct kmod_config
*config
,
128 const char *modname
, const char *options
)
130 struct kmod_options
*opt
;
131 struct kmod_list
*list
;
132 size_t modnamelen
= strlen(modname
) + 1;
133 size_t optionslen
= strlen(options
) + 1;
135 DBG(config
->ctx
, "modname'%s' options='%s'\n", modname
, options
);
137 opt
= malloc(sizeof(*opt
) + modnamelen
+ optionslen
);
141 opt
->options
= sizeof(*opt
) + modnamelen
+ (char *)opt
;
143 memcpy(opt
->modname
, modname
, modnamelen
);
144 memcpy(opt
->options
, options
, optionslen
);
145 strchr_replace(opt
->options
, '\t', ' ');
147 list
= kmod_list_append(config
->options
, opt
);
151 config
->options
= list
;
157 ERR(config
->ctx
, "out-of-memory\n");
161 static void kmod_config_free_options(struct kmod_config
*config
,
164 struct kmod_options
*opt
= l
->data
;
168 config
->options
= kmod_list_remove(l
);
171 static int kmod_config_add_alias(struct kmod_config
*config
,
172 const char *name
, const char *modname
)
174 struct kmod_alias
*alias
;
175 struct kmod_list
*list
;
176 size_t namelen
= strlen(name
) + 1, modnamelen
= strlen(modname
) + 1;
178 DBG(config
->ctx
, "name=%s modname=%s\n", name
, modname
);
180 alias
= malloc(sizeof(*alias
) + namelen
+ modnamelen
);
184 alias
->name
= sizeof(*alias
) + modnamelen
+ (char *)alias
;
186 memcpy(alias
->modname
, modname
, modnamelen
);
187 memcpy(alias
->name
, name
, namelen
);
189 list
= kmod_list_append(config
->aliases
, alias
);
193 config
->aliases
= list
;
199 ERR(config
->ctx
, "out-of-memory name=%s modname=%s\n", name
, modname
);
203 static void kmod_config_free_alias(struct kmod_config
*config
,
206 struct kmod_alias
*alias
= l
->data
;
210 config
->aliases
= kmod_list_remove(l
);
213 static int kmod_config_add_blacklist(struct kmod_config
*config
,
217 struct kmod_list
*list
;
219 DBG(config
->ctx
, "modname=%s\n", modname
);
225 list
= kmod_list_append(config
->blacklists
, p
);
228 config
->blacklists
= list
;
234 ERR(config
->ctx
, "out-of-memory modname=%s\n", modname
);
238 static void kmod_config_free_blacklist(struct kmod_config
*config
,
242 config
->blacklists
= kmod_list_remove(l
);
245 static void kcmdline_parse_result(struct kmod_config
*config
, char *modname
,
246 char *param
, char *value
)
248 if (modname
== NULL
|| param
== NULL
|| value
== NULL
)
251 DBG(config
->ctx
, "%s %s\n", modname
, param
);
253 if (streq(modname
, "modprobe") && !strncmp(param
, "blacklist=", 10)) {
255 char *t
= strsep(&value
, ",");
259 kmod_config_add_blacklist(config
, t
);
262 kmod_config_add_options(config
,
263 underscores(config
->ctx
, modname
), param
);
267 static int kmod_config_parse_kcmdline(struct kmod_config
*config
)
269 char buf
[KCMD_LINE_SIZE
];
271 char *p
, *modname
, *param
= NULL
, *value
= NULL
;
273 fd
= open("/proc/cmdline", O_RDONLY
);
274 err
= read_str_safe(fd
, buf
, sizeof(buf
));
277 ERR(config
->ctx
, "could not read from '/proc/cmdline': %s\n",
282 for (p
= buf
, modname
= buf
; *p
!= '\0' && *p
!= '\n'; p
++) {
286 kcmdline_parse_result(config
, modname
, param
, value
);
287 param
= value
= NULL
;
301 kcmdline_parse_result(config
, modname
, param
, value
);
307 * Take an fd and own it. It will be closed on return. filename is used only
310 static int kmod_config_parse(struct kmod_config
*config
, int fd
,
311 const char *filename
)
313 struct kmod_ctx
*ctx
= config
->ctx
;
316 unsigned int linenum
;
319 fp
= fdopen(fd
, "r");
322 ERR(config
->ctx
, "fd %d: %m", fd
);
327 while ((line
= getline_wrapped(fp
, &linenum
)) != NULL
) {
330 if (line
[0] == '\0' || line
[0] == '#')
333 cmd
= strtok_r(line
, "\t ", &saveptr
);
337 if (streq(cmd
, "alias")) {
338 char *alias
= strtok_r(NULL
, "\t ", &saveptr
);
339 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
341 if (alias
== NULL
|| modname
== NULL
)
344 kmod_config_add_alias(config
,
345 underscores(ctx
, alias
),
346 underscores(ctx
, modname
));
347 } else if (streq(cmd
, "blacklist")) {
348 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
353 kmod_config_add_blacklist(config
,
354 underscores(ctx
, modname
));
355 } else if (streq(cmd
, "options")) {
356 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
361 kmod_config_add_options(config
,
362 underscores(ctx
, modname
),
363 strtok_r(NULL
, "\0", &saveptr
));
364 } else if streq(cmd
, "install") {
365 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
370 kmod_config_add_command(config
,
371 underscores(ctx
, modname
),
372 strtok_r(NULL
, "\0", &saveptr
),
373 cmd
, &config
->install_commands
);
374 } else if streq(cmd
, "remove") {
375 char *modname
= strtok_r(NULL
, "\t ", &saveptr
);
380 kmod_config_add_command(config
,
381 underscores(ctx
, modname
),
382 strtok_r(NULL
, "\0", &saveptr
),
383 cmd
, &config
->remove_commands
);
384 } else if (streq(cmd
, "include")
385 || streq(cmd
, "softdep")
386 || streq(cmd
, "config")) {
387 INFO(ctx
, "%s: command %s not implemented yet\n",
391 ERR(ctx
, "%s line %u: ignoring bad line starting with '%s'\n",
392 filename
, linenum
, cmd
);
404 void kmod_config_free(struct kmod_config
*config
)
406 while (config
->aliases
)
407 kmod_config_free_alias(config
, config
->aliases
);
409 while (config
->blacklists
)
410 kmod_config_free_blacklist(config
, config
->blacklists
);
412 while (config
->options
)
413 kmod_config_free_options(config
, config
->options
);
415 while (config
->install_commands
) {
416 kmod_config_free_command(config
, config
->install_commands
,
417 &config
->install_commands
);
420 while (config
->remove_commands
) {
421 kmod_config_free_command(config
, config
->remove_commands
,
422 &config
->remove_commands
);
428 static bool conf_files_filter_out(struct kmod_ctx
*ctx
, DIR *d
,
429 const char *path
, const char *fn
)
431 size_t len
= strlen(fn
);
437 if (len
< 6 || (!streq(&fn
[len
- 5], ".conf")
438 && !streq(&fn
[len
- 6], ".alias"))) {
439 INFO(ctx
, "All config files need .conf: %s/%s, "
440 "it will be ignored in a future release\n",
445 fstatat(dirfd(d
), fn
, &st
, 0);
447 if (S_ISDIR(st
.st_mode
)) {
448 ERR(ctx
, "Directories inside directories are not supported: "
449 "%s/%s\n", path
, fn
);
457 * Iterate over a directory (given by @path) and save the list of
458 * configuration files in @list.
460 static DIR *conf_files_list(struct kmod_ctx
*ctx
, struct kmod_list
**list
,
475 struct dirent ent
, *entp
;
476 struct kmod_list
*l
, *tmp
;
479 err
= readdir_r(d
, &ent
, &entp
);
481 ERR(ctx
, "reading entry %s\n", strerror(-err
));
488 if (conf_files_filter_out(ctx
, d
, path
, entp
->d_name
))
492 kmod_list_foreach(l
, *list
) {
493 if (strcmp(entp
->d_name
, l
->data
) < 0)
497 dname
= strdup(entp
->d_name
);
502 tmp
= kmod_list_append(*list
, dname
);
504 tmp
= kmod_list_prepend(*list
, dname
);
506 tmp
= kmod_list_insert_before(l
, dname
);
511 if (l
== NULL
|| l
== *list
)
518 ERR(ctx
, "out of memory while scanning '%s'\n", path
);
520 for (; *list
!= NULL
; *list
= kmod_list_remove(*list
))
526 int kmod_config_new(struct kmod_ctx
*ctx
, struct kmod_config
**p_config
,
527 const char * const *config_paths
)
529 struct kmod_config
*config
;
532 *p_config
= config
= calloc(1, sizeof(struct kmod_config
));
538 for (i
= 0; config_paths
[i
] != NULL
; i
++) {
539 const char *path
= config_paths
[i
];
540 struct kmod_list
*list
;
544 if (stat(path
, &st
) != 0) {
545 DBG(ctx
, "could not load '%s': %s\n",
546 path
, strerror(errno
));
550 if (S_ISREG(st
.st_mode
)) {
551 int fd
= open(path
, O_RDONLY
);
552 DBG(ctx
, "parsing file '%s': %d\n", path
, fd
);
554 kmod_config_parse(config
, fd
, path
);
556 } else if (!S_ISDIR(st
.st_mode
)) {
557 ERR(ctx
, "unsupported file mode %s: %#x\n",
562 d
= conf_files_list(ctx
, &list
, path
);
564 for (; list
!= NULL
; list
= kmod_list_remove(list
)) {
565 int fd
= openat(dirfd(d
), list
->data
, O_RDONLY
);
566 DBG(ctx
, "parsing file '%s/%s': %d\n", path
,
567 (const char *) list
->data
, fd
);
569 kmod_config_parse(config
, fd
, list
->data
);
577 kmod_config_parse_kcmdline(config
);