]>
Commit | Line | Data |
---|---|---|
e701e381 | 1 | /* |
e6b0e49b | 2 | * Copyright (C) 2012-2013 ProFUSION embedded systems |
e701e381 | 3 | * |
e1b1ab24 LDM |
4 | * 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. | |
e701e381 LDM |
8 | * |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
e1b1ab24 LDM |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. | |
e701e381 | 13 | * |
e1b1ab24 | 14 | * You should have received a copy of the GNU Lesser General Public |
dea2dfee | 15 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
e701e381 LDM |
16 | */ |
17 | ||
f6ef5d6b | 18 | #include <assert.h> |
f6ef5d6b | 19 | #include <dirent.h> |
f6ef5d6b | 20 | #include <dlfcn.h> |
c2e4286b LDM |
21 | #include <errno.h> |
22 | #include <fcntl.h> | |
f6ef5d6b | 23 | #include <limits.h> |
f6ef5d6b LDM |
24 | #include <stdarg.h> |
25 | #include <stddef.h> | |
f6ef5d6b | 26 | #include <stdio.h> |
c2e4286b LDM |
27 | #include <stdlib.h> |
28 | #include <string.h> | |
f6ef5d6b | 29 | #include <sys/stat.h> |
c2e4286b | 30 | #include <sys/types.h> |
f6ef5d6b LDM |
31 | #include <unistd.h> |
32 | ||
af87874f LDM |
33 | #include <shared/util.h> |
34 | ||
f6ef5d6b LDM |
35 | #include "testsuite.h" |
36 | ||
37 | struct mod { | |
38 | struct mod *next; | |
39 | int ret; | |
40 | int errcode; | |
41 | char name[]; | |
42 | }; | |
43 | ||
44 | static struct mod *modules; | |
45 | static bool need_init = true; | |
46 | ||
af87874f | 47 | static void parse_retcodes(struct mod **_modules, const char *s) |
f6ef5d6b LDM |
48 | { |
49 | const char *p; | |
50 | ||
51 | if (s == NULL) | |
52 | return; | |
53 | ||
54 | for (p = s;;) { | |
55 | struct mod *mod; | |
56 | const char *modname; | |
57 | char *end; | |
58 | size_t modnamelen; | |
59 | int ret, errcode; | |
60 | long l; | |
61 | ||
62 | modname = p; | |
63 | if (modname == NULL || modname[0] == '\0') | |
64 | break; | |
65 | ||
af87874f | 66 | modnamelen = strcspn(p, ":"); |
f6ef5d6b LDM |
67 | if (modname[modnamelen] != ':') |
68 | break; | |
69 | ||
70 | p = modname + modnamelen + 1; | |
71 | if (p == NULL) | |
72 | break; | |
73 | ||
74 | l = strtol(p, &end, 0); | |
75 | if (end == p || *end != ':') | |
76 | break; | |
af87874f | 77 | |
f6ef5d6b LDM |
78 | ret = (int) l; |
79 | p = end + 1; | |
80 | ||
81 | l = strtol(p, &end, 0); | |
82 | if (*end == ':') | |
83 | p = end + 1; | |
84 | else if (*end != '\0') | |
85 | break; | |
86 | ||
87 | errcode = (int) l; | |
88 | ||
89 | mod = malloc(sizeof(*mod) + modnamelen + 1); | |
90 | if (mod == NULL) | |
91 | break; | |
92 | ||
93 | memcpy(mod->name, modname, modnamelen); | |
94 | mod->name[modnamelen] = '\0'; | |
95 | mod->ret = ret; | |
96 | mod->errcode = errcode; | |
af87874f LDM |
97 | mod->next = *_modules; |
98 | *_modules = mod; | |
f6ef5d6b LDM |
99 | } |
100 | } | |
101 | ||
102 | static struct mod *find_module(struct mod *_modules, const char *modname) | |
103 | { | |
104 | struct mod *mod; | |
105 | ||
106 | for (mod = _modules; mod != NULL; mod = mod->next) { | |
af87874f | 107 | if (streq(mod->name, modname)) |
f6ef5d6b LDM |
108 | return mod; |
109 | } | |
110 | ||
111 | return NULL; | |
112 | } | |
113 | ||
114 | static void init_retcodes(void) | |
115 | { | |
116 | const char *s; | |
af87874f | 117 | struct mod *mod; |
f6ef5d6b LDM |
118 | |
119 | if (!need_init) | |
120 | return; | |
121 | ||
122 | need_init = false; | |
123 | s = getenv(S_TC_DELETE_MODULE_RETCODES); | |
124 | if (s == NULL) { | |
af87874f | 125 | ERR("TRAP delete_module(): missing export %s?\n", |
f6ef5d6b LDM |
126 | S_TC_DELETE_MODULE_RETCODES); |
127 | } | |
128 | ||
af87874f LDM |
129 | parse_retcodes(&modules, s); |
130 | ||
131 | for (mod = modules; mod != NULL; mod = mod->next) { | |
132 | LOG("Added module to test delete_module:\n"); | |
133 | LOG("\tname=%s ret=%d errcode=%d\n", | |
134 | mod->name, mod->ret, mod->errcode); | |
135 | } | |
f6ef5d6b LDM |
136 | } |
137 | ||
138 | TS_EXPORT long delete_module(const char *name, unsigned int flags); | |
139 | ||
140 | /* | |
141 | * FIXME: change /sys/module/<modname> to fake-remove a module | |
142 | * | |
143 | * Default behavior is to exit successfully. If this is not the intended | |
144 | * behavior, set TESTSUITE_DELETE_MODULE_RETCODES env var. | |
145 | */ | |
146 | long delete_module(const char *modname, unsigned int flags) | |
147 | { | |
148 | struct mod *mod; | |
149 | ||
150 | init_retcodes(); | |
151 | mod = find_module(modules, modname); | |
152 | if (mod == NULL) | |
153 | return 0; | |
154 | ||
155 | errno = mod->errcode; | |
156 | return mod->ret; | |
157 | } | |
158 | ||
159 | /* the test is going away anyway, but lets keep valgrind happy */ | |
160 | void free_resources(void) __attribute__((destructor)); | |
161 | void free_resources(void) | |
162 | { | |
163 | while (modules) { | |
164 | struct mod *mod = modules->next; | |
165 | free(modules); | |
166 | modules = mod; | |
167 | } | |
168 | } |