From: Gongjun Song Date: Fri, 7 Mar 2025 02:33:51 +0000 (+0800) Subject: testsuite: Improve fake_delete behavior X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9cb87e2d3a21ef840096a49838892771483496c2;p=thirdparty%2Fkmod.git testsuite: Improve fake_delete behavior - When fake delete_module() succeeds, remove its entry from /sys/module. - Add tests to ensure module is properly removed. Co-developed-by: Qingqing Li Signed-off-by: Qingqing Li Signed-off-by: Dan He Signed-off-by: Gongjun Song Signed-off-by: Yuchi Chen Signed-off-by: Wenjie Wang Link: https://github.com/kmod-project/kmod/pull/309 Signed-off-by: Lucas De Marchi --- diff --git a/testsuite/delete_module.c b/testsuite/delete_module.c index 25bfc1dc..64b5b1cd 100644 --- a/testsuite/delete_module.c +++ b/testsuite/delete_module.c @@ -19,6 +19,7 @@ #include #include +#include #include "testsuite.h" @@ -122,24 +123,88 @@ static void init_retcodes(void) } } -TS_EXPORT long delete_module(const char *name, unsigned int flags); +static int remove_directory(const char *path) +{ + struct stat st; + DIR *dir; + struct dirent *entry; + char full_path[PATH_MAX]; + + if (stat(path, &st) != 0 || !S_ISDIR(st.st_mode)) { + LOG("Directory %s not found, skip remove.\n", path); + return 0; + } + + dir = opendir(path); + if (!dir) { + ERR("Failed to open directory %s: %s (errno: %d)\n", path, + strerror(errno), errno); + return -1; + } + + while ((entry = readdir(dir)) != NULL) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + + snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name); + + if (entry->d_type == DT_DIR) { + if (remove_directory(full_path) != 0) { + ERR("Failed to remove directory %s: %m\n", full_path); + goto fail; + } + } else { + if (remove(full_path) != 0) { + ERR("Failed to remove file %s: %m\n", full_path); + goto fail; + } + } + } + + closedir(dir); + + if (rmdir(path) != 0) { + ERR("Failed to remove directory %s: %m\n", path); + return -1; + } + + return 0; + +fail: + closedir(dir); + + return -1; +} /* - * FIXME: change /sys/module/ to fake-remove a module - * * Default behavior is to exit successfully. If this is not the intended * behavior, set TESTSUITE_DELETE_MODULE_RETCODES env var. */ +TS_EXPORT long delete_module(const char *name, unsigned int flags); + long delete_module(const char *modname, unsigned int flags) { + DECLARE_STRBUF_WITH_STACK(buf, PATH_MAX); struct mod *mod; + int ret = 0; init_retcodes(); mod = find_module(modules, modname); if (mod == NULL) return 0; + if (!strbuf_pushchars(&buf, "/sys/module/") || + !strbuf_pushchars(&buf, modname)) { + errno = ENOMEM; + return -1; + } + + ret = remove_directory(strbuf_str(&buf)); + if (ret != 0) + return ret; + errno = mod->errcode; + return mod->ret; } diff --git a/testsuite/meson.build b/testsuite/meson.build index 1f49f698..08e3cde9 100644 --- a/testsuite/meson.build +++ b/testsuite/meson.build @@ -95,6 +95,7 @@ _testsuite = [ 'test-testsuite', 'test-util', 'test-weakdep', + 'test-remove' ] if get_option('b_sanitize') != 'none' diff --git a/testsuite/path.c b/testsuite/path.c index b896885a..5acc1fd4 100644 --- a/testsuite/path.c +++ b/testsuite/path.c @@ -180,6 +180,8 @@ static void *get_libc_func(const char *f) WRAP_1ARG(DIR *, NULL, opendir); WRAP_1ARG(int, -1, chdir); +WRAP_1ARG(int, -1, remove); +WRAP_1ARG(int, -1, rmdir); WRAP_2ARGS(FILE *, NULL, fopen, const char *); WRAP_2ARGS(int, -1, mkdir, mode_t); diff --git a/testsuite/test-remove.c b/testsuite/test-remove.c new file mode 100644 index 00000000..a68a7186 --- /dev/null +++ b/testsuite/test-remove.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "testsuite.h" + +static noreturn int test_remove(const struct test *t) +{ + struct kmod_ctx *ctx; + struct kmod_module *mod; + const char *null_config = NULL; + int err; + struct stat st; + + ctx = kmod_new(NULL, &null_config); + if (ctx == NULL) + exit(EXIT_FAILURE); + + err = kmod_module_new_from_path(ctx, "/mod-simple.ko", &mod); + if (err != 0) { + ERR("could not create module from path: %m\n"); + exit(EXIT_FAILURE); + } + + err = kmod_module_insert_module(mod, 0, NULL); + if (err != 0) { + ERR("could not insert module: %m\n"); + exit(EXIT_FAILURE); + } + + err = kmod_module_remove_module(mod, 0); + if (err != 0) { + ERR("could not remove module: %m\n"); + exit(EXIT_FAILURE); + } + + if (stat("/sys/module/mod_simple", &st) == 0 && S_ISDIR(st.st_mode)) { + ERR("could not remove module directory.\n"); + exit(EXIT_FAILURE); + } + kmod_unref(ctx); + + exit(EXIT_SUCCESS); +} +DEFINE_TEST(test_remove, + .description = "test if libkmod's delete_module removes module directory", + .config = { + [TC_ROOTFS] = TESTSUITE_ROOTFS "test-remove/", + [TC_INIT_MODULE_RETCODES] = "", + [TC_DELETE_MODULE_RETCODES] = "mod_simple:0:0" STRINGIFY(ENOENT), + }); + +TESTSUITE_MAIN();