]> git.ipfire.org Git - thirdparty/kmod.git/blame - libkmod/libkmod-config.c
kmod_list: remove nodes in order
[thirdparty/kmod.git] / libkmod / libkmod-config.c
CommitLineData
7c2ab358
LDM
1/*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011 ProFUSION embedded systems
5 *
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 version 2.1.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <stddef.h>
23#include <stdarg.h>
24#include <unistd.h>
25#include <errno.h>
26#include <string.h>
27#include <ctype.h>
28#include <sys/stat.h>
29#include <sys/types.h>
30#include <dirent.h>
31
32#include "libkmod.h"
33#include "libkmod-private.h"
34
35static const char *config_files[] = {
36 "/run/modprobe.d",
37 "/etc/modprobe.d",
7c2ab358
LDM
38 "/lib/modprobe.d",
39};
40
41struct kmod_alias {
42 char *name;
43c29d10 43 char modname[];
7c2ab358
LDM
44};
45
b0ef19f7 46const char *kmod_alias_get_name(const struct kmod_list *l) {
1ce08a56 47 const struct kmod_alias *alias = l->data;
b0ef19f7
LDM
48 return alias->name;
49}
50
51const char *kmod_alias_get_modname(const struct kmod_list *l) {
1ce08a56 52 const struct kmod_alias *alias = l->data;
b0ef19f7
LDM
53 return alias->modname;
54}
55
d13e606f
GSB
56static int kmod_config_add_alias(struct kmod_config *config,
57 const char *name, const char *modname)
7c2ab358
LDM
58{
59 struct kmod_alias *alias;
d13e606f 60 struct kmod_list *list;
43c29d10 61 size_t namelen = strlen(name) + 1, modnamelen = strlen(modname) + 1;
7c2ab358 62
d13e606f 63 DBG(config->ctx, "name=%s modname=%s\n", name, modname);
7c2ab358 64
43c29d10 65 alias = malloc(sizeof(*alias) + namelen + modnamelen);
d13e606f
GSB
66 if (!alias)
67 goto oom_error_init;
43c29d10
GSB
68 alias->name = sizeof(*alias) + modnamelen + (char *)alias;
69
70 memcpy(alias->modname, modname, modnamelen);
71 memcpy(alias->name, name, namelen);
7c2ab358 72
d13e606f
GSB
73 list = kmod_list_append(config->aliases, alias);
74 if (!list)
75 goto oom_error;
76 config->aliases = list;
77 return 0;
78
79oom_error:
d13e606f
GSB
80 free(alias);
81oom_error_init:
82 ERR(config->ctx, "out-of-memory name=%s modname=%s\n", name, modname);
83 return -ENOMEM;
7c2ab358
LDM
84}
85
d13e606f 86static void kmod_config_free_alias(struct kmod_config *config, struct kmod_list *l)
7c2ab358
LDM
87{
88 struct kmod_alias *alias = l->data;
89
7c2ab358
LDM
90 free(alias);
91
d13e606f 92 config->aliases = kmod_list_remove(l);
7c2ab358
LDM
93}
94
d13e606f 95static int kmod_config_add_blacklist(struct kmod_config *config,
81cf2060
LDM
96 const char *modname)
97{
81cf2060 98 char *p;
d13e606f 99 struct kmod_list *list;
81cf2060 100
d13e606f 101 DBG(config->ctx, "modname=%s\n", modname);
81cf2060
LDM
102
103 p = strdup(modname);
d13e606f
GSB
104 if (!p)
105 goto oom_error_init;
106
107 list = kmod_list_append(config->blacklists, p);
108 if (!list)
109 goto oom_error;
110 config->blacklists = list;
111 return 0;
81cf2060 112
d13e606f
GSB
113oom_error:
114 free(p);
115oom_error_init:
116 ERR(config->ctx, "out-of-memory modname=%s\n", modname);
117 return -ENOMEM;
81cf2060
LDM
118}
119
d13e606f 120static void kmod_config_free_blacklist(struct kmod_config *config,
81cf2060
LDM
121 struct kmod_list *l)
122{
123 free(l->data);
d13e606f 124 config->blacklists = kmod_list_remove(l);
81cf2060
LDM
125}
126
d13e606f 127static int kmod_config_parse(struct kmod_config *config, const char *filename)
7c2ab358 128{
d13e606f 129 struct kmod_ctx *ctx = config->ctx;
7c2ab358
LDM
130 char *line;
131 FILE *fp;
132 unsigned int linenum;
133
134 DBG(ctx, "%s\n", filename);
135
136 fp = fopen(filename, "r");
137 if (fp == NULL)
138 return errno;
139
140 while ((line = getline_wrapped(fp, &linenum)) != NULL) {
c11e62bf 141 char *cmd, *saveptr;
7c2ab358
LDM
142
143 if (line[0] == '\0' || line[0] == '#')
144 goto done_next;
145
c11e62bf 146 cmd = strtok_r(line, "\t ", &saveptr);
7c2ab358
LDM
147 if (cmd == NULL)
148 goto done_next;
149
150 if (!strcmp(cmd, "alias")) {
c11e62bf
LDM
151 char *alias = strtok_r(NULL, "\t ", &saveptr);
152 char *modname = strtok_r(NULL, "\t ", &saveptr);
7c2ab358
LDM
153
154 if (alias == NULL || modname == NULL)
155 goto syntax_error;
156
d13e606f 157 kmod_config_add_alias(config,
30be7513
LDM
158 underscores(ctx, alias),
159 underscores(ctx, modname));
81cf2060 160 } else if (!strcmp(cmd, "blacklist")) {
c11e62bf 161 char *modname = strtok_r(NULL, "\t ", &saveptr);
81cf2060
LDM
162
163 if (modname == NULL)
164 goto syntax_error;
165
d13e606f 166 kmod_config_add_blacklist(config,
2295acc5 167 underscores(ctx, modname));
7c2ab358
LDM
168 } else if (!strcmp(cmd, "include") || !strcmp(cmd, "options")
169 || !strcmp(cmd, "install")
7c2ab358
LDM
170 || !strcmp(cmd, "remove")
171 || !strcmp(cmd, "softdep")
172 || !strcmp(cmd, "config")) {
81cf2060
LDM
173 INFO(ctx, "%s: command %s not implemented yet\n",
174 filename, cmd);
7c2ab358
LDM
175 } else {
176syntax_error:
177 ERR(ctx, "%s line %u: ignoring bad line starting with '%s'\n",
178 filename, linenum, cmd);
179 }
180
181done_next:
182 free(line);
183 }
184
185 fclose(fp);
186
187 return 0;
188}
189
d13e606f 190void kmod_config_free(struct kmod_config *config)
7c2ab358
LDM
191{
192 while (config->aliases)
d13e606f 193 kmod_config_free_alias(config, config->aliases);
81cf2060
LDM
194
195 while (config->blacklists)
d13e606f
GSB
196 kmod_config_free_blacklist(config, config->blacklists);
197
198 free(config);
7c2ab358
LDM
199}
200
201static bool conf_files_filter(struct kmod_ctx *ctx, const char *path,
202 const char *fn)
203{
204 size_t len = strlen(fn);
205
206 if (fn[0] == '.')
207 return 1;
208
209 if (len < 6 || (strcmp(&fn[len - 5], ".conf") != 0
210 && strcmp(&fn[len - 6], ".alias"))) {
211 INFO(ctx, "All config files need .conf: %s/%s, "
212 "it will be ignored in a future release\n",
213 path, fn);
214 return 1;
215 }
216
217 return 0;
218}
219
220static int conf_files_list(struct kmod_ctx *ctx, struct kmod_list **list,
221 const char *path, size_t *n)
222{
223 struct stat st;
224 DIR *d;
225 int err;
226
227 if (stat(path, &st) < 0)
228 return -ENOENT;
229
230 if (!S_ISDIR(st.st_mode)) {
231 *list = kmod_list_append(*list, (void *)path);
232 *n += 1;
233 return 0;
234 }
235
236 d = opendir(path);
237 if (d == NULL) {
238 err = errno;
239 ERR(ctx, "%m\n");
240 return -errno;
241 }
242
243 for (;;) {
244 struct dirent ent, *entp;
245 char *p;
246
247 err = readdir_r(d, &ent, &entp);
248 if (err != 0) {
249 err = -err;
250 goto finish;
251 }
252
253 if (entp == NULL)
254 break;
255
256 if (conf_files_filter(ctx, path, entp->d_name) == 1)
257 continue;
258
259 if (asprintf(&p, "%s/%s", path, entp->d_name) < 0) {
260 err = -ENOMEM;
261 goto finish;
262 }
263
264 DBG(ctx, "%s\n", p);
265
266 *list = kmod_list_append(*list, p);
267 *n += 1;
268 }
269
270finish:
271 closedir(d);
272 return err;
273}
274
275static int base_cmp(const void *a, const void *b)
276{
277 const char *s1, *s2;
278
279 s1 = *(char * const *)a;
280 s2 = *(char * const *)b;
281
282 return strcmp(basename(s1), basename(s2));
283}
284
d13e606f 285int kmod_config_new(struct kmod_ctx *ctx, struct kmod_config **p_config)
7c2ab358 286{
d13e606f 287 struct kmod_config *config;
7c2ab358 288 size_t i, n = 0;
1ce08a56 289 const char **files;
7c2ab358
LDM
290 int err = 0;
291 struct kmod_list *list = NULL, *l;
292
d13e606f 293 *p_config = config = calloc(1, sizeof(struct kmod_config));
2295acc5 294 if (config == NULL)
d13e606f 295 return -ENOMEM;
2295acc5 296
d13e606f
GSB
297 config->ctx = ctx;
298
7c2ab358
LDM
299 for (i = 0; i < ARRAY_SIZE(config_files); i++)
300 conf_files_list(ctx, &list, config_files[i], &n);
301
302 files = malloc(sizeof(char *) * n);
303 if (files == NULL) {
304 err = -ENOMEM;
305 goto finish;
306 }
307
308 i = 0;
309 kmod_list_foreach(l, list) {
310 files[i] = l->data;
311 i++;
312 }
313
314 qsort(files, n, sizeof(char *), base_cmp);
315
316 for (i = 0; i < n; i++)
d13e606f 317 kmod_config_parse(config, files[i]);
7c2ab358
LDM
318
319finish:
320 free(files);
321
322 while (list) {
323 free(list->data);
324 list = kmod_list_remove(list);
325 }
326
327 return err;
328}