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