blob: 8bc644f71110b9aefbc3b48db5f2451184e55504 [file] [log] [blame]
Lucas De Marchi8f788d52011-11-25 01:22:56 -02001/*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011 ProFUSION embedded systems
Lucas De Marchi8f788d52011-11-25 01:22:56 -02005 *
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
Lucas De Marchi7636e722011-12-01 17:56:03 -020020#include <assert.h>
Lucas De Marchi8f788d52011-11-25 01:22:56 -020021#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 */
43struct kmod_module {
44 struct kmod_ctx *ctx;
Lucas De Marchi8f788d52011-11-25 01:22:56 -020045 const char *path;
46 const char *name;
Lucas De Marchi7636e722011-12-01 17:56:03 -020047 struct kmod_list *dep;
Gustavo Sverzut Barbieri8d3f3ef2011-12-02 21:10:24 -020048 int refcount;
Lucas De Marchi7636e722011-12-01 17:56:03 -020049 struct {
50 bool dep : 1;
51 } init;
Lucas De Marchi8f788d52011-11-25 01:22:56 -020052};
53
Lucas De Marchi9eaad1f2011-12-01 17:18:24 -020054static char *path_to_modname(const char *path, bool alloc)
Lucas De Marchi8f788d52011-11-25 01:22:56 -020055{
56 char *modname;
57 char *c;
58
59 modname = basename(path);
60 if (modname == NULL || modname[0] == '\0')
61 return NULL;
62
Lucas De Marchi9eaad1f2011-12-01 17:18:24 -020063 if (alloc)
64 modname = strdup(modname);
65
Lucas De Marchi8f788d52011-11-25 01:22:56 -020066 for (c = modname; *c != '\0' && *c != '.'; c++) {
67 if (*c == '-')
68 *c = '_';
69 }
70
71 *c = '\0';
72 return modname;
73}
74
75static const char *get_modname(struct kmod_module *mod)
76{
77 if (mod->name == NULL)
Lucas De Marchi9eaad1f2011-12-01 17:18:24 -020078 mod->name = path_to_modname(mod->path, true);
Lucas De Marchi8f788d52011-11-25 01:22:56 -020079
80 return mod->name;
81}
82
Lucas De Marchi7636e722011-12-01 17:56:03 -020083int kmod_module_parse_dep(struct kmod_module *mod, char *line)
84{
85 struct kmod_ctx *ctx = mod->ctx;
86 struct kmod_list *list = NULL;
87 char *p, *saveptr;
88 int err, n = 0;
89
90 assert(!mod->init.dep && mod->dep == NULL);
91 mod->init.dep = true;
92
93 p = strchr(line, ':');
94 if (p == NULL)
95 return 0;
96
97 p++;
98
99 for (p = strtok_r(p, " \t", &saveptr); p != NULL;
100 p = strtok_r(NULL, " \t", &saveptr)) {
101 const char *modname = path_to_modname(p, false);
Lucas De Marchi1fc1c9a2011-12-02 10:00:03 -0200102 struct kmod_module *depmod;
Lucas De Marchi7636e722011-12-01 17:56:03 -0200103
Lucas De Marchi1fc1c9a2011-12-02 10:00:03 -0200104 err = kmod_module_new_from_name(ctx, modname, &depmod);
Lucas De Marchi7636e722011-12-01 17:56:03 -0200105 if (err < 0) {
106 ERR(ctx, "ctx=%p modname=%s error=%s\n",
107 ctx, modname, strerror(-err));
108 goto fail;
109 }
110
111 DBG(ctx, "add dep: %s\n", modname);
112
Lucas De Marchi1fc1c9a2011-12-02 10:00:03 -0200113 list = kmod_list_append(list, depmod);
Lucas De Marchi7636e722011-12-01 17:56:03 -0200114 n++;
115 }
116
117 DBG(ctx, "%d dependencies for %s\n", n, mod->name);
118
119 mod->dep = list;
120 return n;
121
122fail:
123 kmod_module_unref_list(list);
124 mod->init.dep = false;
125 return err;
126}
127
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200128KMOD_EXPORT int kmod_module_new_from_name(struct kmod_ctx *ctx,
129 const char *name,
130 struct kmod_module **mod)
131{
132 struct kmod_module *m;
133
134 if (ctx == NULL || name == NULL)
135 return -ENOENT;
136
137 m = calloc(1, sizeof(*m));
138 if (m == NULL) {
139 free(m);
140 return -ENOMEM;
141 }
142
143 m->ctx = kmod_ref(ctx);
144 m->name = strdup(name);
Gustavo Sverzut Barbieri87ca03b2011-12-04 12:34:02 -0200145 m->refcount = 1;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200146
147 *mod = m;
148
149 return 0;
150}
151
152KMOD_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);
Gustavo Sverzut Barbieri87ca03b2011-12-04 12:34:02 -0200175 m->refcount = 1;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200176
177 *mod = m;
178
179 return 0;
180}
181
182KMOD_EXPORT struct kmod_module *kmod_module_unref(struct kmod_module *mod)
183{
184 if (mod == NULL)
185 return NULL;
186
187 if (--mod->refcount > 0)
188 return mod;
189
190 DBG(mod->ctx, "kmod_module %p released\n", mod);
191
Lucas De Marchi7636e722011-12-01 17:56:03 -0200192 kmod_module_unref_list(mod->dep);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200193 kmod_unref(mod->ctx);
194 free((char *) mod->path);
195 free((char *) mod->name);
196 free(mod);
197 return NULL;
198}
199
200KMOD_EXPORT struct kmod_module *kmod_module_ref(struct kmod_module *mod)
201{
202 if (mod == NULL)
203 return NULL;
204
205 mod->refcount++;
206
207 return mod;
208}
209
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200210#define CHECK_ERR_AND_FINISH(_err, _label_err, _list, label_finish) \
211 do { \
212 if ((_err) < 0) \
213 goto _label_err; \
214 if (*(_list) != NULL) \
215 goto finish; \
216 } while (0)
217
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200218KMOD_EXPORT int kmod_module_new_from_lookup(struct kmod_ctx *ctx,
219 const char *alias,
220 struct kmod_list **list)
221{
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200222 int err;
223
224 if (ctx == NULL || alias == NULL)
225 return -ENOENT;
226
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200227 if (list == NULL || *list != NULL) {
228 ERR(ctx, "An empty list is needed to create lookup\n");
229 return -ENOSYS;
230 }
231
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200232 /* Aliases from config file override all the others */
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200233 err = kmod_lookup_alias_from_config(ctx, alias, list);
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200234 CHECK_ERR_AND_FINISH(err, fail, list, finish);
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200235
Lucas De Marchi64700e42011-12-01 15:57:53 -0200236 err = kmod_lookup_alias_from_moddep_file(ctx, alias, list);
237 CHECK_ERR_AND_FINISH(err, fail, list, finish);
238
Lucas De Marchi9ba6f572011-11-30 20:31:45 -0200239 err = kmod_lookup_alias_from_symbols_file(ctx, alias, list);
240 CHECK_ERR_AND_FINISH(err, fail, list, finish);
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200241
Lucas De Marchi49e61ca2011-12-01 16:27:04 -0200242 err = kmod_lookup_alias_from_aliases_file(ctx, alias, list);
243 CHECK_ERR_AND_FINISH(err, fail, list, finish);
244
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200245finish:
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200246
247 return err;
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200248fail:
249 kmod_module_unref_list(*list);
250 *list = NULL;
Lucas De Marchi84f42202011-12-02 10:03:34 -0200251 return err;
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200252}
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200253#undef CHECK_ERR_AND_FINISH
254
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200255
256KMOD_EXPORT int kmod_module_unref_list(struct kmod_list *list)
257{
258 for (; list != NULL; list = kmod_list_remove(list))
259 kmod_module_unref(list->data);
260
261 return 0;
262}
263
Lucas De Marchi0835fc32011-12-01 20:06:08 -0200264/*
265 * We don't increase the refcount. Maybe we should.
266 */
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200267KMOD_EXPORT struct kmod_list *kmod_module_get_dependency(const struct kmod_module *mod)
Lucas De Marchi0835fc32011-12-01 20:06:08 -0200268{
269 // FIXME calculate dependency if it's not initialized
270 return mod->dep;
271}
272
Gustavo Sverzut Barbieriad4d1ae2011-12-04 13:14:11 -0200273KMOD_EXPORT struct kmod_module *kmod_module_get_module(const struct kmod_list *entry)
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200274{
Gustavo Sverzut Barbieriad4d1ae2011-12-04 13:14:11 -0200275 if (entry == NULL)
276 return NULL;
277 return kmod_module_ref(entry->data);
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200278}
279
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200280KMOD_EXPORT const char *kmod_module_get_name(const struct kmod_module *mod)
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200281{
282 // FIXME calculate name if name == NULL
283 return mod->name;
284}
285
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200286KMOD_EXPORT const char *kmod_module_get_path(const struct kmod_module *mod)
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200287{
288 // FIXME calculate path if path == NULL
289 return mod->path;
290}
291
292
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200293extern long delete_module(const char *name, unsigned int flags);
294
295KMOD_EXPORT int kmod_module_remove_module(struct kmod_module *mod,
296 unsigned int flags)
297{
298 int err;
299 const char *modname;
300
301 if (mod == NULL)
302 return -ENOENT;
303
304 /* Filter out other flags */
305 flags &= (KMOD_REMOVE_FORCE | KMOD_REMOVE_NOWAIT);
306
307 modname = get_modname(mod);
308 err = delete_module(modname, flags);
309 if (err != 0) {
310 ERR(mod->ctx, "Removing '%s': %s\n", modname,
311 strerror(-err));
312 return err;
313 }
314
315 return 0;
316}
317
318extern long init_module(void *mem, unsigned long len, const char *args);
319
320KMOD_EXPORT int kmod_module_insert_module(struct kmod_module *mod,
321 unsigned int flags)
322{
323 int err;
324 void *mmaped_file;
325 struct stat st;
326 int fd;
327 const char *args = "";
328
329 if (mod == NULL)
330 return -ENOENT;
331
332 if (mod->path == NULL) {
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200333 ERR(mod->ctx, "Not supported to load a module by name yet\n");
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200334 return -ENOSYS;
335 }
336
337 if (flags != 0)
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200338 INFO(mod->ctx, "Flags are not implemented yet\n");
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200339
340 if ((fd = open(mod->path, O_RDONLY)) < 0) {
341 err = -errno;
342 return err;
343 }
344
Lucas De Marchib418a822011-12-01 23:13:27 -0200345 fstat(fd, &st);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200346
347 if ((mmaped_file = mmap(0, st.st_size, PROT_READ,
348 MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
349 close(fd);
350 return -errno;
351 }
352
353 err = init_module(mmaped_file, st.st_size, args);
354 if (err < 0)
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200355 ERR(mod->ctx, "Failed to insert module '%s'\n", mod->path);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200356
357 munmap(mmaped_file, st.st_size);
358 close(fd);
359
360 return err;
361}