Home | History | Annotate | Download | only in testsuite
      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 
     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 
     47 static 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 
    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) {
    107 		if (streq(mod->name, modname))
    108 			return mod;
    109 	}
    110 
    111 	return NULL;
    112 }
    113 
    114 static 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 
    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 }
    169