blob: c4d7efbafe9c2b106cf04503134097113fb94e69 [file] [log] [blame]
Lucas De Marchie701e382012-01-26 17:01:41 -02001/*
Lucas De Marchie6b0e492013-01-16 11:27:21 -02002 * Copyright (C) 2012-2013 ProFUSION embedded systems
Lucas De Marchie701e382012-01-26 17:01:41 -02003 *
Lucas De Marchie1b1ab22012-07-10 09:42:24 -03004 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
Lucas De Marchie701e382012-01-26 17:01:41 -02008 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Lucas De Marchie1b1ab22012-07-10 09:42:24 -030011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
Lucas De Marchie701e382012-01-26 17:01:41 -020013 *
Lucas De Marchie1b1ab22012-07-10 09:42:24 -030014 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Lucas De Marchie701e382012-01-26 17:01:41 -020017 */
18
Lucas De Marchi53646fc2012-01-26 02:09:28 -020019#include <assert.h>
Lucas De Marchifca5b9b2012-06-21 11:30:56 -030020#include <elf.h>
Lucas De Marchi53646fc2012-01-26 02:09:28 -020021#include <errno.h>
22#include <dirent.h>
23#include <fcntl.h>
24#include <dlfcn.h>
25#include <limits.h>
26#include <stdlib.h>
27#include <stdarg.h>
28#include <stddef.h>
29#include <string.h>
30#include <stdio.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <unistd.h>
34
35/* kmod_elf_get_section() is not exported, we need the private header */
36#include <libkmod-private.h>
37
38/* FIXME: hack, change name so we don't clash */
39#undef ERR
Lucas De Marchi5a2949c2012-05-25 00:30:37 -030040#include "mkdir.h"
Lucas De Marchi53646fc2012-01-26 02:09:28 -020041#include "testsuite.h"
42#include "stripped-module.h"
43
44struct mod {
45 struct mod *next;
46 int ret;
47 int errcode;
48 char name[];
49};
50
51static struct mod *modules;
52static bool need_init = true;
Lucas De Marchia6553702012-06-05 00:53:15 -030053static struct kmod_ctx *ctx;
Lucas De Marchi53646fc2012-01-26 02:09:28 -020054
55static void parse_retcodes(struct mod *_modules, const char *s)
56{
57 const char *p;
58
59 if (s == NULL)
60 return;
61
62 for (p = s;;) {
63 struct mod *mod;
64 const char *modname;
65 char *end;
66 size_t modnamelen;
67 int ret, errcode;
68 long l;
69
70 modname = p;
71 if (modname == NULL || modname[0] == '\0')
72 break;
73
74 modnamelen = strcspn(s, ":");
75 if (modname[modnamelen] != ':')
76 break;
77
78 p = modname + modnamelen + 1;
79 if (p == NULL)
80 break;
81
82 l = strtol(p, &end, 0);
83 if (end == p || *end != ':')
84 break;
85 ret = (int) l;
86 p = end + 1;
87
88 l = strtol(p, &end, 0);
89 if (*end == ':')
90 p = end + 1;
91 else if (*end != '\0')
92 break;
93
94 errcode = (int) l;
95
96 mod = malloc(sizeof(*mod) + modnamelen + 1);
97 if (mod == NULL)
98 break;
99
100 memcpy(mod->name, modname, modnamelen);
101 mod->name[modnamelen] = '\0';
102 mod->ret = ret;
103 mod->errcode = errcode;
104 mod->next = _modules;
105 _modules = mod;
106 }
107}
108
Lucas De Marchi5a2949c2012-05-25 00:30:37 -0300109static int write_one_line_file(const char *fn, const char *line, int len)
110{
111 FILE *f;
112 int r;
113
114 assert(fn);
115 assert(line);
116
117 f = fopen(fn, "we");
118 if (!f)
119 return -errno;
120
121 errno = 0;
122 if (fputs(line, f) < 0) {
123 r = -errno;
124 goto finish;
125 }
126
127 fflush(f);
128
129 if (ferror(f)) {
130 if (errno != 0)
131 r = -errno;
132 else
133 r = -EIO;
134 } else
135 r = 0;
136
137finish:
138 fclose(f);
139 return r;
140}
141
142static int create_sysfs_files(const char *modname)
143{
144 char buf[PATH_MAX];
145 const char *sysfsmod = "/sys/module/";
146 int len = strlen(sysfsmod);
147
148 memcpy(buf, sysfsmod, len);
149 strcpy(buf + len, modname);
150 len += strlen(modname);
151
Lucas De Marchi33202e82012-06-19 13:09:23 -0300152 assert(mkdir_p(buf, 0755) >= 0);
Lucas De Marchi5a2949c2012-05-25 00:30:37 -0300153
154 strcpy(buf + len, "/initstate");
155 return write_one_line_file(buf, "live\n", strlen("live\n"));
156}
157
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200158static struct mod *find_module(struct mod *_modules, const char *modname)
159{
160 struct mod *mod;
161
162 for (mod = _modules; mod != NULL; mod = mod->next) {
Lucas De Marchi90fc4102012-06-05 00:07:38 -0300163 if (strcmp(mod->name, modname) == 0)
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200164 return mod;
165 }
166
167 return NULL;
168}
169
170static void init_retcodes(void)
171{
172 const char *s;
173
174 if (!need_init)
175 return;
176
177 need_init = false;
178 s = getenv(S_TC_INIT_MODULE_RETCODES);
179 if (s == NULL) {
180 fprintf(stderr, "TRAP init_module(): missing export %s?\n",
181 S_TC_INIT_MODULE_RETCODES);
182 }
183
Lucas De Marchia6553702012-06-05 00:53:15 -0300184 ctx = kmod_new(NULL, NULL);
185
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200186 parse_retcodes(modules, s);
187}
188
Lucas De Marchia6553702012-06-05 00:53:15 -0300189static inline bool module_is_inkernel(const char *modname)
190{
191 struct kmod_module *mod;
192 int state;
193 bool ret;
194
195 if (kmod_module_new_from_name(ctx, modname, &mod) < 0)
196 return false;
197
198 state = kmod_module_get_initstate(mod);
199
200 if (state == KMOD_MODULE_LIVE ||
201 state == KMOD_MODULE_BUILTIN)
202 ret = true;
203 else
204 ret = false;
205
206 kmod_module_unref(mod);
207
208 return ret;
209}
210
Lucas De Marchifca5b9b2012-06-21 11:30:56 -0300211static uint8_t elf_identify(void *mem)
212{
213 uint8_t *p = mem;
214 return p[EI_CLASS];
215}
216
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200217TS_EXPORT long init_module(void *mem, unsigned long len, const char *args);
218
219/*
Lucas De Marchiddf1e7a2012-06-05 00:20:42 -0300220 * Default behavior is to try to mimic init_module behavior inside the kernel.
221 * If it is a simple test that you know the error code, set the return code
222 * in TESTSUITE_INIT_MODULE_RETCODES env var instead.
223 *
224 * The exception is when the module name is not find in the memory passed.
225 * This is because we want to be able to pass dummy modules (and not real
226 * ones) and it still work.
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200227 */
228long init_module(void *mem, unsigned long len, const char *args)
229{
230 const char *modname;
231 struct kmod_elf *elf;
232 struct mod *mod;
233 const void *buf;
234 uint64_t bufsize;
235 int err;
Lucas De Marchifca5b9b2012-06-21 11:30:56 -0300236 uint8_t class;
237 off_t offset;
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200238
239 init_retcodes();
240
241 elf = kmod_elf_new(mem, len);
242 if (elf == NULL)
243 return 0;
244
245 err = kmod_elf_get_section(elf, ".gnu.linkonce.this_module", &buf,
246 &bufsize);
247 kmod_elf_unref(elf);
248
Lucas De Marchifca5b9b2012-06-21 11:30:56 -0300249 /* We couldn't parse the ELF file. Just exit as if it was successful */
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200250 if (err < 0)
251 return 0;
252
Lucas De Marchifca5b9b2012-06-21 11:30:56 -0300253 /* We need to open both 32 and 64 bits module - hack! */
254 class = elf_identify(mem);
255 if (class == ELFCLASS64)
256 offset = MODULE_NAME_OFFSET_64;
257 else
258 offset = MODULE_NAME_OFFSET_32;
259
260 modname = (char *)buf + offset;
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200261 mod = find_module(modules, modname);
Lucas De Marchiddf1e7a2012-06-05 00:20:42 -0300262 if (mod != NULL) {
263 errno = mod->errcode;
264 err = mod->ret;
Lucas De Marchia6553702012-06-05 00:53:15 -0300265 } else if (module_is_inkernel(modname)) {
266 err = -1;
267 errno = EEXIST;
268 } else
Lucas De Marchiddf1e7a2012-06-05 00:20:42 -0300269 err = 0;
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200270
Lucas De Marchiddf1e7a2012-06-05 00:20:42 -0300271 if (err == 0)
272 create_sysfs_files(modname);
273
274 return err;
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200275}
276
277/* the test is going away anyway, but lets keep valgrind happy */
278void free_resources(void) __attribute__((destructor));
279void free_resources(void)
280{
281 while (modules) {
282 struct mod *mod = modules->next;
283 free(modules);
284 modules = mod;
285 }
Lucas De Marchia6553702012-06-05 00:53:15 -0300286
287 if (ctx)
288 kmod_unref(ctx);
Lucas De Marchi53646fc2012-01-26 02:09:28 -0200289}