blob: 7466805f5edfe65c586f390b1c787c92fdfa2f0d [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"
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -020036//#include "libkmod-index.h"
Lucas De Marchi8f788d52011-11-25 01:22:56 -020037
38/**
39 * kmod_module:
40 *
41 * Opaque object representing a module.
42 */
43struct kmod_module {
44 struct kmod_ctx *ctx;
45 int refcount;
46 const char *path;
47 const char *name;
48};
49
50static char *path_to_modname(const char *path)
51{
52 char *modname;
53 char *c;
54
55 modname = basename(path);
56 if (modname == NULL || modname[0] == '\0')
57 return NULL;
58
59 modname = strdup(modname);
60 for (c = modname; *c != '\0' && *c != '.'; c++) {
61 if (*c == '-')
62 *c = '_';
63 }
64
65 *c = '\0';
66 return modname;
67}
68
69static const char *get_modname(struct kmod_module *mod)
70{
71 if (mod->name == NULL)
72 mod->name = path_to_modname(mod->path);
73
74 return mod->name;
75}
76
77KMOD_EXPORT int kmod_module_new_from_name(struct kmod_ctx *ctx,
78 const char *name,
79 struct kmod_module **mod)
80{
81 struct kmod_module *m;
82
83 if (ctx == NULL || name == NULL)
84 return -ENOENT;
85
86 m = calloc(1, sizeof(*m));
87 if (m == NULL) {
88 free(m);
89 return -ENOMEM;
90 }
91
92 m->ctx = kmod_ref(ctx);
93 m->name = strdup(name);
94
95 *mod = m;
96
97 return 0;
98}
99
100KMOD_EXPORT int kmod_module_new_from_path(struct kmod_ctx *ctx,
101 const char *path,
102 struct kmod_module **mod)
103{
104 struct kmod_module *m;
105 int err;
106 struct stat st;
107
108 if (ctx == NULL || path == NULL)
109 return -ENOENT;
110
111 err = stat(path, &st);
112 if (err < 0)
113 return -errno;
114
115 m = calloc(1, sizeof(*m));
116 if (m == NULL) {
117 free(m);
118 return -ENOMEM;
119 }
120
121 m->ctx = kmod_ref(ctx);
122 m->path = strdup(path);
123
124 *mod = m;
125
126 return 0;
127}
128
129KMOD_EXPORT struct kmod_module *kmod_module_unref(struct kmod_module *mod)
130{
131 if (mod == NULL)
132 return NULL;
133
134 if (--mod->refcount > 0)
135 return mod;
136
137 DBG(mod->ctx, "kmod_module %p released\n", mod);
138
139 kmod_unref(mod->ctx);
140 free((char *) mod->path);
141 free((char *) mod->name);
142 free(mod);
143 return NULL;
144}
145
146KMOD_EXPORT struct kmod_module *kmod_module_ref(struct kmod_module *mod)
147{
148 if (mod == NULL)
149 return NULL;
150
151 mod->refcount++;
152
153 return mod;
154}
155
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200156KMOD_EXPORT int kmod_module_new_from_lookup(struct kmod_ctx *ctx,
157 const char *alias,
158 struct kmod_list **list)
159{
160
161 int err;
162
163 if (ctx == NULL || alias == NULL)
164 return -ENOENT;
165
166
167 if (list == NULL || *list != NULL) {
168 ERR(ctx, "An empty list is needed to create lookup\n");
169 return -ENOSYS;
170 }
171
172 err = kmod_lookup_alias_from_config(ctx, alias, list);
173
174 if (err < 0) {
175 kmod_module_unref_list(*list);
176 *list = NULL;
177 }
178
179 return err;
180}
181
182KMOD_EXPORT int kmod_module_unref_list(struct kmod_list *list)
183{
184 for (; list != NULL; list = kmod_list_remove(list))
185 kmod_module_unref(list->data);
186
187 return 0;
188}
189
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200190KMOD_EXPORT struct kmod_module *kmod_module_get_module(struct kmod_list *l)
191{
192 struct kmod_module *mod = l->data;
193 return kmod_module_ref(mod);
194}
195
196KMOD_EXPORT const char *kmod_module_get_name(struct kmod_module *mod)
197{
198 // FIXME calculate name if name == NULL
199 return mod->name;
200}
201
202KMOD_EXPORT const char *kmod_module_get_path(struct kmod_module *mod)
203{
204 // FIXME calculate path if path == NULL
205 return mod->path;
206}
207
208
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200209extern long delete_module(const char *name, unsigned int flags);
210
211KMOD_EXPORT int kmod_module_remove_module(struct kmod_module *mod,
212 unsigned int flags)
213{
214 int err;
215 const char *modname;
216
217 if (mod == NULL)
218 return -ENOENT;
219
220 /* Filter out other flags */
221 flags &= (KMOD_REMOVE_FORCE | KMOD_REMOVE_NOWAIT);
222
223 modname = get_modname(mod);
224 err = delete_module(modname, flags);
225 if (err != 0) {
226 ERR(mod->ctx, "Removing '%s': %s\n", modname,
227 strerror(-err));
228 return err;
229 }
230
231 return 0;
232}
233
234extern long init_module(void *mem, unsigned long len, const char *args);
235
236KMOD_EXPORT int kmod_module_insert_module(struct kmod_module *mod,
237 unsigned int flags)
238{
239 int err;
240 void *mmaped_file;
241 struct stat st;
242 int fd;
243 const char *args = "";
244
245 if (mod == NULL)
246 return -ENOENT;
247
248 if (mod->path == NULL) {
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200249 ERR(mod->ctx, "Not supported to load a module by name yet\n");
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200250 return -ENOSYS;
251 }
252
253 if (flags != 0)
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200254 INFO(mod->ctx, "Flags are not implemented yet\n");
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200255
256 if ((fd = open(mod->path, O_RDONLY)) < 0) {
257 err = -errno;
258 return err;
259 }
260
261 stat(mod->path, &st);
262
263 if ((mmaped_file = mmap(0, st.st_size, PROT_READ,
264 MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
265 close(fd);
266 return -errno;
267 }
268
269 err = init_module(mmaped_file, st.st_size, args);
270 if (err < 0)
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200271 ERR(mod->ctx, "Failed to insert module '%s'\n", mod->path);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200272
273 munmap(mmaped_file, st.st_size);
274 close(fd);
275
276 return err;
277}