blob: f28678f0ad61f4139caddb8d48bb260bfa89f2d8 [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
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 <inttypes.h>
29#include <sys/stat.h>
30#include <sys/types.h>
31#include <sys/mman.h>
32#include <string.h>
33
34#include "libkmod.h"
35#include "libkmod-private.h"
36
37/**
38 * kmod_module:
39 *
40 * Opaque object representing a module.
41 */
42struct kmod_module {
43 struct kmod_ctx *ctx;
44 int refcount;
45 const char *path;
46 const char *name;
47};
48
49static char *path_to_modname(const char *path)
50{
51 char *modname;
52 char *c;
53
54 modname = basename(path);
55 if (modname == NULL || modname[0] == '\0')
56 return NULL;
57
58 modname = strdup(modname);
59 for (c = modname; *c != '\0' && *c != '.'; c++) {
60 if (*c == '-')
61 *c = '_';
62 }
63
64 *c = '\0';
65 return modname;
66}
67
68static const char *get_modname(struct kmod_module *mod)
69{
70 if (mod->name == NULL)
71 mod->name = path_to_modname(mod->path);
72
73 return mod->name;
74}
75
76KMOD_EXPORT int kmod_module_new_from_name(struct kmod_ctx *ctx,
77 const char *name,
78 struct kmod_module **mod)
79{
80 struct kmod_module *m;
81
82 if (ctx == NULL || name == NULL)
83 return -ENOENT;
84
85 m = calloc(1, sizeof(*m));
86 if (m == NULL) {
87 free(m);
88 return -ENOMEM;
89 }
90
91 m->ctx = kmod_ref(ctx);
92 m->name = strdup(name);
93
94 *mod = m;
95
96 return 0;
97}
98
99KMOD_EXPORT int kmod_module_new_from_path(struct kmod_ctx *ctx,
100 const char *path,
101 struct kmod_module **mod)
102{
103 struct kmod_module *m;
104 int err;
105 struct stat st;
106
107 if (ctx == NULL || path == NULL)
108 return -ENOENT;
109
110 err = stat(path, &st);
111 if (err < 0)
112 return -errno;
113
114 m = calloc(1, sizeof(*m));
115 if (m == NULL) {
116 free(m);
117 return -ENOMEM;
118 }
119
120 m->ctx = kmod_ref(ctx);
121 m->path = strdup(path);
122
123 *mod = m;
124
125 return 0;
126}
127
128KMOD_EXPORT struct kmod_module *kmod_module_unref(struct kmod_module *mod)
129{
130 if (mod == NULL)
131 return NULL;
132
133 if (--mod->refcount > 0)
134 return mod;
135
136 DBG(mod->ctx, "kmod_module %p released\n", mod);
137
138 kmod_unref(mod->ctx);
139 free((char *) mod->path);
140 free((char *) mod->name);
141 free(mod);
142 return NULL;
143}
144
145KMOD_EXPORT struct kmod_module *kmod_module_ref(struct kmod_module *mod)
146{
147 if (mod == NULL)
148 return NULL;
149
150 mod->refcount++;
151
152 return mod;
153}
154
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200155#define CHECK_ERR_AND_FINISH(_err, _label_err, _list, label_finish) \
156 do { \
157 if ((_err) < 0) \
158 goto _label_err; \
159 if (*(_list) != NULL) \
160 goto finish; \
161 } while (0)
162
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200163KMOD_EXPORT int kmod_module_new_from_lookup(struct kmod_ctx *ctx,
164 const char *alias,
165 struct kmod_list **list)
166{
167
168 int err;
169
170 if (ctx == NULL || alias == NULL)
171 return -ENOENT;
172
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200173 if (list == NULL || *list != NULL) {
174 ERR(ctx, "An empty list is needed to create lookup\n");
175 return -ENOSYS;
176 }
177
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200178 /* Aliases from config file override all the others */
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200179 err = kmod_lookup_alias_from_config(ctx, alias, list);
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200180 CHECK_ERR_AND_FINISH(err, fail, list, finish);
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200181
Lucas De Marchi64700e42011-12-01 15:57:53 -0200182 err = kmod_lookup_alias_from_moddep_file(ctx, alias, list);
183 CHECK_ERR_AND_FINISH(err, fail, list, finish);
184
Lucas De Marchi9ba6f572011-11-30 20:31:45 -0200185 err = kmod_lookup_alias_from_symbols_file(ctx, alias, list);
186 CHECK_ERR_AND_FINISH(err, fail, list, finish);
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200187
Lucas De Marchi49e61ca2011-12-01 16:27:04 -0200188 err = kmod_lookup_alias_from_aliases_file(ctx, alias, list);
189 CHECK_ERR_AND_FINISH(err, fail, list, finish);
190
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200191finish:
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200192
193 return err;
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200194fail:
195 kmod_module_unref_list(*list);
196 *list = NULL;
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200197}
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200198#undef CHECK_ERR_AND_FINISH
199
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200200
201KMOD_EXPORT int kmod_module_unref_list(struct kmod_list *list)
202{
203 for (; list != NULL; list = kmod_list_remove(list))
204 kmod_module_unref(list->data);
205
206 return 0;
207}
208
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200209KMOD_EXPORT struct kmod_module *kmod_module_get_module(struct kmod_list *l)
210{
211 struct kmod_module *mod = l->data;
212 return kmod_module_ref(mod);
213}
214
215KMOD_EXPORT const char *kmod_module_get_name(struct kmod_module *mod)
216{
217 // FIXME calculate name if name == NULL
218 return mod->name;
219}
220
221KMOD_EXPORT const char *kmod_module_get_path(struct kmod_module *mod)
222{
223 // FIXME calculate path if path == NULL
224 return mod->path;
225}
226
227
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200228extern long delete_module(const char *name, unsigned int flags);
229
230KMOD_EXPORT int kmod_module_remove_module(struct kmod_module *mod,
231 unsigned int flags)
232{
233 int err;
234 const char *modname;
235
236 if (mod == NULL)
237 return -ENOENT;
238
239 /* Filter out other flags */
240 flags &= (KMOD_REMOVE_FORCE | KMOD_REMOVE_NOWAIT);
241
242 modname = get_modname(mod);
243 err = delete_module(modname, flags);
244 if (err != 0) {
245 ERR(mod->ctx, "Removing '%s': %s\n", modname,
246 strerror(-err));
247 return err;
248 }
249
250 return 0;
251}
252
253extern long init_module(void *mem, unsigned long len, const char *args);
254
255KMOD_EXPORT int kmod_module_insert_module(struct kmod_module *mod,
256 unsigned int flags)
257{
258 int err;
259 void *mmaped_file;
260 struct stat st;
261 int fd;
262 const char *args = "";
263
264 if (mod == NULL)
265 return -ENOENT;
266
267 if (mod->path == NULL) {
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200268 ERR(mod->ctx, "Not supported to load a module by name yet\n");
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200269 return -ENOSYS;
270 }
271
272 if (flags != 0)
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200273 INFO(mod->ctx, "Flags are not implemented yet\n");
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200274
275 if ((fd = open(mod->path, O_RDONLY)) < 0) {
276 err = -errno;
277 return err;
278 }
279
280 stat(mod->path, &st);
281
282 if ((mmaped_file = mmap(0, st.st_size, PROT_READ,
283 MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
284 close(fd);
285 return -errno;
286 }
287
288 err = init_module(mmaped_file, st.st_size, args);
289 if (err < 0)
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200290 ERR(mod->ctx, "Failed to insert module '%s'\n", mod->path);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200291
292 munmap(mmaped_file, st.st_size);
293 close(fd);
294
295 return err;
296}