1/* 2 * Copyright (C) 2012-2013 ProFUSION embedded systems 3 * 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. 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 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 16 */ 17 18#include <assert.h> 19#include <dirent.h> 20#include <dlfcn.h> 21#include <errno.h> 22#include <fcntl.h> 23#include <limits.h> 24#include <stdarg.h> 25#include <stddef.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <string.h> 29#include <sys/stat.h> 30#include <sys/types.h> 31#include <unistd.h> 32 33#include <shared/util.h> 34 35#include "testsuite.h" 36 37struct mod { 38 struct mod *next; 39 int ret; 40 int errcode; 41 char name[]; 42}; 43 44static struct mod *modules; 45static bool need_init = true; 46 47static void parse_retcodes(struct mod **_modules, const char *s) 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 66 modnamelen = strcspn(p, ":"); 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; 77 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; 97 mod->next = *_modules; 98 *_modules = mod; 99 } 100} 101 102static 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) { 107 if (streq(mod->name, modname)) 108 return mod; 109 } 110 111 return NULL; 112} 113 114static void init_retcodes(void) 115{ 116 const char *s; 117 struct mod *mod; 118 119 if (!need_init) 120 return; 121 122 need_init = false; 123 s = getenv(S_TC_DELETE_MODULE_RETCODES); 124 if (s == NULL) { 125 ERR("TRAP delete_module(): missing export %s?\n", 126 S_TC_DELETE_MODULE_RETCODES); 127 } 128 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 } 136} 137 138TS_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 */ 146long 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 */ 160void free_resources(void) __attribute__((destructor)); 161void free_resources(void) 162{ 163 while (modules) { 164 struct mod *mod = modules->next; 165 free(modules); 166 modules = mod; 167 } 168} 169