]> git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod-module.c
improve "const" keyword usage.
[thirdparty/kmod.git] / libkmod / libkmod-module.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 <assert.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stddef.h>
24 #include <stdarg.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <inttypes.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <sys/mman.h>
33 #include <string.h>
34
35 #include "libkmod.h"
36 #include "libkmod-private.h"
37
38 /**
39 * kmod_module:
40 *
41 * Opaque object representing a module.
42 */
43 struct kmod_module {
44 struct kmod_ctx *ctx;
45 int refcount;
46 const char *path;
47 const char *name;
48 struct kmod_list *dep;
49
50 struct {
51 bool dep : 1;
52 } init;
53 };
54
55 static char *path_to_modname(const char *path, bool alloc)
56 {
57 char *modname;
58 char *c;
59
60 modname = basename(path);
61 if (modname == NULL || modname[0] == '\0')
62 return NULL;
63
64 if (alloc)
65 modname = strdup(modname);
66
67 for (c = modname; *c != '\0' && *c != '.'; c++) {
68 if (*c == '-')
69 *c = '_';
70 }
71
72 *c = '\0';
73 return modname;
74 }
75
76 static const char *get_modname(struct kmod_module *mod)
77 {
78 if (mod->name == NULL)
79 mod->name = path_to_modname(mod->path, true);
80
81 return mod->name;
82 }
83
84 int kmod_module_parse_dep(struct kmod_module *mod, char *line)
85 {
86 struct kmod_ctx *ctx = mod->ctx;
87 struct kmod_list *list = NULL;
88 char *p, *saveptr;
89 int err, n = 0;
90
91 assert(!mod->init.dep && mod->dep == NULL);
92 mod->init.dep = true;
93
94 p = strchr(line, ':');
95 if (p == NULL)
96 return 0;
97
98 p++;
99
100 for (p = strtok_r(p, " \t", &saveptr); p != NULL;
101 p = strtok_r(NULL, " \t", &saveptr)) {
102 const char *modname = path_to_modname(p, false);
103 struct kmod_module *depmod;
104
105 err = kmod_module_new_from_name(ctx, modname, &depmod);
106 if (err < 0) {
107 ERR(ctx, "ctx=%p modname=%s error=%s\n",
108 ctx, modname, strerror(-err));
109 goto fail;
110 }
111
112 DBG(ctx, "add dep: %s\n", modname);
113
114 list = kmod_list_append(list, depmod);
115 n++;
116 }
117
118 DBG(ctx, "%d dependencies for %s\n", n, mod->name);
119
120 mod->dep = list;
121 return n;
122
123 fail:
124 kmod_module_unref_list(list);
125 mod->init.dep = false;
126 return err;
127 }
128
129 KMOD_EXPORT int kmod_module_new_from_name(struct kmod_ctx *ctx,
130 const char *name,
131 struct kmod_module **mod)
132 {
133 struct kmod_module *m;
134
135 if (ctx == NULL || name == NULL)
136 return -ENOENT;
137
138 m = calloc(1, sizeof(*m));
139 if (m == NULL) {
140 free(m);
141 return -ENOMEM;
142 }
143
144 m->ctx = kmod_ref(ctx);
145 m->name = strdup(name);
146
147 *mod = m;
148
149 return 0;
150 }
151
152 KMOD_EXPORT int kmod_module_new_from_path(struct kmod_ctx *ctx,
153 const char *path,
154 struct kmod_module **mod)
155 {
156 struct kmod_module *m;
157 int err;
158 struct stat st;
159
160 if (ctx == NULL || path == NULL)
161 return -ENOENT;
162
163 err = stat(path, &st);
164 if (err < 0)
165 return -errno;
166
167 m = calloc(1, sizeof(*m));
168 if (m == NULL) {
169 free(m);
170 return -ENOMEM;
171 }
172
173 m->ctx = kmod_ref(ctx);
174 m->path = strdup(path);
175
176 *mod = m;
177
178 return 0;
179 }
180
181 KMOD_EXPORT struct kmod_module *kmod_module_unref(struct kmod_module *mod)
182 {
183 if (mod == NULL)
184 return NULL;
185
186 if (--mod->refcount > 0)
187 return mod;
188
189 DBG(mod->ctx, "kmod_module %p released\n", mod);
190
191 kmod_module_unref_list(mod->dep);
192 kmod_unref(mod->ctx);
193 free((char *) mod->path);
194 free((char *) mod->name);
195 free(mod);
196 return NULL;
197 }
198
199 KMOD_EXPORT struct kmod_module *kmod_module_ref(struct kmod_module *mod)
200 {
201 if (mod == NULL)
202 return NULL;
203
204 mod->refcount++;
205
206 return mod;
207 }
208
209 #define CHECK_ERR_AND_FINISH(_err, _label_err, _list, label_finish) \
210 do { \
211 if ((_err) < 0) \
212 goto _label_err; \
213 if (*(_list) != NULL) \
214 goto finish; \
215 } while (0)
216
217 KMOD_EXPORT int kmod_module_new_from_lookup(struct kmod_ctx *ctx,
218 const char *alias,
219 struct kmod_list **list)
220 {
221 int err;
222
223 if (ctx == NULL || alias == NULL)
224 return -ENOENT;
225
226 if (list == NULL || *list != NULL) {
227 ERR(ctx, "An empty list is needed to create lookup\n");
228 return -ENOSYS;
229 }
230
231 /* Aliases from config file override all the others */
232 err = kmod_lookup_alias_from_config(ctx, alias, list);
233 CHECK_ERR_AND_FINISH(err, fail, list, finish);
234
235 err = kmod_lookup_alias_from_moddep_file(ctx, alias, list);
236 CHECK_ERR_AND_FINISH(err, fail, list, finish);
237
238 err = kmod_lookup_alias_from_symbols_file(ctx, alias, list);
239 CHECK_ERR_AND_FINISH(err, fail, list, finish);
240
241 err = kmod_lookup_alias_from_aliases_file(ctx, alias, list);
242 CHECK_ERR_AND_FINISH(err, fail, list, finish);
243
244 finish:
245
246 return err;
247 fail:
248 kmod_module_unref_list(*list);
249 *list = NULL;
250 return err;
251 }
252 #undef CHECK_ERR_AND_FINISH
253
254
255 KMOD_EXPORT int kmod_module_unref_list(struct kmod_list *list)
256 {
257 for (; list != NULL; list = kmod_list_remove(list))
258 kmod_module_unref(list->data);
259
260 return 0;
261 }
262
263 /*
264 * We don't increase the refcount. Maybe we should.
265 */
266 KMOD_EXPORT struct kmod_list *kmod_module_get_dependency(const struct kmod_module *mod)
267 {
268 // FIXME calculate dependency if it's not initialized
269 return mod->dep;
270 }
271
272 KMOD_EXPORT struct kmod_module *kmod_module_get_module(const struct kmod_list *l)
273 {
274 struct kmod_module *mod = l->data;
275 return kmod_module_ref(mod);
276 }
277
278 KMOD_EXPORT const char *kmod_module_get_name(const struct kmod_module *mod)
279 {
280 // FIXME calculate name if name == NULL
281 return mod->name;
282 }
283
284 KMOD_EXPORT const char *kmod_module_get_path(const struct kmod_module *mod)
285 {
286 // FIXME calculate path if path == NULL
287 return mod->path;
288 }
289
290
291 extern long delete_module(const char *name, unsigned int flags);
292
293 KMOD_EXPORT int kmod_module_remove_module(struct kmod_module *mod,
294 unsigned int flags)
295 {
296 int err;
297 const char *modname;
298
299 if (mod == NULL)
300 return -ENOENT;
301
302 /* Filter out other flags */
303 flags &= (KMOD_REMOVE_FORCE | KMOD_REMOVE_NOWAIT);
304
305 modname = get_modname(mod);
306 err = delete_module(modname, flags);
307 if (err != 0) {
308 ERR(mod->ctx, "Removing '%s': %s\n", modname,
309 strerror(-err));
310 return err;
311 }
312
313 return 0;
314 }
315
316 extern long init_module(void *mem, unsigned long len, const char *args);
317
318 KMOD_EXPORT int kmod_module_insert_module(struct kmod_module *mod,
319 unsigned int flags)
320 {
321 int err;
322 void *mmaped_file;
323 struct stat st;
324 int fd;
325 const char *args = "";
326
327 if (mod == NULL)
328 return -ENOENT;
329
330 if (mod->path == NULL) {
331 ERR(mod->ctx, "Not supported to load a module by name yet\n");
332 return -ENOSYS;
333 }
334
335 if (flags != 0)
336 INFO(mod->ctx, "Flags are not implemented yet\n");
337
338 if ((fd = open(mod->path, O_RDONLY)) < 0) {
339 err = -errno;
340 return err;
341 }
342
343 fstat(fd, &st);
344
345 if ((mmaped_file = mmap(0, st.st_size, PROT_READ,
346 MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
347 close(fd);
348 return -errno;
349 }
350
351 err = init_module(mmaped_file, st.st_size, args);
352 if (err < 0)
353 ERR(mod->ctx, "Failed to insert module '%s'\n", mod->path);
354
355 munmap(mmaped_file, st.st_size);
356 close(fd);
357
358 return err;
359 }