]> git.ipfire.org Git - thirdparty/kmod.git/blob - testsuite/init_module.c
Move hash implementation to shared directory
[thirdparty/kmod.git] / testsuite / init_module.c
1 /*
2 * Copyright (C) 2012-2013 ProFUSION embedded systems
3 * Copyright (C) 2012-2013 Lucas De Marchi <lucas.de.marchi@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This program 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 #ifndef HAVE_FINIT_MODULE
21 #define HAVE_FINIT_MODULE 1
22 #endif
23
24 #include <assert.h>
25 #include <elf.h>
26 #include <errno.h>
27 #include <dirent.h>
28 #include <fcntl.h>
29 #include <dlfcn.h>
30 #include <limits.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <stddef.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <sys/mman.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/syscall.h>
40 #include <sys/utsname.h>
41 #include <unistd.h>
42
43 #include <shared/util.h>
44
45 /* kmod_elf_get_section() is not exported, we need the private header */
46 #include <libkmod-internal.h>
47
48 /* FIXME: hack, change name so we don't clash */
49 #undef ERR
50 #include "testsuite.h"
51 #include "stripped-module.h"
52
53 struct mod {
54 struct mod *next;
55 int ret;
56 int errcode;
57 char name[];
58 };
59
60 static struct mod *modules;
61 static bool need_init = true;
62 static struct kmod_ctx *ctx;
63
64 static void parse_retcodes(struct mod *_modules, const char *s)
65 {
66 const char *p;
67
68 if (s == NULL)
69 return;
70
71 for (p = s;;) {
72 struct mod *mod;
73 const char *modname;
74 char *end;
75 size_t modnamelen;
76 int ret, errcode;
77 long l;
78
79 modname = p;
80 if (modname == NULL || modname[0] == '\0')
81 break;
82
83 modnamelen = strcspn(s, ":");
84 if (modname[modnamelen] != ':')
85 break;
86
87 p = modname + modnamelen + 1;
88 if (p == NULL)
89 break;
90
91 l = strtol(p, &end, 0);
92 if (end == p || *end != ':')
93 break;
94 ret = (int) l;
95 p = end + 1;
96
97 l = strtol(p, &end, 0);
98 if (*end == ':')
99 p = end + 1;
100 else if (*end != '\0')
101 break;
102
103 errcode = (int) l;
104
105 mod = malloc(sizeof(*mod) + modnamelen + 1);
106 if (mod == NULL)
107 break;
108
109 memcpy(mod->name, modname, modnamelen);
110 mod->name[modnamelen] = '\0';
111 mod->ret = ret;
112 mod->errcode = errcode;
113 mod->next = _modules;
114 _modules = mod;
115 }
116 }
117
118 static int write_one_line_file(const char *fn, const char *line, int len)
119 {
120 FILE *f;
121 int r;
122
123 assert(fn);
124 assert(line);
125
126 f = fopen(fn, "we");
127 if (!f)
128 return -errno;
129
130 errno = 0;
131 if (fputs(line, f) < 0) {
132 r = -errno;
133 goto finish;
134 }
135
136 fflush(f);
137
138 if (ferror(f)) {
139 if (errno != 0)
140 r = -errno;
141 else
142 r = -EIO;
143 } else
144 r = 0;
145
146 finish:
147 fclose(f);
148 return r;
149 }
150
151 static int create_sysfs_files(const char *modname)
152 {
153 char buf[PATH_MAX];
154 const char *sysfsmod = "/sys/module/";
155 int len = strlen(sysfsmod);
156
157 memcpy(buf, sysfsmod, len);
158 strcpy(buf + len, modname);
159 len += strlen(modname);
160
161 assert(mkdir_p(buf, len, 0755) >= 0);
162
163 strcpy(buf + len, "/initstate");
164 return write_one_line_file(buf, "live\n", strlen("live\n"));
165 }
166
167 static struct mod *find_module(struct mod *_modules, const char *modname)
168 {
169 struct mod *mod;
170
171 for (mod = _modules; mod != NULL; mod = mod->next) {
172 if (strcmp(mod->name, modname) == 0)
173 return mod;
174 }
175
176 return NULL;
177 }
178
179 static void init_retcodes(void)
180 {
181 const char *s;
182
183 if (!need_init)
184 return;
185
186 need_init = false;
187 s = getenv(S_TC_INIT_MODULE_RETCODES);
188 if (s == NULL) {
189 fprintf(stderr, "TRAP init_module(): missing export %s?\n",
190 S_TC_INIT_MODULE_RETCODES);
191 }
192
193 ctx = kmod_new(NULL, NULL);
194
195 parse_retcodes(modules, s);
196 }
197
198 static inline bool module_is_inkernel(const char *modname)
199 {
200 struct kmod_module *mod;
201 int state;
202 bool ret;
203
204 if (kmod_module_new_from_name(ctx, modname, &mod) < 0)
205 return false;
206
207 state = kmod_module_get_initstate(mod);
208
209 if (state == KMOD_MODULE_LIVE ||
210 state == KMOD_MODULE_BUILTIN)
211 ret = true;
212 else
213 ret = false;
214
215 kmod_module_unref(mod);
216
217 return ret;
218 }
219
220 static uint8_t elf_identify(void *mem)
221 {
222 uint8_t *p = mem;
223 return p[EI_CLASS];
224 }
225
226 TS_EXPORT long init_module(void *mem, unsigned long len, const char *args);
227
228 /*
229 * Default behavior is to try to mimic init_module behavior inside the kernel.
230 * If it is a simple test that you know the error code, set the return code
231 * in TESTSUITE_INIT_MODULE_RETCODES env var instead.
232 *
233 * The exception is when the module name is not find in the memory passed.
234 * This is because we want to be able to pass dummy modules (and not real
235 * ones) and it still work.
236 */
237 long init_module(void *mem, unsigned long len, const char *args)
238 {
239 const char *modname;
240 struct kmod_elf *elf;
241 struct mod *mod;
242 const void *buf;
243 uint64_t bufsize;
244 int err;
245 uint8_t class;
246 off_t offset;
247
248 init_retcodes();
249
250 elf = kmod_elf_new(mem, len);
251 if (elf == NULL)
252 return 0;
253
254 err = kmod_elf_get_section(elf, ".gnu.linkonce.this_module", &buf,
255 &bufsize);
256 kmod_elf_unref(elf);
257
258 /* We couldn't parse the ELF file. Just exit as if it was successful */
259 if (err < 0)
260 return 0;
261
262 /* We need to open both 32 and 64 bits module - hack! */
263 class = elf_identify(mem);
264 if (class == ELFCLASS64)
265 offset = MODULE_NAME_OFFSET_64;
266 else
267 offset = MODULE_NAME_OFFSET_32;
268
269 modname = (char *)buf + offset;
270 mod = find_module(modules, modname);
271 if (mod != NULL) {
272 errno = mod->errcode;
273 err = mod->ret;
274 } else if (module_is_inkernel(modname)) {
275 err = -1;
276 errno = EEXIST;
277 } else
278 err = 0;
279
280 if (err == 0)
281 create_sysfs_files(modname);
282
283 return err;
284 }
285
286 static int check_kernel_version(int major, int minor)
287 {
288 struct utsname u;
289 const char *p;
290 int maj = 0, min = 0;
291
292 if (uname(&u) < 0)
293 return false;
294 for (p = u.release; *p >= '0' && *p <= '9'; p++)
295 maj = maj * 10 + *p - '0';
296 if (*p == '.')
297 for (p++; *p >= '0' && *p <= '9'; p++)
298 min = min * 10 + *p - '0';
299 if (maj > major || (maj == major && min >= minor))
300 return true;
301 return false;
302 }
303
304
305 TS_EXPORT int finit_module(const int fd, const char *args, const int flags);
306
307 int finit_module(const int fd, const char *args, const int flags)
308 {
309 int err;
310 void *mem;
311 unsigned long len;
312 struct stat st;
313
314 if (!check_kernel_version(3, 8)) {
315 errno = ENOSYS;
316 return -1;
317 }
318 if (fstat(fd, &st) < 0)
319 return -1;
320
321 len = st.st_size;
322 mem = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
323 if (mem == MAP_FAILED)
324 return -1;
325
326 err = init_module(mem, len, args);
327 munmap(mem, len);
328
329 return err;
330 }
331
332 TS_EXPORT long int syscall(long int __sysno, ...)
333 {
334 va_list ap;
335 long ret;
336
337 if (__sysno == -1) {
338 errno = ENOSYS;
339 return -1;
340 }
341
342 if (__sysno == __NR_finit_module) {
343 const char *args;
344 int flags;
345 int fd;
346
347 va_start(ap, __sysno);
348
349 fd = va_arg(ap, int);
350 args = va_arg(ap, const char *);
351 flags = va_arg(ap, int);
352
353 ret = finit_module(fd, args, flags);
354
355 va_end(ap);
356 return ret;
357 }
358
359 /*
360 * FIXME: no way to call the libc function - let's hope there are no
361 * other users.
362 */
363 abort();
364 }
365
366 /* the test is going away anyway, but lets keep valgrind happy */
367 void free_resources(void) __attribute__((destructor));
368 void free_resources(void)
369 {
370 while (modules) {
371 struct mod *mod = modules->next;
372 free(modules);
373 modules = mod;
374 }
375
376 if (ctx)
377 kmod_unref(ctx);
378 }