summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/kdbus/kdbus-test.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/selftests/kdbus/kdbus-test.c')
-rw-r--r--tools/testing/selftests/kdbus/kdbus-test.c899
1 files changed, 899 insertions, 0 deletions
diff --git a/tools/testing/selftests/kdbus/kdbus-test.c b/tools/testing/selftests/kdbus/kdbus-test.c
new file mode 100644
index 000000000..db732e596
--- /dev/null
+++ b/tools/testing/selftests/kdbus/kdbus-test.c
@@ -0,0 +1,899 @@
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <assert.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+#include <sys/syscall.h>
+#include <sys/eventfd.h>
+#include <linux/sched.h>
+
+#include "kdbus-util.h"
+#include "kdbus-enum.h"
+#include "kdbus-test.h"
+
+enum {
+ TEST_CREATE_BUS = 1 << 0,
+ TEST_CREATE_CONN = 1 << 1,
+};
+
+struct kdbus_test {
+ const char *name;
+ const char *desc;
+ int (*func)(struct kdbus_test_env *env);
+ unsigned int flags;
+};
+
+struct kdbus_test_args {
+ bool mntns;
+ bool pidns;
+ bool userns;
+ char *uid_map;
+ char *gid_map;
+ int loop;
+ int wait;
+ int fork;
+ int tap_output;
+ char *module;
+ char *root;
+ char *test;
+ char *busname;
+};
+
+static const struct kdbus_test tests[] = {
+ {
+ .name = "bus-make",
+ .desc = "bus make functions",
+ .func = kdbus_test_bus_make,
+ .flags = 0,
+ },
+ {
+ .name = "hello",
+ .desc = "the HELLO command",
+ .func = kdbus_test_hello,
+ .flags = TEST_CREATE_BUS,
+ },
+ {
+ .name = "byebye",
+ .desc = "the BYEBYE command",
+ .func = kdbus_test_byebye,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "chat",
+ .desc = "a chat pattern",
+ .func = kdbus_test_chat,
+ .flags = TEST_CREATE_BUS,
+ },
+ {
+ .name = "daemon",
+ .desc = "a simple daemon",
+ .func = kdbus_test_daemon,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "fd-passing",
+ .desc = "file descriptor passing",
+ .func = kdbus_test_fd_passing,
+ .flags = TEST_CREATE_BUS,
+ },
+ {
+ .name = "endpoint",
+ .desc = "custom endpoint",
+ .func = kdbus_test_custom_endpoint,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "monitor",
+ .desc = "monitor functionality",
+ .func = kdbus_test_monitor,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "name-basics",
+ .desc = "basic name registry functions",
+ .func = kdbus_test_name_basic,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "name-conflict",
+ .desc = "name registry conflict details",
+ .func = kdbus_test_name_conflict,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "name-queue",
+ .desc = "queuing of names",
+ .func = kdbus_test_name_queue,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "message-basic",
+ .desc = "basic message handling",
+ .func = kdbus_test_message_basic,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "message-prio",
+ .desc = "handling of messages with priority",
+ .func = kdbus_test_message_prio,
+ .flags = TEST_CREATE_BUS,
+ },
+ {
+ .name = "message-quota",
+ .desc = "message quotas are enforced",
+ .func = kdbus_test_message_quota,
+ .flags = TEST_CREATE_BUS,
+ },
+ {
+ .name = "memory-access",
+ .desc = "memory access",
+ .func = kdbus_test_memory_access,
+ .flags = TEST_CREATE_BUS,
+ },
+ {
+ .name = "timeout",
+ .desc = "timeout",
+ .func = kdbus_test_timeout,
+ .flags = TEST_CREATE_BUS,
+ },
+ {
+ .name = "sync-byebye",
+ .desc = "synchronous replies vs. BYEBYE",
+ .func = kdbus_test_sync_byebye,
+ .flags = TEST_CREATE_BUS,
+ },
+ {
+ .name = "sync-reply",
+ .desc = "synchronous replies",
+ .func = kdbus_test_sync_reply,
+ .flags = TEST_CREATE_BUS,
+ },
+ {
+ .name = "message-free",
+ .desc = "freeing of memory",
+ .func = kdbus_test_free,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "connection-info",
+ .desc = "retrieving connection information",
+ .func = kdbus_test_conn_info,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "connection-update",
+ .desc = "updating connection information",
+ .func = kdbus_test_conn_update,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "writable-pool",
+ .desc = "verifying pools are never writable",
+ .func = kdbus_test_writable_pool,
+ .flags = TEST_CREATE_BUS,
+ },
+ {
+ .name = "policy",
+ .desc = "policy",
+ .func = kdbus_test_policy,
+ .flags = TEST_CREATE_BUS,
+ },
+ {
+ .name = "policy-priv",
+ .desc = "unprivileged bus access",
+ .func = kdbus_test_policy_priv,
+ .flags = TEST_CREATE_BUS,
+ },
+ {
+ .name = "policy-ns",
+ .desc = "policy in user namespaces",
+ .func = kdbus_test_policy_ns,
+ .flags = TEST_CREATE_BUS,
+ },
+ {
+ .name = "metadata-ns",
+ .desc = "metadata in different namespaces",
+ .func = kdbus_test_metadata_ns,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "match-id-add",
+ .desc = "adding of matches by id",
+ .func = kdbus_test_match_id_add,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "match-id-remove",
+ .desc = "removing of matches by id",
+ .func = kdbus_test_match_id_remove,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "match-replace",
+ .desc = "replace of matches with the same cookie",
+ .func = kdbus_test_match_replace,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "match-name-add",
+ .desc = "adding of matches by name",
+ .func = kdbus_test_match_name_add,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "match-name-remove",
+ .desc = "removing of matches by name",
+ .func = kdbus_test_match_name_remove,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "match-name-change",
+ .desc = "matching for name changes",
+ .func = kdbus_test_match_name_change,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "match-bloom",
+ .desc = "matching with bloom filters",
+ .func = kdbus_test_match_bloom,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "activator",
+ .desc = "activator connections",
+ .func = kdbus_test_activator,
+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN,
+ },
+ {
+ .name = "benchmark",
+ .desc = "benchmark",
+ .func = kdbus_test_benchmark,
+ .flags = TEST_CREATE_BUS,
+ },
+ {
+ .name = "benchmark-nomemfds",
+ .desc = "benchmark without using memfds",
+ .func = kdbus_test_benchmark_nomemfds,
+ .flags = TEST_CREATE_BUS,
+ },
+ {
+ .name = "benchmark-uds",
+ .desc = "benchmark comparison to UDS",
+ .func = kdbus_test_benchmark_uds,
+ .flags = TEST_CREATE_BUS,
+ },
+};
+
+#define N_TESTS ((int) (sizeof(tests) / sizeof(tests[0])))
+
+static int test_prepare_env(const struct kdbus_test *t,
+ const struct kdbus_test_args *args,
+ struct kdbus_test_env *env)
+{
+ if (t->flags & TEST_CREATE_BUS) {
+ char *s;
+ char *n = NULL;
+ int ret;
+
+ asprintf(&s, "%s/control", args->root);
+
+ env->control_fd = open(s, O_RDWR);
+ free(s);
+ ASSERT_RETURN(env->control_fd >= 0);
+
+ if (!args->busname) {
+ n = unique_name("test-bus");
+ ASSERT_RETURN(n);
+ }
+
+ ret = kdbus_create_bus(env->control_fd,
+ args->busname ?: n,
+ _KDBUS_ATTACH_ALL, &s);
+ free(n);
+ ASSERT_RETURN(ret == 0);
+
+ asprintf(&env->buspath, "%s/%s/bus", args->root, s);
+ free(s);
+ }
+
+ if (t->flags & TEST_CREATE_CONN) {
+ env->conn = kdbus_hello(env->buspath, 0, NULL, 0);
+ ASSERT_RETURN(env->conn);
+ }
+
+ env->root = args->root;
+ env->module = args->module;
+
+ return 0;
+}
+
+void test_unprepare_env(const struct kdbus_test *t, struct kdbus_test_env *env)
+{
+ if (env->conn) {
+ kdbus_conn_free(env->conn);
+ env->conn = NULL;
+ }
+
+ if (env->control_fd >= 0) {
+ close(env->control_fd);
+ env->control_fd = -1;
+ }
+
+ if (env->buspath) {
+ free(env->buspath);
+ env->buspath = NULL;
+ }
+}
+
+static int test_run(const struct kdbus_test *t,
+ const struct kdbus_test_args *kdbus_args,
+ int wait)
+{
+ int ret;
+ struct kdbus_test_env env = {};
+
+ ret = test_prepare_env(t, kdbus_args, &env);
+ if (ret != TEST_OK)
+ return ret;
+
+ if (wait > 0) {
+ printf("Sleeping %d seconds before running test ...\n", wait);
+ sleep(wait);
+ }
+
+ ret = t->func(&env);
+ test_unprepare_env(t, &env);
+ return ret;
+}
+
+static int test_run_forked(const struct kdbus_test *t,
+ const struct kdbus_test_args *kdbus_args,
+ int wait)
+{
+ int ret;
+ pid_t pid;
+
+ pid = fork();
+ if (pid < 0) {
+ return TEST_ERR;
+ } else if (pid == 0) {
+ ret = test_run(t, kdbus_args, wait);
+ _exit(ret);
+ }
+
+ pid = waitpid(pid, &ret, 0);
+ if (pid <= 0)
+ return TEST_ERR;
+ else if (!WIFEXITED(ret))
+ return TEST_ERR;
+ else
+ return WEXITSTATUS(ret);
+}
+
+static void print_test_result(int ret)
+{
+ switch (ret) {
+ case TEST_OK:
+ printf("OK");
+ break;
+ case TEST_SKIP:
+ printf("SKIPPED");
+ break;
+ case TEST_ERR:
+ printf("ERROR");
+ break;
+ }
+}
+
+static int start_all_tests(struct kdbus_test_args *kdbus_args)
+{
+ int ret;
+ unsigned int fail_cnt = 0;
+ unsigned int skip_cnt = 0;
+ unsigned int ok_cnt = 0;
+ unsigned int i;
+
+ if (kdbus_args->tap_output) {
+ printf("1..%d\n", N_TESTS);
+ fflush(stdout);
+ }
+
+ kdbus_util_verbose = false;
+
+ for (i = 0; i < N_TESTS; i++) {
+ const struct kdbus_test *t = tests + i;
+
+ if (!kdbus_args->tap_output) {
+ unsigned int n;
+
+ printf("Testing %s (%s) ", t->desc, t->name);
+ for (n = 0; n < 60 - strlen(t->desc) - strlen(t->name); n++)
+ printf(".");
+ printf(" ");
+ }
+
+ ret = test_run_forked(t, kdbus_args, 0);
+ switch (ret) {
+ case TEST_OK:
+ ok_cnt++;
+ break;
+ case TEST_SKIP:
+ skip_cnt++;
+ break;
+ case TEST_ERR:
+ fail_cnt++;
+ break;
+ }
+
+ if (kdbus_args->tap_output) {
+ printf("%sok %d - %s%s (%s)\n",
+ (ret == TEST_ERR) ? "not " : "", i + 1,
+ (ret == TEST_SKIP) ? "# SKIP " : "",
+ t->desc, t->name);
+ fflush(stdout);
+ } else {
+ print_test_result(ret);
+ printf("\n");
+ }
+ }
+
+ if (kdbus_args->tap_output)
+ printf("Failed %d/%d tests, %.2f%% okay\n", fail_cnt, N_TESTS,
+ 100.0 - (fail_cnt * 100.0) / ((float) N_TESTS));
+ else
+ printf("\nSUMMARY: %u tests passed, %u skipped, %u failed\n",
+ ok_cnt, skip_cnt, fail_cnt);
+
+ return fail_cnt > 0 ? TEST_ERR : TEST_OK;
+}
+
+static int start_one_test(struct kdbus_test_args *kdbus_args)
+{
+ int i, ret;
+ bool test_found = false;
+
+ for (i = 0; i < N_TESTS; i++) {
+ const struct kdbus_test *t = tests + i;
+
+ if (strcmp(t->name, kdbus_args->test))
+ continue;
+
+ do {
+ test_found = true;
+ if (kdbus_args->fork)
+ ret = test_run_forked(t, kdbus_args,
+ kdbus_args->wait);
+ else
+ ret = test_run(t, kdbus_args,
+ kdbus_args->wait);
+
+ printf("Testing %s: ", t->desc);
+ print_test_result(ret);
+ printf("\n");
+
+ if (ret != TEST_OK)
+ break;
+ } while (kdbus_args->loop);
+
+ return ret;
+ }
+
+ if (!test_found) {
+ printf("Unknown test-id '%s'\n", kdbus_args->test);
+ return TEST_ERR;
+ }
+
+ return TEST_OK;
+}
+
+static void usage(const char *argv0)
+{
+ unsigned int i, j;
+
+ printf("Usage: %s [options]\n"
+ "Options:\n"
+ "\t-a, --tap Output test results in TAP format\n"
+ "\t-m, --module <module> Kdbus module name\n"
+ "\t-x, --loop Run in a loop\n"
+ "\t-f, --fork Fork before running a test\n"
+ "\t-h, --help Print this help\n"
+ "\t-r, --root <root> Toplevel of the kdbus hierarchy\n"
+ "\t-t, --test <test-id> Run one specific test only, in verbose mode\n"
+ "\t-b, --bus <busname> Instead of generating a random bus name, take <busname>.\n"
+ "\t-w, --wait <secs> Wait <secs> before actually starting test\n"
+ "\t --mntns New mount namespace\n"
+ "\t --pidns New PID namespace\n"
+ "\t --userns New user namespace\n"
+ "\t --uidmap uid_map UID map for user namespace\n"
+ "\t --gidmap gid_map GID map for user namespace\n"
+ "\n", argv0);
+
+ printf("By default, all test are run once, and a summary is printed.\n"
+ "Available tests for --test:\n\n");
+
+ for (i = 0; i < N_TESTS; i++) {
+ const struct kdbus_test *t = tests + i;
+
+ printf("\t%s", t->name);
+
+ for (j = 0; j < 24 - strlen(t->name); j++)
+ printf(" ");
+
+ printf("Test %s\n", t->desc);
+ }
+
+ printf("\n");
+ printf("Note that some tests may, if run specifically by --test, "
+ "behave differently, and not terminate by themselves.\n");
+
+ exit(EXIT_FAILURE);
+}
+
+void print_kdbus_test_args(struct kdbus_test_args *args)
+{
+ if (args->userns || args->pidns || args->mntns)
+ printf("# Starting tests in new %s%s%s namespaces%s\n",
+ args->mntns ? "MOUNT " : "",
+ args->pidns ? "PID " : "",
+ args->userns ? "USER " : "",
+ args->mntns ? ", kdbusfs will be remounted" : "");
+ else
+ printf("# Starting tests in the same namespaces\n");
+}
+
+void print_metadata_support(void)
+{
+ bool no_meta_audit, no_meta_cgroups, no_meta_seclabel;
+
+ /*
+ * KDBUS_ATTACH_CGROUP, KDBUS_ATTACH_AUDIT and
+ * KDBUS_ATTACH_SECLABEL
+ */
+ no_meta_audit = !config_auditsyscall_is_enabled();
+ no_meta_cgroups = !config_cgroups_is_enabled();
+ no_meta_seclabel = !config_security_is_enabled();
+
+ if (no_meta_audit | no_meta_cgroups | no_meta_seclabel)
+ printf("# Starting tests without %s%s%s metadata support\n",
+ no_meta_audit ? "AUDIT " : "",
+ no_meta_cgroups ? "CGROUP " : "",
+ no_meta_seclabel ? "SECLABEL " : "");
+ else
+ printf("# Starting tests with full metadata support\n");
+}
+
+int run_tests(struct kdbus_test_args *kdbus_args)
+{
+ int ret;
+ static char control[4096];
+
+ snprintf(control, sizeof(control), "%s/control", kdbus_args->root);
+
+ if (access(control, W_OK) < 0) {
+ printf("Unable to locate control node at '%s'.\n",
+ control);
+ return TEST_ERR;
+ }
+
+ if (kdbus_args->test) {
+ ret = start_one_test(kdbus_args);
+ } else {
+ do {
+ ret = start_all_tests(kdbus_args);
+ if (ret != TEST_OK)
+ break;
+ } while (kdbus_args->loop);
+ }
+
+ return ret;
+}
+
+static void nop_handler(int sig) {}
+
+static int test_prepare_mounts(struct kdbus_test_args *kdbus_args)
+{
+ int ret;
+ char kdbusfs[64] = {'\0'};
+
+ snprintf(kdbusfs, sizeof(kdbusfs), "%sfs", kdbus_args->module);
+
+ /* make current mount slave */
+ ret = mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL);
+ if (ret < 0) {
+ ret = -errno;
+ printf("error mount() root: %d (%m)\n", ret);
+ return ret;
+ }
+
+ /* Remount procfs since we need it in our tests */
+ if (kdbus_args->pidns) {
+ ret = mount("proc", "/proc", "proc",
+ MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL);
+ if (ret < 0) {
+ ret = -errno;
+ printf("error mount() /proc : %d (%m)\n", ret);
+ return ret;
+ }
+ }
+
+ /* Remount kdbusfs */
+ ret = mount(kdbusfs, kdbus_args->root, kdbusfs,
+ MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL);
+ if (ret < 0) {
+ ret = -errno;
+ printf("error mount() %s :%d (%m)\n", kdbusfs, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int run_tests_in_namespaces(struct kdbus_test_args *kdbus_args)
+{
+ int ret;
+ int efd = -1;
+ int status;
+ pid_t pid, rpid;
+ struct sigaction oldsa;
+ struct sigaction sa = {
+ .sa_handler = nop_handler,
+ .sa_flags = SA_NOCLDSTOP,
+ };
+
+ efd = eventfd(0, EFD_CLOEXEC);
+ if (efd < 0) {
+ ret = -errno;
+ printf("eventfd() failed: %d (%m)\n", ret);
+ return TEST_ERR;
+ }
+
+ ret = sigaction(SIGCHLD, &sa, &oldsa);
+ if (ret < 0) {
+ ret = -errno;
+ printf("sigaction() failed: %d (%m)\n", ret);
+ return TEST_ERR;
+ }
+
+ /* setup namespaces */
+ pid = syscall(__NR_clone, SIGCHLD|
+ (kdbus_args->userns ? CLONE_NEWUSER : 0) |
+ (kdbus_args->mntns ? CLONE_NEWNS : 0) |
+ (kdbus_args->pidns ? CLONE_NEWPID : 0), NULL);
+ if (pid < 0) {
+ printf("clone() failed: %d (%m)\n", -errno);
+ return TEST_ERR;
+ }
+
+ if (pid == 0) {
+ eventfd_t event_status = 0;
+
+ ret = prctl(PR_SET_PDEATHSIG, SIGKILL);
+ if (ret < 0) {
+ ret = -errno;
+ printf("error prctl(): %d (%m)\n", ret);
+ _exit(TEST_ERR);
+ }
+
+ /* reset sighandlers of childs */
+ ret = sigaction(SIGCHLD, &oldsa, NULL);
+ if (ret < 0) {
+ ret = -errno;
+ printf("sigaction() failed: %d (%m)\n", ret);
+ _exit(TEST_ERR);
+ }
+
+ ret = eventfd_read(efd, &event_status);
+ if (ret < 0 || event_status != 1) {
+ printf("error eventfd_read()\n");
+ _exit(TEST_ERR);
+ }
+
+ if (kdbus_args->mntns) {
+ ret = test_prepare_mounts(kdbus_args);
+ if (ret < 0) {
+ printf("error preparing mounts\n");
+ _exit(TEST_ERR);
+ }
+ }
+
+ ret = run_tests(kdbus_args);
+ _exit(ret);
+ }
+
+ /* Setup userns mapping */
+ if (kdbus_args->userns) {
+ ret = userns_map_uid_gid(pid, kdbus_args->uid_map,
+ kdbus_args->gid_map);
+ if (ret < 0) {
+ printf("error mapping uid and gid in userns\n");
+ eventfd_write(efd, 2);
+ return TEST_ERR;
+ }
+ }
+
+ ret = eventfd_write(efd, 1);
+ if (ret < 0) {
+ ret = -errno;
+ printf("error eventfd_write(): %d (%m)\n", ret);
+ return TEST_ERR;
+ }
+
+ rpid = waitpid(pid, &status, 0);
+ ASSERT_RETURN_VAL(rpid == pid, TEST_ERR);
+
+ close(efd);
+
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ return TEST_ERR;
+
+ return TEST_OK;
+}
+
+int start_tests(struct kdbus_test_args *kdbus_args)
+{
+ int ret;
+ bool namespaces;
+ static char fspath[4096];
+
+ namespaces = (kdbus_args->mntns || kdbus_args->pidns ||
+ kdbus_args->userns);
+
+ /* for pidns we need mntns set */
+ if (kdbus_args->pidns && !kdbus_args->mntns) {
+ printf("Failed: please set both pid and mnt namesapces\n");
+ return TEST_ERR;
+ }
+
+ if (kdbus_args->userns) {
+ if (!config_user_ns_is_enabled()) {
+ printf("User namespace not supported\n");
+ return TEST_ERR;
+ }
+
+ if (!kdbus_args->uid_map || !kdbus_args->gid_map) {
+ printf("Failed: please specify uid or gid mapping\n");
+ return TEST_ERR;
+ }
+ }
+
+ print_kdbus_test_args(kdbus_args);
+ print_metadata_support();
+
+ /* setup kdbus paths */
+ if (!kdbus_args->module)
+ kdbus_args->module = "kdbus";
+
+ if (!kdbus_args->root) {
+ snprintf(fspath, sizeof(fspath), "/sys/fs/%s",
+ kdbus_args->module);
+ kdbus_args->root = fspath;
+ }
+
+ /* Start tests */
+ if (namespaces)
+ ret = run_tests_in_namespaces(kdbus_args);
+ else
+ ret = run_tests(kdbus_args);
+
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int t, ret = 0;
+ struct kdbus_test_args *kdbus_args;
+ enum {
+ ARG_MNTNS = 0x100,
+ ARG_PIDNS,
+ ARG_USERNS,
+ ARG_UIDMAP,
+ ARG_GIDMAP,
+ };
+
+ kdbus_args = malloc(sizeof(*kdbus_args));
+ if (!kdbus_args) {
+ printf("unable to malloc() kdbus_args\n");
+ return EXIT_FAILURE;
+ }
+
+ memset(kdbus_args, 0, sizeof(*kdbus_args));
+
+ static const struct option options[] = {
+ { "loop", no_argument, NULL, 'x' },
+ { "help", no_argument, NULL, 'h' },
+ { "root", required_argument, NULL, 'r' },
+ { "test", required_argument, NULL, 't' },
+ { "bus", required_argument, NULL, 'b' },
+ { "wait", required_argument, NULL, 'w' },
+ { "fork", no_argument, NULL, 'f' },
+ { "module", required_argument, NULL, 'm' },
+ { "tap", no_argument, NULL, 'a' },
+ { "mntns", no_argument, NULL, ARG_MNTNS },
+ { "pidns", no_argument, NULL, ARG_PIDNS },
+ { "userns", no_argument, NULL, ARG_USERNS },
+ { "uidmap", required_argument, NULL, ARG_UIDMAP },
+ { "gidmap", required_argument, NULL, ARG_GIDMAP },
+ {}
+ };
+
+ srand(time(NULL));
+
+ while ((t = getopt_long(argc, argv, "hxfm:r:t:b:w:a", options, NULL)) >= 0) {
+ switch (t) {
+ case 'x':
+ kdbus_args->loop = 1;
+ break;
+
+ case 'm':
+ kdbus_args->module = optarg;
+ break;
+
+ case 'r':
+ kdbus_args->root = optarg;
+ break;
+
+ case 't':
+ kdbus_args->test = optarg;
+ break;
+
+ case 'b':
+ kdbus_args->busname = optarg;
+ break;
+
+ case 'w':
+ kdbus_args->wait = strtol(optarg, NULL, 10);
+ break;
+
+ case 'f':
+ kdbus_args->fork = 1;
+ break;
+
+ case 'a':
+ kdbus_args->tap_output = 1;
+ break;
+
+ case ARG_MNTNS:
+ kdbus_args->mntns = true;
+ break;
+
+ case ARG_PIDNS:
+ kdbus_args->pidns = true;
+ break;
+
+ case ARG_USERNS:
+ kdbus_args->userns = true;
+ break;
+
+ case ARG_UIDMAP:
+ kdbus_args->uid_map = optarg;
+ break;
+
+ case ARG_GIDMAP:
+ kdbus_args->gid_map = optarg;
+ break;
+
+ default:
+ case 'h':
+ usage(argv[0]);
+ }
+ }
+
+ ret = start_tests(kdbus_args);
+ if (ret == TEST_ERR)
+ return EXIT_FAILURE;
+
+ free(kdbus_args);
+
+ return 0;
+}