testsuite/test-modinfo testsuite/test-util testsuite/test-new-module \
testsuite/test-modprobe testsuite/test-blacklist \
testsuite/test-dependencies testsuite/test-depmod \
- testsuite/test-list
+ testsuite/test-list testsuite/test-user
check_PROGRAMS = $(TESTSUITE)
TESTS = $(TESTSUITE)
testsuite_test_depmod_CPPFLAGS = $(TESTSUITE_CPPFLAGS)
testsuite_test_list_LDADD = $(TESTSUITE_LDADD)
testsuite_test_list_CPPFLAGS = $(TESTSUITE_CPPFLAGS)
+testsuite_test_user_LDADD = $(TESTSUITE_LDADD)
+testsuite_test_user_CPPFLAGS = $(TESTSUITE_CPPFLAGS)
testsuite-distclean:
$(RM) -r $(ROOTFS)
/test-modprobe
/test-hash
/test-list
+/test-user
/rootfs
/stamp-rootfs
/test-scratchbuf.log
/test-testsuite.trs
/test-list.log
/test-list.trs
+/test-user.log
+/test-user.trs
obj-m += mod-fake-scsi-mod.o
obj-m += mod-fake-cciss.o
+obj-m += mod-weakdep.o
+
else
# only build ARCH-specific module
ifeq ($(ARCH),)
--- /dev/null
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#ifndef MODULE_WEAKDEP
+#define MODULE_WEAKDEP(_weakdep) MODULE_INFO(weakdep, _weakdep)
+#endif
+
+static int __init weakdep_init(void)
+{
+ return 0;
+}
+
+module_init(weakdep_init);
+
+MODULE_AUTHOR("Jose Ignacio Tornos Martinez <jtornosm@redhat.com>");
+MODULE_LICENSE("LGPL");
+MODULE_WEAKDEP("mod-simple");
--- /dev/null
+# Weak dependencies extracted from modules themselves.
+weakdep mod_weakdep mod-simple
--- /dev/null
+weakdep mod-loop-b mod-loop-a mod-simple
--- /dev/null
+# Aliases extracted from modules themselves.
--- /dev/null
+kernel/mod-loop-b.ko:
+kernel/mod-loop-a.ko:
+kernel/mod-simple.ko:
--- /dev/null
+# Device nodes to trigger on-demand module loading.
--- /dev/null
+# Soft dependencies extracted from modules themselves.
--- /dev/null
+# Aliases for symbols, used by symbol_request().
+alias symbol:printB mod_loop_b
+alias symbol:printA mod_loop_a
--- /dev/null
+# Weak dependencies extracted from modules themselves.
--- /dev/null
+mod-loop-b: mod_loop_a mod_simple
+mod-weakdep: mod_simple
--- /dev/null
+weakdep mod-loop-b mod-loop-a mod-simple
--- /dev/null
+# Aliases extracted from modules themselves.
--- /dev/null
+kernel/mod-weakdep.ko:
+kernel/mod-simple.ko:
+kernel/mod-loop-b.ko:
+kernel/mod-loop-a.ko: kernel/mod-loop-b.ko
--- /dev/null
+# Soft dependencies extracted from modules themselves.
--- /dev/null
+# Aliases for symbols, used by symbol_request().
+alias symbol:printB mod_loop_b
+alias symbol:printA mod_loop_a
--- /dev/null
+# Weak dependencies extracted from modules themselves.
+weakdep mod_weakdep mod-simple
["test-depmod/search-order-external-last/lib/modules/external/"]="mod-simple.ko"
["test-depmod/search-order-override$MODULE_DIRECTORY/4.4.4/foo/"]="mod-simple.ko"
["test-depmod/search-order-override$MODULE_DIRECTORY/4.4.4/override/"]="mod-simple.ko"
+ ["test-depmod/check-weakdep$MODULE_DIRECTORY/4.4.4/kernel/mod-weakdep.ko"]="mod-weakdep.ko"
+ ["test-depmod/check-weakdep$MODULE_DIRECTORY/4.4.4/kernel/mod-simple.ko"]="mod-simple.ko"
["test-dependencies$MODULE_DIRECTORY/4.0.20-kmod/kernel/fs/foo/"]="mod-foo-b.ko"
["test-dependencies$MODULE_DIRECTORY/4.0.20-kmod/kernel/"]="mod-foo-c.ko"
["test-dependencies$MODULE_DIRECTORY/4.0.20-kmod/kernel/lib/"]="mod-foo-a.ko"
["test-modprobe/show-exports/mod-loop-a.ko"]="mod-loop-a.ko"
["test-modprobe/softdep-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
["test-modprobe/softdep-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
+ ["test-modprobe/weakdep-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
+ ["test-modprobe/weakdep-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
+ ["test-modprobe/weakdep-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-simple.ko"]="mod-simple.ko"
["test-modprobe/install-cmd-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
["test-modprobe/install-cmd-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
["test-modprobe/force$MODULE_DIRECTORY/4.4.4/kernel/"]="mod-simple.ko"
["test-modinfo/mod-simple-sha256.ko"]="mod-simple.ko"
["test-modinfo/mod-simple-pkcs7.ko"]="mod-simple.ko"
["test-modinfo/external/lib/modules/external/mod-simple.ko"]="mod-simple.ko"
+ ["test-user$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
+ ["test-user$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
+ ["test-user$MODULE_DIRECTORY/4.4.4/kernel/mod-simple.ko"]="mod-simple.ko"
+ ["test-user$MODULE_DIRECTORY/4.4.4/kernel/mod-weakdep.ko"]="mod-weakdep.ko"
)
gzip_array=(
},
});
+#define CHECK_WEAKDEP_ROOTFS TESTSUITE_ROOTFS "test-depmod/check-weakdep"
+#define CHECK_WEAKDEP_LIB_MODULES CHECK_WEAKDEP_ROOTFS MODULE_DIRECTORY "/" MODULES_UNAME
+static noreturn int depmod_check_weakdep(const struct test *t)
+{
+ const char *progname = ABS_TOP_BUILDDIR "/tools/depmod";
+ const char *const args[] = {
+ progname,
+ NULL,
+ };
+
+ test_spawn_prog(progname, args);
+ exit(EXIT_FAILURE);
+}
+DEFINE_TEST(depmod_check_weakdep,
+ .description = "check weakdep output",
+ .config = {
+ [TC_UNAME_R] = MODULES_UNAME,
+ [TC_ROOTFS] = CHECK_WEAKDEP_ROOTFS,
+ },
+ .output = {
+ .files = (const struct keyval[]) {
+ { CHECK_WEAKDEP_LIB_MODULES "/correct-modules.weakdep",
+ CHECK_WEAKDEP_LIB_MODULES "/modules.weakdep" },
+ { }
+ },
+ });
+
TESTSUITE_MAIN();
.modules_loaded = "mod-loop-a,mod-loop-b",
);
+static noreturn int modprobe_weakdep_loop(const struct test *t)
+{
+ const char *progname = ABS_TOP_BUILDDIR "/tools/modprobe";
+ const char *const args[] = {
+ progname,
+ "mod-loop-b",
+ NULL,
+ };
+
+ test_spawn_prog(progname, args);
+ exit(EXIT_FAILURE);
+}
+DEFINE_TEST(modprobe_weakdep_loop,
+ .description = "check if modprobe breaks weakdep loop",
+ .config = {
+ [TC_UNAME_R] = "4.4.4",
+ [TC_ROOTFS] = TESTSUITE_ROOTFS "test-modprobe/weakdep-loop",
+ [TC_INIT_MODULE_RETCODES] = "",
+ },
+ .modules_loaded = "mod-loop-b",
+ .modules_not_loaded = "mod-loop-a,mod-simple-c",
+ );
+
static noreturn int modprobe_install_cmd_loop(const struct test *t)
{
const char *progname = ABS_TOP_BUILDDIR "/tools/modprobe";
--- /dev/null
+/*
+ * Copyright Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libkmod/libkmod.h>
+
+#include "testsuite.h"
+
+#define TEST_USER_ROOTFS TESTSUITE_ROOTFS "test-user/"
+#define TEST_USER_KERNEL_DIR TEST_USER_ROOTFS "lib/modules/4.4.4/"
+
+static const char *const test_user_config_paths[] = {
+ TEST_USER_ROOTFS "etc/modprobe.d",
+ NULL
+};
+
+static const char *const mod_name[] = {
+ "mod-loop-b",
+ "mod-weakdep",
+ NULL
+};
+
+static int test_user_weakdep(const struct test *t)
+{
+ struct kmod_ctx *ctx;
+ int mod_name_index = 0;
+ int err;
+
+ ctx = kmod_new(TEST_USER_KERNEL_DIR, test_user_config_paths);
+ if (ctx == NULL)
+ exit(EXIT_FAILURE);
+
+ while (mod_name[mod_name_index]) {
+ struct kmod_list *list = NULL;
+ struct kmod_module *mod = NULL;
+ struct kmod_list *mod_list = NULL;
+ struct kmod_list *itr = NULL;
+
+ printf("%s:", mod_name[mod_name_index]);
+ err = kmod_module_new_from_lookup(ctx, mod_name[mod_name_index], &list);
+ if (list == NULL || err < 0) {
+ fprintf(stderr, "module %s not found in directory %s\n",
+ mod_name[mod_name_index],
+ ctx ? kmod_get_dirname(ctx) : "(missing)");
+ exit(EXIT_FAILURE);
+ }
+
+ mod = kmod_module_get_module(list);
+
+ err = kmod_module_get_weakdeps(mod, &mod_list);
+ if (err) {
+ fprintf(stderr, "weak dependencies can not be read for %s (%d)\n",
+ mod_name[mod_name_index], err);
+ exit(EXIT_FAILURE);
+ }
+
+ kmod_list_foreach(itr, mod_list) {
+ struct kmod_module *weakdep_mod = kmod_module_get_module(itr);
+ const char *weakdep_name = kmod_module_get_name(weakdep_mod);
+
+ printf(" %s", weakdep_name);
+ kmod_module_unref(weakdep_mod);
+ }
+ printf("\n");
+
+ kmod_module_unref_list(mod_list);
+ kmod_module_unref(mod);
+ kmod_module_unref_list(list);
+
+ mod_name_index++;
+ }
+
+ kmod_unref(ctx);
+
+ return EXIT_SUCCESS;
+}
+DEFINE_TEST(test_user_weakdep,
+ .description = "check if modprobe breaks weakdep2",
+ .config = {
+ [TC_UNAME_R] = "4.4.4",
+ [TC_ROOTFS] = TESTSUITE_ROOTFS "test-user",
+ [TC_INIT_MODULE_RETCODES] = "",
+ },
+ .need_spawn = true,
+ .output = {
+ .out = TESTSUITE_ROOTFS "test-user/correct-weakdep.txt",
+ });
+
+TESTSUITE_MAIN();
}
/*
- * Store the expected module names in buf and return a list of pointers to
- * them.
+ * Auxiliary function to store the module names in buf and return a list
+ * of pointers to them.
*/
-static const char **read_expected_modules(const struct test *t,
+static const char **read_modules(const char* modules,
char **buf, int *count)
{
const char **res;
int i;
char *p;
- if (t->modules_loaded[0] == '\0') {
- *count = 0;
- *buf = NULL;
- return NULL;
- }
- *buf = strdup(t->modules_loaded);
+
+ *buf = strdup(modules);
if (!*buf) {
*count = -1;
return NULL;
return res;
}
+/*
+ * Store the expected module names in buf and return a list of pointers to
+ * them.
+ */
+static const char **read_expected_modules(const struct test *t,
+ char **buf, int *count)
+{
+ if (t->modules_loaded[0] == '\0') {
+ *count = 0;
+ *buf = NULL;
+ return NULL;
+ }
+ return read_modules(t->modules_loaded, buf, count);
+}
+
+/*
+ * Store the unexpected module names in buf and return a list of pointers to
+ * them.
+ */
+static const char **read_unexpected_modules(const struct test *t,
+ char **buf, int *count)
+{
+ if (t->modules_not_loaded[0] == '\0') {
+ *count = 0;
+ *buf = NULL;
+ return NULL;
+ }
+ return read_modules(t->modules_not_loaded, buf, count);
+}
+
static char **read_loaded_modules(const struct test *t, char **buf, int *count)
{
char dirname[PATH_MAX];
return err;
}
+static int check_not_loaded_modules(const struct test *t)
+{
+ int l1, l2, i1, i2;
+ const char **a1;
+ char **a2;
+ char *buf1, *buf2;
+ int err = false;
+
+ a1 = read_unexpected_modules(t, &buf1, &l1);
+ if (l1 < 0)
+ return err;
+ a2 = read_loaded_modules(t, &buf2, &l2);
+ if (l2 < 0)
+ goto out_a1;
+ qsort(a1, l1, sizeof(char *), cmp_modnames);
+ qsort(a2, l2, sizeof(char *), cmp_modnames);
+ i1 = i2 = 0;
+ err = true;
+ while (i1 < l1 || i2 < l2) {
+ int cmp;
+
+ if (i1 >= l1)
+ cmp = 1;
+ else if (i2 >= l2)
+ cmp = -1;
+ else
+ cmp = cmp_modnames(&a1[i1], &a2[i2]);
+ if (cmp == 0) {
+ err = false;
+ ERR("module %s loaded\n", a1[i1]);
+ i1++;
+ } else if (cmp < 0) {
+ i1++;
+ i2++;
+ } else {
+ err = false;
+ ERR("module %s is loaded but should not be\n", a2[i2]);
+ i2++;
+ }
+ }
+ free(a2);
+ free(buf2);
+out_a1:
+ free(a1);
+ free(buf1);
+ return err;
+}
+
static inline int test_run_parent(const struct test *t, int fdout[2],
int fderr[2], int fdmonitor[2], pid_t child)
{
match_modules = check_loaded_modules(t);
else
match_modules = true;
+ if (match_modules && t->modules_not_loaded)
+ match_modules = check_not_loaded_modules(t);
if (t->expected_fail == false) {
if (err == 0) {
} output;
/* comma-separated list of loaded modules at the end of the test */
const char *modules_loaded;
+ const char *modules_not_loaded;
testfunc func;
const char *config[_TC_LAST];
const char *path;