]> git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod-config.c
66d837248a36c87697ccebf93cd591e961fa2246
[thirdparty/kmod.git] / libkmod / libkmod-config.c
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
35 static const char *config_files[] = {
36 "/run/modprobe.d",
37 "/etc/modprobe.d",
38 "/lib/modprobe.d",
39 };
40
41 struct kmod_alias {
42 char *name;
43 char *modname;
44 };
45
46 const char *kmod_alias_get_name(const struct kmod_list *l) {
47 struct kmod_alias *alias = l->data;
48 return alias->name;
49 }
50
51 const char *kmod_alias_get_modname(const struct kmod_list *l) {
52 struct kmod_alias *alias = l->data;
53 return alias->modname;
54 }
55
56 static struct kmod_list *add_alias(struct kmod_ctx *ctx,
57 struct kmod_list *aliases,
58 const char *name, const char *modname)
59 {
60 struct kmod_alias *alias;
61
62 DBG(ctx, "name=%s modname=%s\n", name, modname);
63
64 alias = malloc(sizeof(*alias));
65 alias->name = strdup(name);
66 alias->modname = strdup(modname);
67
68 return kmod_list_append(aliases, alias);
69 }
70
71 static struct kmod_list *free_alias(struct kmod_ctx *ctx, struct kmod_list *l)
72 {
73 struct kmod_alias *alias = l->data;
74
75 free(alias->modname);
76 free(alias->name);
77 free(alias);
78
79 return kmod_list_remove(l);
80 }
81
82 static struct kmod_list *add_blacklist(struct kmod_ctx *ctx,
83 struct kmod_list *blacklist,
84 const char *modname)
85 {
86 char *p;
87
88 DBG(ctx, "modname=%s\n", modname);
89
90 p = strdup(modname);
91
92 return kmod_list_append(blacklist, p);
93 }
94
95 static struct kmod_list *free_blacklist(struct kmod_ctx *ctx,
96 struct kmod_list *l)
97 {
98 free(l->data);
99 return kmod_list_remove(l);
100 }
101
102
103 int kmod_parse_config_file(struct kmod_ctx *ctx, const char *filename,
104 struct kmod_config *config)
105 {
106 char *line;
107 FILE *fp;
108 unsigned int linenum;
109
110 DBG(ctx, "%s\n", filename);
111
112 fp = fopen(filename, "r");
113 if (fp == NULL)
114 return errno;
115
116 while ((line = getline_wrapped(fp, &linenum)) != NULL) {
117 char *cmd, *saveptr;
118
119 if (line[0] == '\0' || line[0] == '#')
120 goto done_next;
121
122 cmd = strtok_r(line, "\t ", &saveptr);
123 if (cmd == NULL)
124 goto done_next;
125
126 if (!strcmp(cmd, "alias")) {
127 char *alias = strtok_r(NULL, "\t ", &saveptr);
128 char *modname = strtok_r(NULL, "\t ", &saveptr);
129
130 if (alias == NULL || modname == NULL)
131 goto syntax_error;
132
133 config->aliases = add_alias(ctx, config->aliases,
134 underscores(ctx, alias),
135 underscores(ctx, modname));
136 } else if (!strcmp(cmd, "blacklist")) {
137 char *modname = strtok_r(NULL, "\t ", &saveptr);
138
139 if (modname == NULL)
140 goto syntax_error;
141
142 config->blacklists = add_blacklist(ctx,
143 config->blacklists,
144 underscores(ctx, modname));
145 } else if (!strcmp(cmd, "include") || !strcmp(cmd, "options")
146 || !strcmp(cmd, "install")
147 || !strcmp(cmd, "remove")
148 || !strcmp(cmd, "softdep")
149 || !strcmp(cmd, "config")) {
150 INFO(ctx, "%s: command %s not implemented yet\n",
151 filename, cmd);
152 } else {
153 syntax_error:
154 ERR(ctx, "%s line %u: ignoring bad line starting with '%s'\n",
155 filename, linenum, cmd);
156 }
157
158 done_next:
159 free(line);
160 }
161
162 fclose(fp);
163
164 return 0;
165 }
166
167 void kmod_free_config(struct kmod_ctx *ctx, struct kmod_config *config)
168 {
169 while (config->aliases)
170 config->aliases = free_alias(ctx, config->aliases);
171
172 while (config->blacklists)
173 config->blacklists = free_blacklist(ctx, config->blacklists);
174 }
175
176 static bool conf_files_filter(struct kmod_ctx *ctx, const char *path,
177 const char *fn)
178 {
179 size_t len = strlen(fn);
180
181 if (fn[0] == '.')
182 return 1;
183
184 if (len < 6 || (strcmp(&fn[len - 5], ".conf") != 0
185 && strcmp(&fn[len - 6], ".alias"))) {
186 INFO(ctx, "All config files need .conf: %s/%s, "
187 "it will be ignored in a future release\n",
188 path, fn);
189 return 1;
190 }
191
192 return 0;
193 }
194
195 static int conf_files_list(struct kmod_ctx *ctx, struct kmod_list **list,
196 const char *path, size_t *n)
197 {
198 struct stat st;
199 DIR *d;
200 int err;
201
202 if (stat(path, &st) < 0)
203 return -ENOENT;
204
205 if (!S_ISDIR(st.st_mode)) {
206 *list = kmod_list_append(*list, (void *)path);
207 *n += 1;
208 return 0;
209 }
210
211 d = opendir(path);
212 if (d == NULL) {
213 err = errno;
214 ERR(ctx, "%m\n");
215 return -errno;
216 }
217
218 for (;;) {
219 struct dirent ent, *entp;
220 char *p;
221
222 err = readdir_r(d, &ent, &entp);
223 if (err != 0) {
224 err = -err;
225 goto finish;
226 }
227
228 if (entp == NULL)
229 break;
230
231 if (conf_files_filter(ctx, path, entp->d_name) == 1)
232 continue;
233
234 if (asprintf(&p, "%s/%s", path, entp->d_name) < 0) {
235 err = -ENOMEM;
236 goto finish;
237 }
238
239 DBG(ctx, "%s\n", p);
240
241 *list = kmod_list_append(*list, p);
242 *n += 1;
243 }
244
245 finish:
246 closedir(d);
247 return err;
248 }
249
250 static int base_cmp(const void *a, const void *b)
251 {
252 const char *s1, *s2;
253
254 s1 = *(char * const *)a;
255 s2 = *(char * const *)b;
256
257 return strcmp(basename(s1), basename(s2));
258 }
259
260 int kmod_parse_config(struct kmod_ctx *ctx, struct kmod_config *config)
261 {
262
263 size_t i, n = 0;
264 char **files = NULL;
265 int err = 0;
266 struct kmod_list *list = NULL, *l;
267
268 for (i = 0; i < ARRAY_SIZE(config_files); i++)
269 conf_files_list(ctx, &list, config_files[i], &n);
270
271 files = malloc(sizeof(char *) * n);
272 if (files == NULL) {
273 err = -ENOMEM;
274 goto finish;
275 }
276
277 i = 0;
278 kmod_list_foreach(l, list) {
279 files[i] = l->data;
280 i++;
281 }
282
283 qsort(files, n, sizeof(char *), base_cmp);
284
285 for (i = 0; i < n; i++)
286 kmod_parse_config_file(ctx, files[i], config);
287
288 finish:
289 free(files);
290
291 while (list) {
292 free(list->data);
293 list = kmod_list_remove(list);
294 }
295
296 return err;
297 }