2 * Copyright (C) 2012-2013 ProFUSION embedded systems
3 * Copyright (C) 2012-2013 Lucas De Marchi <lucas.de.marchi@gmail.com>
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.
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.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 #ifndef HAVE_FINIT_MODULE
20 #define HAVE_FINIT_MODULE 1
38 #include <sys/syscall.h>
39 #include <sys/types.h>
40 #include <sys/utsname.h>
42 #include <shared/util.h>
44 /* kmod_elf_get_section() is not exported, we need the private header */
45 #include <libkmod/libkmod-internal.h>
47 /* FIXME: hack, change name so we don't clash */
49 #include "testsuite.h"
50 #include "stripped-module.h"
59 static struct mod
*modules
;
60 static bool need_init
= true;
61 static struct kmod_ctx
*ctx
;
63 static void parse_retcodes(struct mod
*_modules
, const char *s
)
79 if (modname
== NULL
|| modname
[0] == '\0')
82 modnamelen
= strcspn(s
, ":");
83 if (modname
[modnamelen
] != ':')
86 p
= modname
+ modnamelen
+ 1;
90 l
= strtol(p
, &end
, 0);
91 if (end
== p
|| *end
!= ':')
96 l
= strtol(p
, &end
, 0);
99 else if (*end
!= '\0')
104 mod
= malloc(sizeof(*mod
) + modnamelen
+ 1);
108 memcpy(mod
->name
, modname
, modnamelen
);
109 mod
->name
[modnamelen
] = '\0';
111 mod
->errcode
= errcode
;
112 mod
->next
= _modules
;
117 static int write_one_line_file(const char *fn
, const char *line
, int len
)
130 if (fputs(line
, f
) < 0) {
150 static int create_sysfs_files(const char *modname
)
153 const char *sysfsmod
= "/sys/module/";
154 int len
= strlen(sysfsmod
);
156 memcpy(buf
, sysfsmod
, len
);
157 strcpy(buf
+ len
, modname
);
158 len
+= strlen(modname
);
160 assert(mkdir_p(buf
, len
, 0755) >= 0);
162 strcpy(buf
+ len
, "/initstate");
163 return write_one_line_file(buf
, "live\n", strlen("live\n"));
166 static struct mod
*find_module(struct mod
*_modules
, const char *modname
)
170 for (mod
= _modules
; mod
!= NULL
; mod
= mod
->next
) {
171 if (strcmp(mod
->name
, modname
) == 0)
178 static void init_retcodes(void)
186 s
= getenv(S_TC_INIT_MODULE_RETCODES
);
188 fprintf(stderr
, "TRAP init_module(): missing export %s?\n",
189 S_TC_INIT_MODULE_RETCODES
);
192 ctx
= kmod_new(NULL
, NULL
);
194 parse_retcodes(modules
, s
);
197 static inline bool module_is_inkernel(const char *modname
)
199 struct kmod_module
*mod
;
203 if (kmod_module_new_from_name(ctx
, modname
, &mod
) < 0)
206 state
= kmod_module_get_initstate(mod
);
208 if (state
== KMOD_MODULE_LIVE
||
209 state
== KMOD_MODULE_BUILTIN
)
214 kmod_module_unref(mod
);
219 static uint8_t elf_identify(void *mem
)
225 TS_EXPORT
long init_module(void *mem
, unsigned long len
, const char *args
);
228 * Default behavior is to try to mimic init_module behavior inside the kernel.
229 * If it is a simple test that you know the error code, set the return code
230 * in TESTSUITE_INIT_MODULE_RETCODES env var instead.
232 * The exception is when the module name is not find in the memory passed.
233 * This is because we want to be able to pass dummy modules (and not real
234 * ones) and it still work.
236 long init_module(void *mem
, unsigned long len
, const char *args
)
239 struct kmod_elf
*elf
;
249 elf
= kmod_elf_new(mem
, len
);
253 err
= kmod_elf_get_section(elf
, ".gnu.linkonce.this_module", &buf
,
257 /* We couldn't parse the ELF file. Just exit as if it was successful */
261 /* We need to open both 32 and 64 bits module - hack! */
262 class = elf_identify(mem
);
263 if (class == ELFCLASS64
)
264 offset
= MODULE_NAME_OFFSET_64
;
266 offset
= MODULE_NAME_OFFSET_32
;
268 modname
= (char *)buf
+ offset
;
269 mod
= find_module(modules
, modname
);
271 errno
= mod
->errcode
;
273 } else if (module_is_inkernel(modname
)) {
280 create_sysfs_files(modname
);
285 static int check_kernel_version(int major
, int minor
)
289 int maj
= 0, min
= 0;
293 for (p
= u
.release
; *p
>= '0' && *p
<= '9'; p
++)
294 maj
= maj
* 10 + *p
- '0';
296 for (p
++; *p
>= '0' && *p
<= '9'; p
++)
297 min
= min
* 10 + *p
- '0';
298 if (maj
> major
|| (maj
== major
&& min
>= minor
))
304 TS_EXPORT
int finit_module(const int fd
, const char *args
, const int flags
);
306 int finit_module(const int fd
, const char *args
, const int flags
)
313 if (!check_kernel_version(3, 8)) {
317 if (fstat(fd
, &st
) < 0)
321 mem
= mmap(NULL
, len
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
322 if (mem
== MAP_FAILED
)
325 err
= init_module(mem
, len
, args
);
331 TS_EXPORT
long int syscall(long int __sysno
, ...)
341 if (__sysno
== __NR_finit_module
) {
346 va_start(ap
, __sysno
);
348 fd
= va_arg(ap
, int);
349 args
= va_arg(ap
, const char *);
350 flags
= va_arg(ap
, int);
352 ret
= finit_module(fd
, args
, flags
);
359 * FIXME: no way to call the libc function - let's hope there are no
365 /* the test is going away anyway, but lets keep valgrind happy */
366 void free_resources(void) __attribute__((destructor
));
367 void free_resources(void)
370 struct mod
*mod
= modules
->next
;