Removed test-runner.c, and renamed py_runner to test-runner. Removed
tools/test-runner from .gitignore.
This was done as a separate commit to avoid a nasty diff between the
existing test runner, and the new python version
---
.gitignore | 1 -
Makefile.am | 7 -
tools/{py_runner.py => test-runner} | 0
tools/test-runner.c | 3310 ---------------------------
4 files changed, 3318 deletions(-)
rename tools/{py_runner.py => test-runner} (100%)
delete mode 100644 tools/test-runner.c
diff --git a/.gitignore b/.gitignore
index 93fec4f7..33405af8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,7 +33,6 @@ wired/ead.8
wired/ead.service
tools/hwsim
tools/hwsim.1
-tools/test-runner
tools/probe-req
unit/test-cmac-aes
unit/test-arc4
diff --git a/Makefile.am b/Makefile.am
index e83dbeee..5f16920f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -366,13 +366,6 @@ man_MANS += tools/hwsim.1
endif
endif
-if TOOLS
-noinst_PROGRAMS += tools/test-runner
-
-tools_test_runner_SOURCES = tools/test-runner.c
-tools_test_runner_LDADD = $(ell_ldadd)
-endif
-
unit_tests = unit/test-cmac-aes \
unit/test-hmac-md5 unit/test-hmac-sha1 unit/test-hmac-sha256 \
unit/test-prf-sha1 unit/test-kdf-sha256 \
diff --git a/tools/py_runner.py b/tools/test-runner
similarity index 100%
rename from tools/py_runner.py
rename to tools/test-runner
diff --git a/tools/test-runner.c b/tools/test-runner.c
deleted file mode 100644
index 40148241..00000000
--- a/tools/test-runner.c
+++ /dev/null
@@ -1,3310 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2012-2019 Intel Corporation. All rights reserved.
- *
- *
- * This library 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 library 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <string.h>
-#include <getopt.h>
-#include <poll.h>
-#include <dirent.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/mount.h>
-#include <sys/param.h>
-#include <sys/reboot.h>
-#include <sys/time.h>
-#include <glob.h>
-#include <time.h>
-#include <ell/ell.h>
-
-#include "linux/nl80211.h"
-
-#ifndef WAIT_ANY
-#define WAIT_ANY (-1)
-#endif
-
-#define CMDLINE_MAX 2048
-
-#define BIN_IW "iw"
-#define BIN_HWSIM "hwsim"
-#define BIN_OFONO "ofonod"
-#define BIN_PHONESIM "phonesim"
-#define BIN_HOSTAPD "hostapd"
-#define BIN_IWD "iwd"
-
-#define HWSIM_RADIOS_MAX 100
-#define TEST_MAX_EXEC_TIME_SEC 20
-
-static enum action {
- ACTION_AUTO_TEST,
- ACTION_UNIT_TEST,
-} test_action;
-
-static const char *own_binary;
-static char **test_argv;
-static int test_argc;
-static char **verbose_apps;
-static char *verbose_opt;
-static bool valgrind;
-static char *gdb_opt;
-static bool enable_debug;
-const char *debug_filter;
-static struct l_settings *hw_config;
-static bool native_hw;
-static bool shell;
-static bool log;
-static char log_dir[PATH_MAX];
-static uid_t log_uid;
-static gid_t log_gid;
-static const char *qemu_binary;
-static const char *kernel_image;
-static const char *exec_home;
-static const char *test_action_params;
-static char top_level_path[PATH_MAX];
-static struct l_queue *wiphy_list;
-
-#if defined(__i386__)
-/*
- * If iwd is being compiled for i386, prefer the i386 qemu but try the
- * X86-64 version as a fallback.
- */
-static const char * const qemu_table[] = {
- "qemu-system-i386",
- "/usr/bin/qemu-system-i386",
- "qemu-system-x86_64",
- "/usr/bin/qemu-system-x86_64",
- NULL
-};
-#elif defined(__x86_64__)
-/*
- * If iwd is being built for X86-64 bits there's no point booting a 32-bit
- * only system.
- */
-static const char * const qemu_table[] = {
- "qemu-system-x86_64",
- "/usr/bin/qemu-system-x86_64",
- NULL
-};
-#elif defined(__arm__)
-/*
- * If iwd is being built for ARM look for 32-bit version.
- */
-static const char * const qemu_table[] = {
- "qemu-system-arm",
- "/usr/bin/qemu-system-arm",
- NULL
-};
-#elif defined(__aarch64__)
-/*
- * If iwd is being built for AARCH64 look for 64-bit version.
- */
-static const char * const qemu_table[] = {
- "qemu-system-aarch64",
- "/usr/bin/qemu-system-aarch64",
- NULL
-};
-#elif defined(__powerpc__)
-/*
- * If iwd is being built for PowerPC look for 32-bit version.
- */
-static const char * const qemu_table[] = {
- "qemu-system-ppc",
- "/usr/bin/qemu-system-ppc",
- NULL
-};
-#elif defined(__powerpc64__)
-/*
- * If iwd is being built for PowerPC-64 look for 64-bit version.
- */
-static const char * const qemu_table[] = {
- "qemu-system-ppc64",
- "/usr/bin/qemu-system-ppc64",
- NULL
-};
-#else
-#warning Qemu binary name not defined for this architecture yet
-static const char * const qemu_table[] = { NULL };
-#endif
-
-struct wiphy {
- char name[20];
- int id;
- unsigned int interface_index;
- bool interface_created : 1;
- bool used_by_hostapd : 1;
- char *interface_name;
- char *hostapd_ctrl_interface;
- char *hostapd_config;
- bool can_ap;
-};
-
-static bool check_verbosity(const char *app)
-{
- char **apps = verbose_apps;
-
- /*
- * All processes are verbose if logging is enabled. Kernel is a bit
- * different as we just pipe dmesg into a log file at the end of
- * execution.
- */
- if (log && strcmp(app, "kernel") != 0)
- return true;
-
- /*
- * Turn on output if this is a unit test run. Nothing should output
- * anything except the tests themselves and the kernel.
- */
- if (test_action == ACTION_UNIT_TEST && strcmp(app, "kernel") != 0)
- return true;
-
- if (!apps)
- return false;
-
- while (*apps) {
- if (!strcmp(app, *apps))
- return true;
-
- apps++;
- }
-
- return false;
-}
-
-static bool path_exist(const char *path_name)
-{
- struct stat st;
-
- if (!stat(path_name, &st))
- return true;
-
- return false;
-}
-
-static const char *find_qemu(void)
-{
- int i;
-
- for (i = 0; qemu_table[i]; i++)
- if (path_exist(qemu_table[i]))
- return qemu_table[i];
-
- return NULL;
-}
-
-static const char * const kernel_table[] = {
- "bzImage",
- "arch/x86/boot/bzImage",
- "vmlinux",
- "arch/x86/boot/vmlinux",
- NULL
-};
-
-static const char *find_kernel(void)
-{
- int i;
-
- for (i = 0; kernel_table[i]; i++)
- if (path_exist(kernel_table[i]))
- return kernel_table[i];
-
- return NULL;
-}
-
-static const struct {
- const char *target;
- const char *linkpath;
-} dev_table[] = {
- { "/proc/self/fd", "/dev/fd" },
- { "/proc/self/fd/0", "/dev/stdin" },
- { "/proc/self/fd/1", "/dev/stdout" },
- { "/proc/self/fd/2", "/dev/stderr" },
- { }
-};
-
-static const struct {
- const char *fstype;
- const char *target;
- const char *options;
- unsigned long flags;
-} mount_table[] = {
- { "sysfs", "/sys", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV
},
- { "proc", "/proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV
},
- { "devpts", "/dev/pts", "mode=0620", MS_NOSUID|MS_NOEXEC
},
- { "tmpfs", "/dev/shm", "mode=1777",
- MS_NOSUID|MS_NODEV|MS_STRICTATIME },
- { "tmpfs", "/run", "mode=0755",
- MS_NOSUID|MS_NODEV|MS_STRICTATIME },
- { "tmpfs", "/var/lib/iwd", "mode=0755", 0 },
- { "tmpfs", "/tmp", NULL, 0 },
- { "debugfs", "/sys/kernel/debug", NULL, 0 },
- { }
-};
-
-static const char * const config_table[] = {
- "/usr/share/dbus-1",
- NULL
-};
-
-static void prepare_sandbox(void)
-{
- int i;
-
- for (i = 0; mount_table[i].fstype; i++) {
- struct stat st;
-
- if (lstat(mount_table[i].target, &st) < 0) {
- mkdir(mount_table[i].target, 0755);
- }
-
- if (mount(mount_table[i].fstype,
- mount_table[i].target,
- mount_table[i].fstype,
- mount_table[i].flags,
- mount_table[i].options) < 0) {
- l_error("Error: Failed to mount filesystem %s",
- mount_table[i].target);
- }
- }
-
- for (i = 0; dev_table[i].target; i++) {
-
- if (symlink(dev_table[i].target, dev_table[i].linkpath) < 0)
- l_error("Failed to create device symlink: %s",
- strerror(errno));
- }
-
- setsid();
-
- ioctl(STDIN_FILENO, TIOCSCTTY, 1);
-
- for (i = 0; config_table[i]; i++) {
- if (mount("tmpfs", config_table[i], "tmpfs",
- MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
- "mode=0755") < 0)
- l_error("Failed to create filesystem: %s",
- strerror(errno));
- }
-}
-
-static char *const qemu_argv[] = {
- "",
- "-machine", "type=q35,accel=kvm:tcg",
- "-nodefaults",
- "-no-user-config",
- "-monitor", "none",
- "-display", "none",
- "-m", "192M",
- "-nographic",
- "-vga", "none",
- "-net", "none",
- "-no-acpi",
- "-no-hpet",
- "-no-reboot",
- "-fsdev",
"local,id=fsdev-root,path=/,readonly,security_model=none",
- "-device", "virtio-9p-pci,fsdev=fsdev-root,mount_tag=/dev/root",
- "-chardev", "stdio,id=chardev-serial0,signal=off",
- "-device", "pci-serial,chardev=chardev-serial0",
- "-device", "virtio-rng-pci",
- NULL
-};
-
-static char *const qemu_envp[] = {
- "HOME=/",
- NULL
-};
-
-static bool check_virtualization(void)
-{
-#if defined(__GNUC__) && (defined(__i386__) || defined(__amd64__))
- uint32_t ecx;
-
- __asm__ __volatile__("cpuid" : "=c" (ecx) :
- "a" (1) : "%ebx", "%edx");
-
- if (!!(ecx & (1 << 5))) {
- l_info("Found support for Virtual Machine eXtensions");
- return true;
- }
-
- __asm__ __volatile__("cpuid" : "=c" (ecx) :
- "a" (0x80000001) : "%ebx", "%edx");
-
- if (ecx & (1 << 2)) {
- l_info("Found support for Secure Virtual Machine extension");
- return true;
- }
-#endif
- return false;
-}
-
-static bool start_qemu(void)
-{
- char cwd[PATH_MAX], testargs[PATH_MAX];
- char *initcmd, *cmdline;
- char **argv;
- int i, pos;
- bool has_virt;
- int num_pci = 0, num_usb = 0;
- char **pci_keys = NULL;
- char **usb_keys = NULL;
- L_AUTO_FREE_VAR(char *, log_option) = NULL;
-
- has_virt = check_virtualization();
-
- if (!getcwd(cwd, sizeof(cwd)))
- strcat(cwd, "/");
-
- if (own_binary[0] == '/')
- initcmd = l_strdup_printf("%s", own_binary);
- else
- initcmd = l_strdup_printf("%s/%s", cwd, own_binary);
-
- pos = snprintf(testargs, sizeof(testargs), "%s", test_argv[0]);
-
- for (i = 1; i < test_argc; i++) {
- int len;
-
- len = sizeof(testargs) - pos;
- pos += snprintf(testargs + pos, len, " %s", test_argv[i]);
- }
-
- cmdline = l_strdup_printf(
- "console=ttyS0,115200n8 earlyprintk=serial "
- "rootfstype=9p "
- "root=/dev/root "
- "rootflags=trans=virtio,version=9p2000.u "
- "acpi=off pci=noacpi noapic %s ro "
- "mac80211_hwsim.radios=0 init=%s TESTHOME=%s "
- "TESTVERBOUT=\'%s\' DEBUG_FILTER=\'%s\'"
- "TEST_ACTION=%u TEST_ACTION_PARAMS=\'%s\' "
- "TESTARGS=\'%s\' PATH=\'%s\' VALGRIND=%u "
- "GDB=\'%s\' HW=\'%s\' SHELL=%u "
- "LOG_PATH=\'%s\' LOG_UID=\'%d\' LOG_GID=\'%d\'",
- check_verbosity("kernel") ? "ignore_loglevel" :
"quiet",
- initcmd, cwd, verbose_opt ? verbose_opt : "none",
- enable_debug ? debug_filter : "",
- test_action,
- test_action_params ? test_action_params : "",
- testargs,
- getenv("PATH"),
- valgrind,
- gdb_opt ? gdb_opt : "none",
- hw_config ? "real" : "virtual",
- shell,
- log ? log_dir : "none",
- log_uid, log_gid);
-
- if (hw_config) {
- if (l_settings_has_group(hw_config, "PCIAdapters")) {
- pci_keys = l_settings_get_keys(hw_config, "PCIAdapters");
-
- for (num_pci = 0; pci_keys[num_pci]; num_pci++);
- }
-
- if (l_settings_has_group(hw_config, "USBAdapters")) {
- usb_keys = l_settings_get_keys(hw_config, "USBAdapters");
-
- for (num_usb = 0; usb_keys[num_usb]; num_usb++);
- }
-
- if (!pci_keys && !usb_keys) {
- l_error("hs config had no PCIAdapters or USBAdapters");
- l_free(initcmd);
- l_free(cmdline);
- return false;
- }
- }
-
- /*
- * This got quite confusing. We need enough room for:
- *
- * qemu_argv (static list above with default parameters)
- * -kernel,-append,-cpu,-host parameters (7)
- * -enable-kvm and/or -usb (2)
- * PCI and/or USB parameters (num_pci * 2) (num_usb * 2)
- * Logging directory/device (2)
- */
- argv = alloca(sizeof(qemu_argv) + sizeof(char *) *
- (7 + (2 + (num_pci * 2) + (num_usb * 2) + 2)));
- memcpy(argv, qemu_argv, sizeof(qemu_argv));
-
- pos = (sizeof(qemu_argv) / sizeof(char *)) - 1;
-
- argv[0] = (char *) qemu_binary;
-
- argv[pos++] = "-kernel";
- argv[pos++] = (char *) kernel_image;
- argv[pos++] = "-append";
- argv[pos++] = (char *) cmdline;
- argv[pos++] = "-cpu";
- argv[pos++] = has_virt ? "host" : "max";
-
- if (pci_keys) {
- argv[pos++] = "-enable-kvm";
- for (i = 0; pci_keys[i]; i++) {
- argv[pos++] = "-device";
- argv[pos] = alloca(22);
- sprintf(argv[pos], "vfio-pci,host=%s",
- l_settings_get_value(hw_config,
- "PCIAdapters", pci_keys[i]));
- pos++;
- }
- }
-
- if (usb_keys) {
- argv[pos++] = "-usb";
- for (i = 0; usb_keys[i]; i++) {
- const char *value = l_settings_get_value(hw_config,
- "USBAdapters", usb_keys[i]);
- char **info = l_strsplit(value, ',');
-
- if (l_strv_length(info) != 2) {
- l_error("hw config formatting error");
- l_strv_free(info);
- return false;
- }
-
- argv[pos++] = "-device";
- argv[pos] = alloca(32);
- sprintf(argv[pos], "usb-host,hostbus=%s,hostaddr=%s",
- info[0], info[1]);
- pos++;
-
- l_strv_free(info);
- }
- }
-
- if (log) {
- /*
- * Create a virtfs device and tag it. This allows the guest to
- * mount 'logdir' in the path specified with --log.
- */
- log_option = l_strdup_printf("local,path=%s,mount_tag=logdir,"
- "security_model=passthrough,id=logdir",
- log_dir);
- argv[pos++] = "-virtfs";
- argv[pos++] = log_option;
- }
-
- argv[pos] = NULL;
-
- execve(argv[0], argv, qemu_envp);
-
- /* Don't expect to reach here */
- free(initcmd);
- free(cmdline);
-
- return true;
-}
-
-static pid_t execute_program(char *argv[], char *envp[], bool wait,
- const char *test_name)
-{
- int status;
- pid_t pid, child_pid;
- char *str;
- bool verbose;
- char *log_name = argv[0];
-
- if (!argv[0])
- return -1;
-
- /*
- * We have a few special cases here:
- *
- * Since execute_program automatically logs to <process>.log this would
- * put all iwd output into valgrind.log rather than iwd.log. Since we
- * are explicitly having valgrind output to a log file we can assume any
- * output from this is only IWD, and not valgrind.
- *
- * python3 is special cased so that tests which start IWD manually can
- * still show IWD output when using -v iwd.
- */
- if (!strcmp(log_name, "valgrind") || !strcmp(log_name, "python3"))
- log_name = "iwd";
-
- str = l_strjoinv(argv, ' ');
- l_debug("Executing: %s", str);
- l_free(str);
-
- child_pid = fork();
- if (child_pid < 0) {
- l_error("Failed to fork new process");
- return -1;
- }
-
- if (child_pid == 0) {
- int fd = -1;
- L_AUTO_FREE_VAR(char *, log_file) = NULL;
-
- verbose = check_verbosity(log_name);
-
- /* No stdout and no logging */
- if (!verbose && !log)
- fd = open("/dev/null", O_WRONLY);
- else if (log && verbose) {
- /*
- * Create the log file for this process. If no test name
- * was specified this is a 'global' process (only run
- * once, not per-test).
- */
- if (test_name) {
- log_file = l_strdup_printf("%s/%s/%s.log",
- log_dir, test_name, log_name);
- } else
- log_file = l_strdup_printf("%s/%s.log",
- log_dir, log_name);
-
- fd = open(log_file, O_WRONLY | O_CREAT | O_APPEND,
- S_IRUSR | S_IWUSR);
- if (fchown(fd, log_uid, log_gid) < 0)
- l_error("failed to fchown %s", log_file);
- }
-
- if (fd > -1) {
- dup2(fd, 1);
- dup2(fd, 2);
-
- close(fd);
- }
-
- execvpe(argv[0], argv, envp);
-
- l_error("Failed to call execvpe for: %s. Error: %s", argv[0],
- strerror(errno));
-
- exit(EXIT_FAILURE);
- }
-
- if (!wait)
- goto exit;
-
- do {
- pid = waitpid(child_pid, &status, 0);
- } while (!WIFEXITED(status) && pid == child_pid);
-
- if (WEXITSTATUS(status) != EXIT_SUCCESS)
- return -1;
-
-exit:
- return child_pid;
-}
-
-static void kill_process(pid_t pid)
-{
- int status;
- int i = 0;
-
- l_debug("Terminate pid: %d", pid);
-
- kill(pid, SIGTERM);
-
- do {
- if (waitpid(pid, &status, WNOHANG) == pid)
- return;
-
- usleep(100000);
- } while (!WIFEXITED(status) && !WIFSIGNALED(status) && i++ < 20);
-
- l_error("Failed to kill process %d gracefully", pid);
- kill(pid, SIGKILL);
-
- /* SIGKILL shouldn't need WNOHANG */
- waitpid(pid, &status, 0);
-}
-
-static bool wait_for_socket(const char *socket, useconds_t wait_time)
-{
- int i = 0;
-
- do {
- if (path_exist(socket))
- return true;
-
- usleep(wait_time);
- } while ((wait_time > 0) ? i++ < 20 : true);
-
- l_error("Error: cannot find socket: %s", socket);
- return false;
-}
-
-static void create_dbus_system_conf(void)
-{
- FILE *fp;
-
- fp = fopen("/usr/share/dbus-1/system.conf", "we");
- if (!fp)
- return;
-
- fputs("<!DOCTYPE busconfig PUBLIC ", fp);
- fputs("\"-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN\" ",
fp);
-
fputs("\"http://www.freedesktop.org/standards/dbus/1.0/", fp);
- fputs("busconfig.dtd\">\n", fp);
- fputs("<busconfig>\n", fp);
- fputs("<type>system</type>\n", fp);
- fputs("<listen>unix:path=/run/dbus/system_bus_socket</listen>\n",
fp);
- fputs("<limit
name=\"reply_timeout\">2147483647</limit>", fp);
- fputs("<auth>ANONYMOUS</auth>\n", fp);
- fputs("<allow_anonymous/>\n", fp);
- fputs("<policy context=\"default\">\n", fp);
- fputs("<allow user=\"*\"/>\n", fp);
- fputs("<allow own=\"*\"/>\n", fp);
- fputs("<allow send_type=\"method_call\"/>\n", fp);
- fputs("<allow send_type=\"signal\"/>\n", fp);
- fputs("<allow send_type=\"method_return\"/>\n", fp);
- fputs("<allow send_type=\"error\"/>\n", fp);
- fputs("<allow receive_type=\"method_call\"/>\n", fp);
- fputs("<allow receive_type=\"signal\"/>\n", fp);
- fputs("<allow receive_type=\"method_return\"/>\n", fp);
- fputs("<allow receive_type=\"error\"/>\n", fp);
- fputs("</policy>\n", fp);
- fputs("</busconfig>\n", fp);
-
- fclose(fp);
-
- mkdir("/run/dbus", 0755);
-}
-
-static bool start_dbus_daemon(void)
-{
- char *argv[4];
- pid_t pid;
-
- argv[0] = "dbus-daemon";
- argv[1] = "--system";
- argv[2] = "--nosyslog";
- argv[3] = NULL;
-
- if (check_verbosity("dbus"))
- setenv("DBUS_VERBOSE", "1", true);
-
- pid = execute_program(argv, environ, false, NULL);
- if (pid < 0)
- return false;
-
- if (!wait_for_socket("/run/dbus/system_bus_socket", 25 * 10000))
- return false;
-
- if (check_verbosity("dbus-monitor")) {
- argv[0] = "dbus-monitor";
- argv[1] = "--system";
- argv[2] = NULL;
- execute_program(argv, environ, false, NULL);
- }
-
- l_debug("D-Bus is running");
-
- return true;
-}
-
-static bool start_haveged(void)
-{
- char *argv[2];
- pid_t pid;
-
- argv[0] = "haveged";
- argv[1] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return false;
-
- return true;
-}
-
-static bool set_interface_state(const char *if_name, bool isUp)
-{
- char *state, *argv[4];
- pid_t pid;
-
- if (isUp)
- state = "up";
- else
- state = "down";
-
- argv[0] = "ifconfig";
- argv[1] = (char *) if_name;
- argv[2] = state;
- argv[3] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return false;
-
- return true;
-}
-
-static bool create_interface(const char *if_name, const char *phy_name)
-{
- char *argv[9];
- pid_t pid;
-
- argv[0] = BIN_IW;
- argv[1] = "phy";
- argv[2] = (char *) phy_name;
- argv[3] = "interface";
- argv[4] = "add";
- argv[5] = (char *) if_name;
- argv[6] = "type";
- argv[7] = "managed";
- argv[8] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return false;
-
- return true;
-}
-
-static bool delete_interface(const char *if_name)
-{
- char *argv[5];
- pid_t pid;
-
- argv[0] = BIN_IW;
- argv[1] = "dev";
- argv[2] = (char *) if_name;
- argv[3] = "del";
- argv[4] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return false;
-
- return true;
-}
-
-static bool list_interfaces(void)
-{
- char *argv[3];
- pid_t pid;
-
- argv[0] = "ifconfig";
- argv[1] = "-a";
- argv[2] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return false;
-
- return true;
-}
-
-static bool list_hwsim_radios(void)
-{
- char *argv[3];
- pid_t pid;
-
- argv[0] = BIN_HWSIM;
- argv[1] = "--list";
- argv[2] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return false;
-
- return true;
-}
-
-static int read_radio_id(void)
-{
- static int current_radio_id;
-
- return current_radio_id++;
-}
-
-struct hwsim_radio_params {
- unsigned int channels;
- bool p2p_device;
- bool use_chanctx;
- char *iftype_disable;
- char *cipher_disable;
-};
-
-static int create_hwsim_radio(const char *radio_name,
- struct hwsim_radio_params *params)
-{
- char *argv[10];
- pid_t pid;
- int idx = 0;
-
- /*TODO add the rest of params*/
- argv[idx++] = BIN_HWSIM;
- argv[idx++] = "--create";
- argv[idx++] = "--name";
- argv[idx++] = (char *) radio_name;
- argv[idx++] = "--nointerface";
-
- if (params->iftype_disable) {
- argv[idx++] = "--iftype-disable";
- argv[idx++] = params->iftype_disable;
- }
-
- if (params->cipher_disable) {
- argv[idx++] = "--cipher-disable";
- argv[idx++] = params->cipher_disable;
- }
-
- argv[idx] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return -1;
-
- return read_radio_id();
-}
-
-static bool destroy_hwsim_radio(int radio_id)
-{
- char *argv[4];
- char destroy_param[20];
- pid_t pid;
-
- sprintf(destroy_param, "--destroy=%d", radio_id);
-
- argv[0] = BIN_HWSIM;
- argv[1] = destroy_param;
- argv[2] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return false;
-
- return true;
-}
-
-static pid_t register_hwsim_as_trans_medium(void)
-{
- char *argv[16];
- unsigned int idx = 0;
-
- if (strcmp(gdb_opt, "hwsim") == 0) {
- argv[idx++] = "gdb";
- argv[idx++] = "--args";
- }
-
- argv[idx++] = BIN_HWSIM;
- argv[idx++] = NULL;
-
- return execute_program(argv, environ, false, NULL);
-}
-
-static void terminate_medium(pid_t medium_pid)
-{
- kill_process(medium_pid);
-}
-
-#define HOSTAPD_CTRL_INTERFACE_PREFIX "/var/run/hostapd"
-
-static bool loopback_started;
-
-static void start_loopback(void)
-{
- char *argv[7];
-
- if (loopback_started)
- return;
-
- argv[0] = "ifconfig";
- argv[1] = "lo";
- argv[2] = "127.0.0.1";
- argv[3] = "up";
- argv[4] = NULL;
- execute_program(argv, environ, false, NULL);
-
- argv[0] = "route";
- argv[1] = "add";
- argv[2] = "127.0.0.1";
- argv[3] = NULL;
- execute_program(argv, environ, false, NULL);
-
- loopback_started = true;
-}
-
-static pid_t start_phonesim(const char *test_name)
-{
- char *argv[5];
-
- argv[0] = BIN_PHONESIM;
- argv[1] = "-p";
- argv[2] = "12345";
- argv[3] = "/usr/share/phonesim/default.xml";
- argv[4] = NULL;
-
- start_loopback();
-
- setenv("OFONO_PHONESIM_CONFIG", "/tmp/phonesim.conf", true);
-
- return execute_program(argv, environ, false, test_name);
-}
-
-static void stop_phonesim(pid_t pid)
-{
- kill_process(pid);
-}
-
-static pid_t start_ofono(const char *test_name)
-{
- char *argv[5];
- bool verbose = check_verbosity(BIN_OFONO);
-
- argv[0] = BIN_OFONO;
- argv[1] = "-n";
- argv[2] = "--plugin=atmodem,phonesim";
-
- if (verbose)
- argv[3] = "-d";
- else
- argv[3] = NULL;
-
- argv[4] = NULL;
-
- start_loopback();
-
- return execute_program(argv, environ, false, test_name);
-}
-
-static void stop_ofono(pid_t pid)
-{
- kill_process(pid);
-}
-
-static pid_t start_hostapd(char **config_files, struct wiphy **wiphys,
- const char *test_name, const char *radius_conf)
-{
- char **argv;
- pid_t pid;
- int idx = 0;
- uint32_t wait = 25 * 10000;
- bool verbose = check_verbosity(BIN_HOSTAPD);
- size_t ifnames_size;
- char *ifnames;
- int i;
-
- for (i = 0, ifnames_size = 0; wiphys[i]; i++)
- ifnames_size += 1 + strlen(wiphys[i]->interface_name);
-
- argv = alloca(sizeof(char *) * (9 + i));
-
- if (strcmp(gdb_opt, "hostapd") == 0) {
- argv[idx++] = "gdb";
- argv[idx++] = "--args";
- wait = 0;
- }
-
- argv[idx++] = BIN_HOSTAPD;
-
- ifnames = alloca(ifnames_size);
- argv[idx++] = "-i";
- argv[idx++] = ifnames;
-
- argv[idx++] = "-g";
- argv[idx++] = wiphys[0]->hostapd_ctrl_interface;
-
- for (i = 0, ifnames_size = 0; wiphys[i]; i++) {
- if (ifnames_size)
- ifnames[ifnames_size++] = ',';
- strcpy(ifnames + ifnames_size, wiphys[i]->interface_name);
- ifnames_size += strlen(wiphys[i]->interface_name);
-
- argv[idx++] = config_files[i];
- }
-
- if (radius_conf)
- argv[idx++] = (void *)radius_conf;
-
- if (verbose) {
- argv[idx++] = "-d";
- argv[idx++] = NULL;
- } else {
- argv[idx++] = NULL;
- }
-
- pid = execute_program(argv, environ, false, log ? test_name : NULL);
- if (pid < 0) {
- goto exit;
- }
-
- if (!wait_for_socket(wiphys[0]->hostapd_ctrl_interface, wait))
- pid = -1;
-exit:
- return pid;
-}
-
-static void destroy_hostapd_instances(pid_t hostapd_pids[])
-{
- int i = 0;
-
- while (hostapd_pids[i] != -1) {
- kill_process(hostapd_pids[i]);
-
- l_debug("hostapd instance with pid=%d is destroyed",
- hostapd_pids[i]);
-
- hostapd_pids[i] = -1;
-
- i++;
- }
-}
-
-#define TEST_TOP_DIR_DEFAULT_NAME "autotests"
-#define TEST_DIR_PREFIX "test"
-
-static bool is_test_file(const char *file)
-{
- size_t i;
- static const char * const test_file_extension_table[] = {
- "test",
- "test.py",
- "Test",
- "Test.py",
- NULL
- };
-
- for (i = 0; test_file_extension_table[i]; i++) {
- if (l_str_has_suffix(file, test_file_extension_table[i]))
- return true;
- }
-
- return false;
-}
-
-static int is_test_dir(const char *dir)
-{
- return strncmp(dir, TEST_DIR_PREFIX, strlen(TEST_DIR_PREFIX)) == 0;
-}
-
-static bool find_test_configuration(const char *path, int level,
- struct l_queue *config_queue);
-
-struct test_entry {
- struct l_queue *test_queue;
- char *path;
-};
-
-static int insert_py_test(const void *a, const void *b, void *user_data)
-{
- return strcmp((const char *)a, (const char *)b);
-}
-
-static int insert_test_entry(const void *a, const void *b, void *user_data)
-{
- const struct test_entry *entry_a = a;
- const struct test_entry *entry_b = b;
-
- return strcmp(entry_a->path, entry_b->path);
-}
-
-static bool add_path(const char *path, int level, struct l_queue *config_queue)
-{
- DIR *dir = NULL;
- struct l_queue *py_test_queue = NULL;
- struct dirent *entry;
- char *npath;
-
- dir = opendir(path);
- if (!dir) {
- l_error("Test directory does not exist: %s", path);
- return false;
- }
-
- while ((entry = readdir(dir))) {
- if (entry->d_type == DT_DIR) {
- if (!strcmp(entry->d_name, ".") ||
- !strcmp(entry->d_name, ".."))
- continue;
-
- if (level == 0 && is_test_dir(entry->d_name)) {
- npath = l_strdup_printf("%s/%s", path,
- entry->d_name);
-
- find_test_configuration(npath, 1, config_queue);
-
- l_free(npath);
- }
- } else if (level == 1 && is_test_file(entry->d_name)) {
- if (!py_test_queue)
- py_test_queue = l_queue_new();
-
- l_queue_insert(py_test_queue, l_strdup(entry->d_name),
- insert_py_test, NULL);
- }
- }
-
- if (py_test_queue && !l_queue_isempty(py_test_queue)) {
- struct test_entry *entry = l_new(struct test_entry, 1);
-
- entry->test_queue = py_test_queue;
- entry->path = l_strdup(path);
-
- l_queue_insert(config_queue, entry, insert_test_entry, NULL);
- }
-
- closedir(dir);
- return true;
-}
-
-static bool find_test_configuration(const char *path, int level,
- struct l_queue *config_queue)
-{
- glob_t glist;
- int i = 0;
- int ret;
-
- if (!config_queue)
- return false;
-
- ret = glob(path, 0, NULL, &glist);
- if (ret != 0) {
- l_error("Could not match glob %s", path);
- return false;
- }
-
- while (glist.gl_pathv[i]) {
- if (!add_path(glist.gl_pathv[i], level, config_queue))
- return false;
-
- i++;
- }
-
- return true;
-}
-
-#define HW_CONFIG_FILE_NAME "hw.conf"
-#define HW_CONFIG_GROUP_HOSTAPD "HOSTAPD"
-#define HW_CONFIG_GROUP_SETUP "SETUP"
-
-#define HW_CONFIG_SETUP_NUM_RADIOS "num_radios"
-#define HW_CONFIG_SETUP_RADIO_CONFS "radio_confs"
-#define HW_CONFIG_SETUP_MAX_EXEC_SEC "max_test_exec_interval_sec"
-#define HW_CONFIG_SETUP_TMPFS_EXTRAS "tmpfs_extra_stuff"
-#define HW_CONFIG_SETUP_START_IWD "start_iwd"
-#define HW_CONFIG_SETUP_IWD_CONF_DIR "iwd_config_dir"
-#define HW_CONFIG_SETUP_REG_DOMAIN "reg_domain"
-#define HW_CONFIG_SETUP_NEEDS_HWSIM "needs_hwsim"
-
-static struct l_settings *read_hw_config(const char *test_dir_path)
-{
- struct l_settings *hw_settings;
- char *hw_file;
-
- hw_file = l_strdup_printf("%s/%s", test_dir_path, HW_CONFIG_FILE_NAME);
-
- hw_settings = l_settings_new();
-
- if (!l_settings_load_from_file(hw_settings, hw_file)) {
- l_error("No %s file found", HW_CONFIG_FILE_NAME);
- goto error_exit;
- }
-
- if (!l_settings_has_group(hw_settings, HW_CONFIG_GROUP_SETUP)) {
- l_error("No %s setting group found in %s",
- HW_CONFIG_GROUP_SETUP, hw_file);
- goto error_exit;
- }
-
- l_free(hw_file);
- return hw_settings;
-
-error_exit:
- l_free(hw_file);
- l_settings_free(hw_settings);
- return NULL;
-}
-
-#define HW_CONFIG_PHY_CHANNELS "channels"
-#define HW_CONFIG_PHY_CHANCTX "use_chanctx"
-#define HW_CONFIG_PHY_P2P "p2p_device"
-#define HW_CONFIG_PHY_IFTYPE_DISABLE "iftype_disable"
-#define HW_CONFIG_PHY_CIPHER_DISABLE "cipher_disable"
-
-#define HW_MIN_NUM_RADIOS 1
-
-#define HW_INTERFACE_PREFIX "wln"
-#define HW_INTERFACE_STATE_UP true
-#define HW_INTERFACE_STATE_DOWN false
-
-static bool configure_hw_radios(struct l_settings *hw_settings,
- struct l_queue *wiphy_list)
-{
- char **radio_conf_list;
- int i, num_radios_requested;
- bool status = false;
-
- l_settings_get_int(hw_settings, HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_NUM_RADIOS,
- &num_radios_requested);
-
- if (num_radios_requested < HW_MIN_NUM_RADIOS) {
- l_error("%s must be greater or equal to %d",
- HW_CONFIG_SETUP_NUM_RADIOS, HW_MIN_NUM_RADIOS);
- return false;
- }
-
- radio_conf_list =
- l_settings_get_string_list(hw_settings, HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_RADIO_CONFS,
- ':');
- for (i = 0; i < num_radios_requested; i++) {
- struct wiphy *wiphy;
- struct hwsim_radio_params params = { 0 };
-
- wiphy = l_new(struct wiphy, 1);
-
- sprintf(wiphy->name, "rad%d", i);
-
- /* radio not in radio_confs, use default parameters */
- if (!l_strv_contains(radio_conf_list, wiphy->name)) {
- params.channels = 1;
- params.p2p_device = true;
- params.use_chanctx = true;
- goto create;
- }
-
- if (!l_settings_get_uint(hw_settings, wiphy->name,
- HW_CONFIG_PHY_CHANNELS,
- ¶ms.channels))
- params.channels = 1;
-
- if (!l_settings_get_bool(hw_settings, wiphy->name,
- HW_CONFIG_PHY_P2P, ¶ms.p2p_device))
- params.p2p_device = true;
-
- if (!l_settings_get_bool(hw_settings, wiphy->name,
- HW_CONFIG_PHY_CHANCTX,
- ¶ms.use_chanctx))
- params.use_chanctx = true;
-
- params.iftype_disable = l_settings_get_string(hw_settings,
- wiphy->name,
- HW_CONFIG_PHY_IFTYPE_DISABLE);
- params.cipher_disable = l_settings_get_string(hw_settings,
- wiphy->name,
- HW_CONFIG_PHY_CIPHER_DISABLE);
-
-create:
- wiphy->id = create_hwsim_radio(wiphy->name, ¶ms);
- wiphy->can_ap = true;
-
- if (wiphy->id < 0) {
- l_free(wiphy);
- goto exit;
- }
-
- l_queue_push_tail(wiphy_list, wiphy);
- }
-
- status = true;
-
-exit:
- l_strfreev(radio_conf_list);
- return status;
-}
-
-static void wiphy_free(void *data)
-{
- struct wiphy *wiphy = data;
-
- if (wiphy->interface_created) {
- set_interface_state(wiphy->interface_name,
- HW_INTERFACE_STATE_DOWN);
-
- if (delete_interface(wiphy->interface_name))
- l_debug("Removed interface %s", wiphy->interface_name);
- else
- l_error("Failed to remove interface %s",
- wiphy->interface_name);
- }
-
- /* Native interfaces cannot be destroyed */
- if (native_hw) {
- set_interface_state(wiphy->interface_name,
- HW_INTERFACE_STATE_DOWN);
- } else {
- destroy_hwsim_radio(wiphy->id);
- l_debug("Removed radio id %d", wiphy->id);
- }
-
- l_free(wiphy->hostapd_config);
- l_free(wiphy->hostapd_ctrl_interface);
- l_free(wiphy->interface_name);
-
- l_free(wiphy);
-}
-
-static bool configure_hostapd_instances(struct l_settings *hw_settings,
- char *config_dir_path,
- struct l_queue *wiphy_list,
- pid_t hostapd_pids_out[],
- int *phys_used)
-{
- char **hostap_keys;
- int i;
- char **hostapd_config_file_paths;
- struct wiphy **wiphys;
- const char *radius_config = NULL;
-
- *phys_used = 0;
-
- if (!l_settings_has_group(hw_settings, HW_CONFIG_GROUP_HOSTAPD)) {
- l_info("No hostapd instances to create");
- return true;
- }
-
- hostap_keys =
- l_settings_get_keys(hw_settings, HW_CONFIG_GROUP_HOSTAPD);
-
- for (i = 0; hostap_keys[i]; i++);
-
- hostapd_config_file_paths = l_new(char *, i + 1);
- wiphys = alloca(sizeof(struct wiphy *) * (i + 1));
- memset(wiphys, 0, sizeof(struct wiphy *) * (i + 1));
-
- hostapd_pids_out[0] = -1;
-
- for (i = 0; hostap_keys[i]; i++) {
- const struct l_queue_entry *wiphy_entry;
- const char *hostapd_config_file;
- unsigned wiphy_idx = 0;
-
- hostapd_config_file =
- l_settings_get_value(hw_settings,
- HW_CONFIG_GROUP_HOSTAPD,
- hostap_keys[i]);
-
- hostapd_config_file_paths[i] =
- l_strdup_printf("%s/%s", config_dir_path,
- hostapd_config_file);
-
- if (!path_exist(hostapd_config_file_paths[i])) {
- l_error("%s : hostapd configuration file [%s] "
- "does not exist.", HW_CONFIG_FILE_NAME,
- hostapd_config_file_paths[i]);
- goto done;
- }
-
- if (!strcmp(hostap_keys[i], "radius_server")) {
- radius_config = l_settings_get_value(hw_settings,
- HW_CONFIG_GROUP_HOSTAPD,
- "radius_server");
- continue;
- }
-
- for (wiphy_entry = l_queue_get_entries(wiphy_list);
- wiphy_entry;
- wiphy_entry = wiphy_entry->next,
- wiphy_idx++) {
- struct wiphy *wiphy = wiphy_entry->data;
-
- /*
- * We can skip this check in native mode since we have
- * no control over the phy name. Any test requiring a
- * "special" radio should not be ran in native mode.
- */
- if (!native_hw && strcmp(wiphy->name, hostap_keys[i]))
- continue;
-
- if (wiphy->used_by_hostapd) {
- /*
- * Since we bypass the above check in native
- * mode we could still get here. We can just
- * continue searching for more adapters if this
- * one is already in use.
- */
- if (native_hw)
- continue;
-
- l_error("Wiphy %s already used by hostapd",
- wiphy->name);
- goto done;
- }
-
- if (!wiphy->can_ap)
- continue;
-
- wiphys[i] = wiphy;
- break;
- }
-
- if (!wiphy_entry) {
- l_error("Failed to find available wiphy.");
- goto done;
- }
-
- if (native_hw)
- goto hostapd_done;
-
- wiphys[i]->interface_name = l_strdup_printf("%s%d",
- HW_INTERFACE_PREFIX,
- wiphy_idx);
- if (!create_interface(wiphys[i]->interface_name,
- wiphys[i]->name)) {
- l_error("Failed to create hostapd interface %s on "
- "radio %s",
- wiphys[i]->interface_name, wiphys[i]->name);
- goto done;
- }
-
- wiphys[i]->interface_created = true;
- l_info("Created hostapd interface %s on %s radio",
- wiphys[i]->interface_name, wiphys[i]->name);
-
- if (!native_hw && !set_interface_state(wiphys[i]->interface_name,
- HW_INTERFACE_STATE_UP)) {
- l_error("Failed to set %s state UP",
- wiphys[i]->interface_name);
- goto done;
- }
-
-hostapd_done:
- wiphys[i]->used_by_hostapd = true;
- wiphys[i]->hostapd_ctrl_interface =
- l_strdup_printf("%s/%s", HOSTAPD_CTRL_INTERFACE_PREFIX,
- wiphys[0]->interface_name);
- wiphys[i]->hostapd_config = l_strdup(hostapd_config_file);
-
- (*phys_used)++;
- }
-
- hostapd_pids_out[0] = start_hostapd(hostapd_config_file_paths, wiphys,
- basename(config_dir_path),
- radius_config);
- hostapd_pids_out[1] = -1;
-
-done:
- l_strfreev(hostapd_config_file_paths);
-
- if (hostapd_pids_out[0] < 1)
- return false;
-
- return true;
-}
-
-static pid_t start_iwd(const char *config_dir, struct l_queue *wiphy_list,
- const char *ext_options, int num_phys, const char *test_name)
-{
- char *argv[13], **envp;
- char *iwd_phys = NULL;
- pid_t ret;
- int idx = 0;
- L_AUTO_FREE_VAR(char *, fd_option) = NULL;
-
- if (valgrind) {
- L_AUTO_FREE_VAR(char *, valgrind_log);
- int fd;
-
- argv[idx++] = "valgrind";
- argv[idx++] = "--leak-check=full";
-
- /*
- * Valgrind needs --log-fd if we want both stderr and stdout
- */
- if (log)
- valgrind_log = l_strdup_printf("%s/%s/valgrind.log",
- log_dir, test_name);
- else
- valgrind_log = l_strdup("/tmp/valgrind.log");
-
- fd = open(valgrind_log, O_WRONLY | O_CREAT | O_APPEND,
- S_IRUSR | S_IWUSR);
-
- if (log) {
- if (fchown(fd, log_uid, log_gid) < 0)
- l_error("chown failed");
- }
-
- fd_option = l_strdup_printf("--log-fd=%d", fd);
- argv[idx++] = fd_option;
- }
-
- if (strcmp(gdb_opt, "iwd") == 0) {
- argv[idx++] = "gdb";
- argv[idx++] = "--args";
- }
-
- argv[idx++] = BIN_IWD;
-
- if (check_verbosity(BIN_IWD) || shell)
- argv[idx++] = "-d";
-
- argv[idx] = NULL;
-
- if (wiphy_list) {
- const struct l_queue_entry *wiphy_entry;
- struct l_string *list = l_string_new(64);
-
- for (wiphy_entry = l_queue_get_entries(wiphy_list);
- wiphy_entry;
- wiphy_entry = wiphy_entry->next) {
- struct wiphy *wiphy = wiphy_entry->data;
-
- if (wiphy->used_by_hostapd)
- continue;
-
- /*
- * Break out, only adding the required number of phys
- * for this test.
- */
- if (num_phys == 0)
- break;
-
- l_string_append_printf(list, "%s,", wiphy->name);
-
- num_phys--;
- }
-
- iwd_phys = l_string_unwrap(list);
- /* Take care of last comma */
- iwd_phys[strlen(iwd_phys) - 1] = '\0';
-
- argv[idx++] = "-p";
- argv[idx++] = iwd_phys;
- argv[idx] = NULL;
- }
-
- argv[idx++] = (char *)ext_options;
- argv[idx] = NULL;
-
- envp = l_strv_copy(environ);
- envp = l_strv_append_printf(envp, "CONFIGURATION_DIRECTORY=%s",
- config_dir);
- envp = l_strv_append_printf(envp, "STATE_DIRECTORY=%s",
- DAEMON_STORAGEDIR);
-
- ret = execute_program(argv, envp, false, test_name);
-
- l_strv_free(envp);
-
- l_free(iwd_phys);
-
- return ret;
-}
-
-static void terminate_iwd(pid_t iwd_pid)
-{
- kill_process(iwd_pid);
-}
-
-static pid_t start_monitor(const char *test_name)
-{
- char *argv[6];
- char *write_arg;
- pid_t pid;
-
- write_arg = l_strdup_printf("%s/%s/monitor.pcap", log_dir, test_name);
-
- argv[0] = "iwmon";
- argv[1] = "--nortnl";
- argv[2] = "--nowiphy";
- argv[3] = "--write";
- argv[4] = write_arg;
- argv[5] = NULL;
-
- pid = execute_program(argv, environ, false, test_name);
-
- l_free(write_arg);
-
- return pid;
-}
-
-static bool create_tmpfs_extra_stuff(char **tmpfs_extra_stuff)
-{
- size_t i = 0;
-
- if (!tmpfs_extra_stuff)
- return true;
-
- while (tmpfs_extra_stuff[i]) {
- char *link_dir;
- char *target_dir;
-
- target_dir = realpath(tmpfs_extra_stuff[i], NULL);
-
- if (!path_exist(target_dir)) {
- l_error("No such directory: %s", target_dir);
- l_free(target_dir);
- return false;
- }
-
- link_dir = l_strdup_printf("%s%s", "/tmp",
- rindex(target_dir, '/'));
-
- if (symlink(target_dir, link_dir) < 0) {
- l_error("Failed to create symlink %s for %s: %s",
- link_dir, target_dir, strerror(errno));
-
- l_free(target_dir);
- l_free(link_dir);
- return false;
- }
-
- l_free(tmpfs_extra_stuff[i]);
- l_free(target_dir);
-
- tmpfs_extra_stuff[i] = link_dir;
- i++;
- }
-
- return true;
-}
-
-static bool remove_absolute_path_dirs(char **tmpfs_extra_stuff)
-{
- size_t i = 0;
-
- if (!tmpfs_extra_stuff)
- return true;
-
- while (tmpfs_extra_stuff[i]) {
- if (unlink(tmpfs_extra_stuff[i]) < 0) {
- l_error("Failed to remove symlink for %s: %s",
- tmpfs_extra_stuff[i], strerror(errno));
-
- return false;
- }
-
- i++;
- }
-
- return true;
-}
-
-#define CONSOLE_LN_DEFAULT "\x1B[0m"
-#define CONSOLE_LN_RED "\x1B[31m"
-#define CONSOLE_LN_GREEN "\x1B[32m"
-#define CONSOLE_LN_BLACK "\x1B[30m"
-#define CONSOLE_LN_YELLOW "\x1B[33m"
-#define CONSOLE_LN_RESET "\033[0m"
-
-#define CONSOLE_LN_BOLD "\x1b[1m"
-
-#define CONSOLE_BG_WHITE "\e[47m"
-#define CONSOLE_BG_DEFAULT "\e[0m"
-
-enum test_status {
- TEST_STATUS_STARTED,
- TEST_STATUS_PASSED,
- TEST_STATUS_FAILED,
- TEST_STATUS_TIMEDOUT,
-};
-
-static void print_test_status(char *test_name, enum test_status ts,
- double interval)
-{
- const char *clear_line = "\r";
- int int_len;
- char *color_str;
- char *status_str;
- char *interval_str;
- char *line_end = "";
-
- switch (ts) {
- case TEST_STATUS_STARTED:
- color_str = CONSOLE_LN_RESET;
- status_str = "STARTED ";
-
- if (strcmp(verbose_opt, "none"))
- line_end = "\n";
-
- break;
- case TEST_STATUS_PASSED:
- printf("%s", clear_line);
- color_str = CONSOLE_LN_GREEN;
- status_str = "PASSED ";
- line_end = "\n";
-
- break;
- case TEST_STATUS_FAILED:
- printf("%s", clear_line);
- color_str = CONSOLE_LN_RED;
- status_str = "FAILED ";
- line_end = "\n";
-
- break;
- case TEST_STATUS_TIMEDOUT:
- printf("%s", clear_line);
- color_str = CONSOLE_LN_YELLOW;
- status_str = "TIMED OUT ";
- line_end = "\n";
-
- break;
- }
-
- if (interval > 0)
- int_len = snprintf(NULL, 0, "%.3f", interval);
- else
- int_len = 3;
-
- int_len++;
-
- interval_str = l_malloc(int_len);
- memset(interval_str, ' ', int_len);
- interval_str[int_len - 1] = '\0';
-
- if (interval > 0)
- sprintf(interval_str, "%.3f sec", interval);
- else
- sprintf(interval_str, "%s", "...");
-
- printf("%s%s%s%-60s%7s%s", color_str, status_str, CONSOLE_LN_RESET,
- test_name, interval_str, line_end);
-
- fflush(stdout);
-
- l_free(interval_str);
-}
-
-static void test_timeout_timer_tick(struct l_timeout *timeout, void *user_data)
-{
- pid_t *test_exec_pid = (pid_t *) user_data;
-
- kill_process(*test_exec_pid);
-
- l_main_quit();
-}
-
-static void test_timeout_signal_handler(uint32_t signo, void *user_data)
-{
- switch (signo) {
- case SIGINT:
- case SIGTERM:
- l_main_quit();
- break;
- }
-}
-
-static pid_t start_execution_timeout_timer(unsigned int max_exec_interval_sec,
- pid_t *test_exec_pid)
-{
- struct l_timeout *test_exec_timeout;
- pid_t test_timer_pid;
-
- test_timer_pid = fork();
- if (test_timer_pid < 0) {
- l_error("Failed to fork new process");
- return -1;
- }
-
- if (test_timer_pid == 0) {
- if (!l_main_init())
- exit(EXIT_FAILURE);
-
- test_exec_timeout =
- l_timeout_create(max_exec_interval_sec,
- test_timeout_timer_tick,
- test_exec_pid,
- NULL);
-
- l_main_run_with_signal(test_timeout_signal_handler, NULL);
-
- l_timeout_remove(test_exec_timeout);
-
- l_main_exit();
-
- exit(EXIT_SUCCESS);
- }
-
- return test_timer_pid;
-}
-
-struct test_stats {
- char *config_cycle_name;
- unsigned int num_passed;
- unsigned int num_failed;
- unsigned int num_timedout;
- double py_run_time;
-};
-
-static void run_py_tests(struct l_settings *hw_settings,
- struct l_queue *test_queue,
- struct l_queue *test_stats_queue,
- const char *test_name)
-{
- char *argv[3];
- pid_t test_exec_pid, test_timer_pid = -1;
- struct timeval time_before, time_after, time_elapsed;
- unsigned int max_exec_interval;
- char *py_test = NULL;
- struct test_stats *test_stats;
- pid_t monitor_pid = -1;
-
- if (!l_settings_get_uint(hw_settings, HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_MAX_EXEC_SEC,
- &max_exec_interval))
- max_exec_interval = TEST_MAX_EXEC_TIME_SEC;
-
- l_info(CONSOLE_LN_BOLD "%-10s%-60s%s" CONSOLE_LN_RESET, "Status",
- "Test", "Duration");
-
-start_next_test:
-
- if (l_queue_isempty(test_queue))
- return;
-
- py_test = (char *) l_queue_pop_head(test_queue);
- if (!py_test)
- return;
-
- if (log) {
- char *test_path;
- char *ext;
- char *full_path;
-
- test_path = l_strdup_printf("%s/%s", test_name, py_test);
- ext = strchr(test_path, '.');
- ext[0] = '\0';
-
- full_path = l_strdup_printf("%s/%s", log_dir, test_path);
-
- mkdir(full_path, 0755);
- if (chown(full_path, log_uid, log_gid) < 0)
- l_error("chown failed %s", full_path);
-
- l_free(full_path);
-
- monitor_pid = start_monitor(test_path);
-
- l_free(test_path);
- }
-
- argv[0] = "python3";
- argv[1] = py_test;
- argv[2] = NULL;
-
- print_test_status(py_test, TEST_STATUS_STARTED, 0);
- test_exec_pid = execute_program(argv, environ, false, test_name);
-
- gettimeofday(&time_before, NULL);
-
- if (!strcmp(gdb_opt, "none"))
- test_timer_pid = start_execution_timeout_timer(
- max_exec_interval, &test_exec_pid);
-
- test_stats = (struct test_stats *) l_queue_peek_tail(test_stats_queue);
-
- while (true) {
- pid_t corpse;
- int status;
- double interval;
-
- corpse = waitpid(WAIT_ANY, &status, 0);
-
- if (corpse < 0 || corpse == 0)
- continue;
-
- if (test_exec_pid == corpse) {
- gettimeofday(&time_after, NULL);
-
- if (test_timer_pid != -1)
- kill_process(test_timer_pid);
-
- timersub(&time_after, &time_before, &time_elapsed);
- interval = time_elapsed.tv_sec +
- 1e-6 * time_elapsed.tv_usec;
-
- if (WIFEXITED(status) &&
- WEXITSTATUS(status) == EXIT_SUCCESS) {
- print_test_status(py_test, TEST_STATUS_PASSED,
- interval);
- test_stats->num_passed++;
- } else if (WIFSIGNALED(status)) {
- print_test_status(py_test, TEST_STATUS_TIMEDOUT,
- interval);
- test_stats->num_timedout++;
- } else {
- print_test_status(py_test, TEST_STATUS_FAILED,
- interval);
- test_stats->num_failed++;
- }
-
- test_stats->py_run_time += interval;
-
- break;
- } else if (WIFSTOPPED(status))
- l_info("Process %d stopped with signal %d", corpse,
- WSTOPSIG(status));
- else if (WIFCONTINUED(status))
- l_info("Process %d continued", corpse);
- }
-
- l_free(py_test);
- py_test = NULL;
-
- if (monitor_pid != -1) {
- kill_process(monitor_pid);
- monitor_pid = -1;
- }
-
- goto start_next_test;
-}
-
-static void set_config_cycle_info(const char *config_dir_path,
- struct l_queue *test_stats_queue)
-{
- char sep_line[80];
- char *config_name_ptr;
- struct test_stats *test_stats;
-
- memset(sep_line, '_', sizeof(sep_line) - 1);
- sep_line[sizeof(sep_line) - 1] = '\0';
-
- config_name_ptr = strrchr(config_dir_path, '/');
- config_name_ptr++;
-
- l_info("%s", sep_line);
- l_info(CONSOLE_LN_BOLD "Starting configuration cycle No: %d [%s]"
- CONSOLE_LN_RESET, l_queue_length(test_stats_queue) + 1,
- config_name_ptr);
-
- test_stats = l_new(struct test_stats, 1);
- test_stats->config_cycle_name = strdup(config_name_ptr);
-
- l_queue_push_tail(test_stats_queue, test_stats);
-}
-
-static void set_wiphy_list(struct l_queue *wiphy_list)
-{
- const struct l_queue_entry *wiphy_entry;
- int size = 32;
- char *var;
-
- for (wiphy_entry = l_queue_get_entries(wiphy_list);
- wiphy_entry; wiphy_entry = wiphy_entry->next) {
- struct wiphy *wiphy = wiphy_entry->data;
-
- size += 32 + strlen(wiphy->name);
- if (wiphy->used_by_hostapd) {
- size += 32 + strlen(wiphy->interface_name) +
- strlen(wiphy->hostapd_ctrl_interface) +
- strlen(wiphy->hostapd_config);
- }
- }
-
- var = alloca(size);
- size = 0;
-
- for (wiphy_entry = l_queue_get_entries(wiphy_list);
- wiphy_entry; wiphy_entry = wiphy_entry->next) {
- struct wiphy *wiphy = wiphy_entry->data;
-
- if (size)
- var[size++] = '\n';
-
- size += sprintf(var + size, "%s=", wiphy->name);
-
- if (wiphy->used_by_hostapd)
- size += sprintf(var + size,
- "hostapd,name=%s,ctrl_interface=%s,"
- "config=%s",
- wiphy->interface_name,
- wiphy->hostapd_ctrl_interface,
- wiphy->hostapd_config);
- else
- size += sprintf(var + size, "iwd");
- }
-
- var[size++] = '\0';
-
- setenv("TEST_WIPHY_LIST", var, true);
-}
-
-static void set_reg_domain(const char *domain)
-{
- char *argv[5];
-
- argv[0] = "iw";
- argv[1] = "reg";
- argv[2] = "set";
- argv[3] = (char *) domain;
- argv[4] = NULL;
-
- execute_program(argv, environ, false, NULL);
-}
-
-static void wiphy_up(void *data, void *user_data)
-{
- struct wiphy *wiphy = data;
-
- set_interface_state(wiphy->interface_name, true);
-}
-
-static void wiphy_reset(void *data, void *user_data)
-{
- struct wiphy *wiphy = data;
-
- wiphy->used_by_hostapd = false;
-
- l_free(wiphy->hostapd_config);
- wiphy->hostapd_config = NULL;
- l_free(wiphy->hostapd_ctrl_interface);
- wiphy->hostapd_ctrl_interface = NULL;
-}
-
-static void create_network_and_run_tests(void *data, void *user_data)
-{
- pid_t hostapd_pids[HWSIM_RADIOS_MAX];
- pid_t iwd_pid = -1;
- pid_t medium_pid = -1;
- pid_t ofono_pid = -1;
- pid_t phonesim_pid = -1;
- char *config_dir_path;
- char *iwd_config_dir;
- char **tmpfs_extra_stuff = NULL;
- struct l_settings *hw_settings;
- struct l_queue *test_queue;
- struct l_queue *test_stats_queue;
- bool start_iwd_daemon = true;
- bool needs_hwsim = false;
- bool ofono_req = false;
- const char *sim_keys;
- const char *iwd_ext_options = NULL;
- const char *reg_domain;
- int phys_used;
- int num_radios;
- struct test_entry *entry = data;
- char *test_name = NULL;
-
- memset(hostapd_pids, -1, sizeof(hostapd_pids));
-
- config_dir_path = (char *) entry->path;
- test_queue = (struct l_queue *) entry->test_queue;
- test_stats_queue = (struct l_queue *) user_data;
-
- if (l_queue_isempty(test_queue)) {
- l_error("No Python IWD tests have been found in %s",
- config_dir_path);
- return;
- }
-
- set_config_cycle_info(config_dir_path, test_stats_queue);
-
- hw_settings = read_hw_config(config_dir_path);
- if (!hw_settings)
- return;
-
- l_info("Configuring network...");
-
- if (log) {
- char *log_path;
-
- test_name = basename(config_dir_path);
- log_path = l_strdup_printf("%s/%s", log_dir, test_name);
-
- mkdir(log_path, 0755);
- if (chown(log_path, log_uid, log_gid) < 0)
- l_error("chown failed");
-
- l_free(log_path);
- }
-
- if (chdir(config_dir_path) < 0) {
- l_error("Failed to change to test directory: %s",
- strerror(errno));
- goto free_hw_settings;
- }
-
- tmpfs_extra_stuff =
- l_settings_get_string_list(hw_settings, HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_TMPFS_EXTRAS,
- ':');
-
- sim_keys = l_settings_get_value(hw_settings, HW_CONFIG_GROUP_SETUP,
- "sim_keys");
-
- if (sim_keys) {
- if (!strcmp(sim_keys, "ofono")) {
- bool ofono_found = false;
- bool phonesim_found = false;
-
- if (!system("which ofonod > /dev/null 2>&1"))
- ofono_found = true;
-
- if (!system("which phonesim > /dev/null 2>&1"))
- phonesim_found = true;
-
- if (!ofono_found || !phonesim_found) {
- l_info("ofono or phonesim not found, skipping");
- goto free_tmpfs_extra;
- }
-
- ofono_req = true;
- iwd_ext_options = "--plugin=ofono";
- } else {
- setenv("IWD_SIM_KEYS", sim_keys, true);
- iwd_ext_options = "--plugin=sim_hardcoded";
- }
- }
-
- /* turn on/off timeouts if GDB is being used */
- if (!strcmp(gdb_opt, "none"))
- setenv("IWD_TEST_TIMEOUTS", "on", true);
- else
- setenv("IWD_TEST_TIMEOUTS", "off", true);
-
- if (!create_tmpfs_extra_stuff(tmpfs_extra_stuff))
- goto remove_abs_paths;
-
- l_settings_get_int(hw_settings, HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_NUM_RADIOS,
- &num_radios);
-
- if (!native_hw) {
- reg_domain = l_settings_get_value(hw_settings,
- HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_REG_DOMAIN);
- if (reg_domain)
- set_reg_domain(reg_domain);
-
- wiphy_list = l_queue_new();
-
- if (!configure_hw_radios(hw_settings, wiphy_list))
- goto remove_abs_paths;
-
- medium_pid = register_hwsim_as_trans_medium();
- if (medium_pid < 0)
- goto remove_abs_paths;
-
- if (check_verbosity("hwsim")) {
- list_hwsim_radios();
- list_interfaces();
- }
- } else {
- int len;
-
- l_settings_get_bool(hw_settings, HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_NEEDS_HWSIM, &needs_hwsim);
-
- /* Skip test that require hwsim dbus APIs (hwsim not running) */
- if (needs_hwsim) {
- l_error("test requires hwsim, skipping");
- goto remove_abs_paths;
- }
-
- len = l_queue_length(wiphy_list);
-
- /* Skip tests that need more radios than we have */
- if (num_radios > len) {
- l_error("test requires %d radios, only %d found",
- num_radios, len);
- goto remove_abs_paths;
- }
-
- l_queue_foreach(wiphy_list, wiphy_up, NULL);
- }
-
- if (check_verbosity("tls"))
- setenv("IWD_TLS_DEBUG", "on", true);
-
- if (!configure_hostapd_instances(hw_settings, config_dir_path,
- wiphy_list, hostapd_pids,
- &phys_used))
- goto exit_hostapd;
-
- l_settings_get_bool(hw_settings, HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_START_IWD, &start_iwd_daemon);
-
- if (start_iwd_daemon) {
- /*
- * In native mode we may have more radios than a test actually
- * needs. This would result in IWD managing all phys that
- * hostapd wasn't using, which could throw off test results.
- * By passing the number of phys the test expects IWD to have
- * we can leave the remaining (unneeded) phys unmanaged.
- */
- int iwd_phys = num_radios - phys_used;
-
- iwd_config_dir =
- l_settings_get_string(hw_settings,
- HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_IWD_CONF_DIR);
- if (!iwd_config_dir)
- iwd_config_dir = "/tmp";
-
- iwd_pid = start_iwd(iwd_config_dir, wiphy_list,
- iwd_ext_options, iwd_phys, test_name);
-
- if (iwd_pid == -1)
- goto exit_hostapd;
- } else {
- /* tells pytest to start iwd with valgrind */
- if (valgrind)
- setenv("IWD_TEST_VALGRIND", "on", true);
- }
-
- if (ofono_req) {
- phonesim_pid = start_phonesim(test_name);
- ofono_pid = start_ofono(test_name);
- }
-
- set_wiphy_list(wiphy_list);
-
- if (!shell)
- run_py_tests(hw_settings, test_queue, test_stats_queue,
- test_name);
- else {
- if (system("/bin/sh"))
- l_info("executing /bin/sh failed");
- }
-
- l_info("Destructing network...");
-
- /* Script has responsibility to cleanup any iwd instances it started */
- if (iwd_pid > 0)
- terminate_iwd(iwd_pid);
-
- /* /tmp/valgrind.log will only exist without logging turned on */
- if (valgrind && !log) {
- if (system("cat /tmp/valgrind.log"))
- l_info("cat /tmp/valgrind.log failed");
-
- if (system("echo \"\" > /tmp/valgrind.log"))
- l_info("Failed to reset /tmp/valgrind.log");
- }
-
- if (log) {
- L_AUTO_FREE_VAR(char *, dmesg);
- L_AUTO_FREE_VAR(char *, kernel_log);
-
- kernel_log = l_strdup_printf("%s/kernel.log", log_dir);
- dmesg = l_strdup_printf("dmesg > %s", kernel_log);
-
- if (system(dmesg))
- l_error("dmesg failed");
- if (chown(kernel_log, log_uid, log_gid))
- l_error("chown failed");
- }
-
- if (ofono_req) {
- loopback_started = false;
- stop_ofono(ofono_pid);
- stop_phonesim(phonesim_pid);
- }
-
-exit_hostapd:
- destroy_hostapd_instances(hostapd_pids);
-
- if (!native_hw)
- terminate_medium(medium_pid);
-
-remove_abs_paths:
- remove_absolute_path_dirs(tmpfs_extra_stuff);
-
- /*
- * If running in hwsim mode, we want to completely free/destroy the
- * wiphy list since it will be re-populated on the next test. For the
- * native case we want to reset the list as if it was freshly
- * discovered. This ensures that all the hostapd flags get reset.
- */
- if (!native_hw)
- l_queue_destroy(wiphy_list, wiphy_free);
- else
- l_queue_foreach(wiphy_list, wiphy_reset, NULL);
-
-free_tmpfs_extra:
- l_strfreev(tmpfs_extra_stuff);
-free_hw_settings:
- l_settings_free(hw_settings);
-}
-
-struct stat_totals {
- unsigned int total_passed;
- unsigned int total_failed;
- unsigned int total_timedout;
- double total_duration;
-};
-
-static void print_test_stat(void *data, void *user_data)
-{
- struct test_stats *test_stats;
- struct stat_totals *stat_totals;
- char *str_runtime, *str_passed, *str_failed, *str_timedout;
-
- test_stats = (struct test_stats *) data;
- stat_totals = (struct stat_totals *) user_data;
-
- stat_totals->total_duration += test_stats->py_run_time;
- stat_totals->total_passed += test_stats->num_passed;
- stat_totals->total_failed += test_stats->num_failed;
- stat_totals->total_timedout += test_stats->num_timedout;
-
- if (test_stats->py_run_time)
- str_runtime = l_strdup_printf("| %9.3f sec",
- test_stats->py_run_time);
- else
- str_runtime = l_strdup_printf("| %9s", "Skipped");
-
- if (test_stats->num_passed)
- str_passed = l_strdup_printf(" %6d ", test_stats->num_passed);
- else
- str_passed = l_strdup_printf(" %6c ", '-');
-
- if (test_stats->num_failed)
- str_failed = l_strdup_printf(" %6d ", test_stats->num_failed);
- else
- str_failed = l_strdup_printf(" %6c ", '-');
-
- if (test_stats->num_timedout)
- str_timedout = l_strdup_printf(" %9d ",
- test_stats->num_timedout);
- else
- str_timedout = l_strdup_printf(" %9c ", '-');
-
- l_info(CONSOLE_LN_BOLD "%27s "
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_GREEN "%s"
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_RED "%s"
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_YELLOW "%s"
- CONSOLE_LN_RESET "%s", test_stats->config_cycle_name,
- str_passed, str_failed, str_timedout, str_runtime);
-
- l_free(str_passed);
- l_free(str_failed);
- l_free(str_timedout);
- l_free(str_runtime);
-}
-
-static void print_results(struct l_queue *test_stat_queue)
-{
- struct stat_totals stat_totals = { 0, 0, 0, 0 };
- char sep_line[80];
-
- memset(sep_line, '_', sizeof(sep_line) - 1);
- sep_line[sizeof(sep_line) - 1] = '\0';
-
- l_info("%s\n" CONSOLE_LN_RESET, sep_line);
- l_info("%27s " CONSOLE_LN_DEFAULT "|" CONSOLE_LN_GREEN " %s
"
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_RED " %5s "
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_YELLOW " %9s "
- CONSOLE_LN_RESET "| Duration",
- "Configuration cycle", "PASSED", "FAILED", "TIMED
OUT");
-
- memset(sep_line, '-', sizeof(sep_line) - 1);
- sep_line[sizeof(sep_line) - 1] = '\0';
- l_info("%s" CONSOLE_LN_RESET, sep_line);
-
- l_queue_foreach(test_stat_queue, print_test_stat, &stat_totals);
-
- l_info("%s" CONSOLE_LN_RESET, sep_line);
- l_info("%27s "
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_GREEN " %6d "
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_RED " %6d "
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_YELLOW " %9d "
- CONSOLE_LN_RESET "| %9.3f sec",
- "Total", stat_totals.total_passed, stat_totals.total_failed,
- stat_totals.total_timedout, stat_totals.total_duration);
-
- memset(sep_line, '_', sizeof(sep_line) - 1);
- sep_line[sizeof(sep_line) - 1] = '\0';
- l_info("%s" CONSOLE_LN_RESET, sep_line);
-}
-
-static void test_stat_queue_entry_destroy(void *data)
-{
- struct test_stats *ts;
-
- ts = (struct test_stats *) data;
-
- l_free(ts->config_cycle_name);
- l_free(ts);
-}
-
-static void free_test_entry(void *data)
-{
- struct test_entry *entry = data;
-
- l_free(entry->path);
- l_free(entry);
-}
-
-static void run_auto_tests(void)
-{
- L_AUTO_FREE_VAR(char*, test_home_path) = NULL;
- L_AUTO_FREE_VAR(char*, env_path) = NULL;
- int i;
- struct l_queue *test_config_queue;
- struct l_queue *test_stat_queue;
- char **test_config_dirs;
-
- if (log) {
- if (mount("logdir", log_dir, "9p", 0,
- "trans=virtio,version=9p2000.L") < 0) {
- l_error("Mounting %s failed", log_dir);
- return;
- }
- }
-
- env_path = l_strdup_printf("%s/src:%s/tools:%s", top_level_path,
- top_level_path, getenv("PATH"));
-
- setenv("PATH", env_path, true);
-
- test_home_path = l_strdup_printf("%s/%s", top_level_path,
- TEST_TOP_DIR_DEFAULT_NAME);
-
- if (!path_exist(test_home_path)) {
- l_error("Test directory %s does not exist", test_home_path);
- return;
- }
-
- test_config_queue = l_queue_new();
- if (!test_config_queue)
- return;
-
- test_config_dirs = l_strsplit(test_action_params, ',');
-
- if (test_config_dirs[0]) {
- i = 0;
-
- while (test_config_dirs[i]) {
- if (strchr(test_config_dirs[i], '/')) {
- if (!find_test_configuration(
- test_config_dirs[i], 1,
- test_config_queue))
- goto exit;
- } else {
- char *config_dir_path;
-
- config_dir_path =
- l_strdup_printf("%s/%s", test_home_path,
- test_config_dirs[i]);
-
- if (!find_test_configuration(config_dir_path, 1,
- test_config_queue)) {
- l_free(config_dir_path);
-
- goto exit;
- }
-
- l_free(config_dir_path);
- }
-
- i++;
- }
- } else {
- /*
- * --shell without any specific tests implies 'shell' test
- */
- if (shell) {
- char *config_dir_path;
- config_dir_path = l_strdup_printf("%s/shell",
- test_home_path);
-
- if (!find_test_configuration(config_dir_path, 1,
- test_config_queue)) {
- l_free(config_dir_path);
- goto exit;
- }
-
- l_free(config_dir_path);
- } else {
- l_info("Automatic test execution requested");
- l_info("Searching for the test configurations...");
-
- if (!find_test_configuration(test_home_path, 0,
- test_config_queue))
- goto exit;
- }
- }
-
- if (l_queue_isempty(test_config_queue)) {
- l_error("No test configuration discovered");
- goto exit;
- }
-
- create_dbus_system_conf();
-
- if (!start_dbus_daemon())
- goto exit;
-
- if (!start_haveged()) {
- l_error("Failed to start haveged");
- goto exit;
- }
-
- test_stat_queue = l_queue_new();
-
- l_queue_foreach(test_config_queue, create_network_and_run_tests,
- test_stat_queue);
-
- print_results(test_stat_queue);
-
- l_queue_destroy(test_stat_queue, test_stat_queue_entry_destroy);
-
-exit:
- l_strfreev(verbose_apps);
- l_strfreev(test_config_dirs);
- l_queue_destroy(test_config_queue, free_test_entry);
-}
-
-static void run_unit_tests(void)
-{
- DIR *d;
- struct dirent *dirent;
- char *argv[2];
- char *unit_test_abs_path = NULL;
- char **unit_tests = NULL;
-
- if (strcmp(test_action_params, "")) {
- unit_tests = l_strsplit(test_action_params, ',');
-
- if (!unit_tests || !unit_tests[0])
- goto exit;
- }
-
- if (chdir(top_level_path) < 0)
- goto exit;
-
- d = opendir("unit/");
- if (!d)
- goto exit;
-
- while ((dirent = readdir(d)) != NULL) {
- struct stat st;
-
- if (dirent->d_type != DT_REG)
- continue;
-
- unit_test_abs_path = l_strdup_printf("%s%s%s", top_level_path,
- "/unit/", dirent->d_name);
-
- if (stat(unit_test_abs_path, &st) < 0)
- goto next;
-
- if (!(st.st_mode & S_IEXEC))
- goto next;
-
- if (unit_tests) {
- if (!l_strv_contains(unit_tests, dirent->d_name))
- goto next;
- }
-
- argv[0] = unit_test_abs_path;
- argv[1] = NULL;
-
- l_info("\n---------- Unit %s ----------", dirent->d_name);
- execute_program(argv, environ, true, NULL);
-
-next:
- l_free(unit_test_abs_path);
- }
-
- closedir(d);
-
-exit:
- l_strfreev(unit_tests);
-}
-
-static bool wiphy_match(const void *a, const void *b)
-{
- const struct wiphy *wiphy = a;
- int id = L_PTR_TO_INT(b);
-
- return (wiphy->id == id);
-}
-
-static struct wiphy *wiphy_find(int wiphy_id)
-{
- return l_queue_find(wiphy_list, wiphy_match, L_INT_TO_PTR(wiphy_id));
-}
-
-static void parse_supported_iftypes(uint16_t *iftypes,
- struct l_genl_attr *attr)
-{
- uint16_t type, len;
- const void *data;
-
- while (l_genl_attr_next(attr, &type, &len, &data)) {
- /*
- * NL80211_IFTYPE_UNSPECIFIED can be ignored, so we start
- * at the first bit
- */
- if (type > sizeof(uint16_t) * 8) {
- l_warn("unsupported iftype: %u", type);
- continue;
- }
-
- *iftypes |= 1 << (type - 1);
- }
-}
-
-static void wiphy_dump_callback(struct l_genl_msg *msg, void *user_data)
-{
- struct wiphy *wiphy;
- struct l_genl_attr attr;
- struct l_genl_attr nested;
- uint32_t id = UINT32_MAX;
- uint16_t type, len;
- const void *data;
- const char *name = NULL;
- uint32_t name_len = 0;
- uint16_t iftypes = 0;
-
- if (!l_genl_attr_init(&attr, msg))
- return;
-
- while (l_genl_attr_next(&attr, &type, &len, &data)) {
- switch (type) {
- case NL80211_ATTR_WIPHY:
- if (len != sizeof(uint32_t))
- return;
-
- id = *((uint32_t *) data);
-
- if (wiphy_find(id))
- return;
-
- break;
- case NL80211_ATTR_WIPHY_NAME:
- if (len > sizeof(((struct wiphy *) 0)->name))
- return;
-
- name = data;
- name_len = len;
-
- break;
- case NL80211_ATTR_SUPPORTED_IFTYPES:
- if (l_genl_attr_recurse(&attr, &nested))
- parse_supported_iftypes(&iftypes, &nested);
-
- break;
- }
- }
-
- if (id == UINT32_MAX || !name)
- return;
-
- wiphy = l_new(struct wiphy, 1);
- strncpy(wiphy->name, name, name_len);
- wiphy->id = id;
- wiphy->can_ap = iftypes & (1 << NL80211_IFTYPE_AP);
-
- l_queue_push_tail(wiphy_list, wiphy);
-}
-
-static void iface_dump_callback(struct l_genl_msg *msg, void *user_data)
-{
- struct l_genl_attr attr;
- uint16_t type, len;
- const void *data;
- const char *ifname = NULL;
- struct wiphy *wiphy = NULL;
-
- if (!l_genl_attr_init(&attr, msg))
- return;
-
- while (l_genl_attr_next(&attr, &type, &len, &data)) {
- switch (type) {
-
- case NL80211_ATTR_IFNAME:
- if (len > 16) {
- l_warn("Invalid interface name attribute");
- return;
- }
-
- ifname = data;
- break;
-
- case NL80211_ATTR_WIPHY:
- if (len != sizeof(uint32_t)) {
- l_warn("Invalid wiphy attribute");
- return;
- }
-
- wiphy = wiphy_find(*((uint32_t *) data));
- break;
- }
- }
-
- if (!ifname || !wiphy)
- return;
-
- wiphy->interface_name = l_strdup(ifname);
- wiphy->interface_created = false;
-
- l_info("Discovered interface %s", wiphy->interface_name);
-}
-
-struct nl_data {
- struct l_genl *genl;
- struct l_genl_family *nl80211;
-};
-
-static void iface_dump_done(void *user_data)
-{
- struct nl_data *data = user_data;
-
- l_debug("Interface discovery complete, running tests");
-
- list_interfaces();
-
- run_auto_tests();
-
- l_queue_destroy(wiphy_list, wiphy_free);
-
- l_genl_family_free(data->nl80211);
- l_genl_unref(data->genl);
- l_free(data);
-
- l_main_quit();
-}
-
-static void wiphy_dump_done(void *user_data)
-{
- struct nl_data *data = user_data;
- struct l_genl_msg *msg;
-
- l_debug("Wiphy discovery complete, discovering interfaces");
-
- msg = l_genl_msg_new(NL80211_CMD_GET_INTERFACE);
- if (!l_genl_family_dump(data->nl80211, msg, iface_dump_callback,
- data, iface_dump_done))
- l_error("Getting all interface information failed");
-}
-
-static void nl80211_requested(const struct l_genl_family_info *info,
- void *user_data)
-{
- struct nl_data *data = user_data;
- struct l_genl_msg *msg;
-
- if (info == NULL) {
- l_info("No nl80211 family found");
- goto done;
- }
-
- l_debug("Found nl80211 interface");
-
- data->nl80211 = l_genl_family_new(data->genl, NL80211_GENL_NAME);
- wiphy_list = l_queue_new();
-
- msg = l_genl_msg_new(NL80211_CMD_GET_WIPHY);
- if (!l_genl_family_dump(data->nl80211, msg, wiphy_dump_callback,
- data, wiphy_dump_done))
- l_error("Getting all wiphy devices failed");
-
- return;
-done:
- l_main_quit();
-}
-
-static void start_hw_discovery(void)
-{
- struct nl_data *data = l_new(struct nl_data, 1);
-
- data->genl = l_genl_new();
- l_genl_request_family(data->genl, NL80211_GENL_NAME,
- nl80211_requested, data, NULL);
- /*
- * This is somewhat of a mystery, but it appears that
- * calling lshw causes the OS to re-enumerate the USB
- * bus. Without this no USB adapters are found when
- * doing the wiphy/iface dump from nl80211.
- *
- * This also conveniently prints all the network
- * adapters and their iface name, so its much easier
- * to know which adapter are being used by iwd/hostapd
- * after the test.
- */
- if (system("lshw -C network"))
- l_info("lshw failed");
-
- l_main_run();
-}
-
-static void run_tests(void)
-{
- char cmdline[CMDLINE_MAX], *ptr, *cmds;
- char *test_action_str;
- FILE *fp;
- int i;
-
- fp = fopen("/proc/cmdline", "re");
-
- if (!fp) {
- l_error("Failed to open kernel command line");
- return;
- }
-
- ptr = fgets(cmdline, sizeof(cmdline), fp);
- fclose(fp);
-
- if (!ptr) {
- l_error("Failed to read kernel command line");
- return;
- }
-
- ptr = strstr(cmdline, "LOG_GID=");
- if (ptr) {
- *ptr = '\0';
- test_action_str = ptr + 9;
- ptr = strchr(test_action_str, '\'');
- *ptr = '\0';
- log_gid = atoi(test_action_str);
- }
-
- ptr = strstr(cmdline, "LOG_UID=");
- if (ptr) {
- *ptr = '\0';
- test_action_str = ptr + 9;
- ptr = strchr(test_action_str, '\'');
- *ptr = '\0';
- log_uid = atoi(test_action_str);
- }
-
- ptr = strstr(cmdline, "LOG_PATH=");
- if (ptr) {
- *ptr = '\0';
- test_action_str = ptr + 10;
-
- ptr = strchr(test_action_str, '\'');
- *ptr = '\0';
-
- if (strcmp(test_action_str, "none")) {
- log = true;
- strcpy(log_dir, test_action_str);
- }
- }
-
- ptr = strstr(cmdline, "SHELL=");
- if (ptr) {
- *ptr = '\0';
- test_action_str = ptr + 6;
-
- shell = atoi(test_action_str);
- }
-
- ptr = strstr(cmdline, "HW=");
- if (ptr) {
- *ptr = '\0';
- test_action_str = ptr + 4;
-
- ptr = strchr(test_action_str, '\'');
- if (ptr)
- *ptr = '\0';
-
- if (!strcmp(test_action_str, "virtual"))
- native_hw = false;
- else
- native_hw = true;
- }
-
- ptr = strstr(cmdline, "GDB=");
- if (ptr) {
- *ptr = '\0';
- test_action_str = ptr + 5;
-
- ptr = strchr(test_action_str, '\'');
- *ptr = '\0';
- gdb_opt = l_strdup(test_action_str);
- }
-
- ptr = strstr(cmdline, "VALGRIND=");
- if (ptr) {
- char *end;
- unsigned long v;
-
- *ptr = '\0';
- test_action_str = ptr + 9;
- v = strtoul(test_action_str, &end, 10);
- if ((v != 0 && v != 1) || end != test_action_str + 1) {
- l_error("malformed valgrind option");
- return;
- }
-
- valgrind = (bool) v;
- }
-
- ptr = strstr(cmdline, "PATH=");
- if (!ptr) {
- l_error("No $PATH section found");
- return;
- }
-
- *ptr = '\0';
- test_action_str = ptr + 6;
- ptr = strchr(test_action_str, '\'');
- *ptr = '\0';
- l_info("%s", test_action_str);
- setenv("PATH", test_action_str, true);
-
- ptr = strstr(cmdline, "TESTARGS=");
-
- if (!ptr) {
- l_error("No test command section found");
- return;
- }
-
- cmds = ptr + 10;
- ptr = strchr(cmds, '\'');
-
- if (!ptr) {
- l_error("Malformed test command section");
- return;
- }
-
- *ptr = '\0';
-
- ptr = strstr(cmdline, "TEST_ACTION_PARAMS=");
-
- if (ptr) {
- test_action_params = ptr + 20;
- ptr = strchr(test_action_params, '\'');
-
- if (!ptr) {
- l_error("Malformed test action parameters section");
- return;
- }
-
- *ptr = '\0';
- }
-
- ptr = strstr(cmdline, "TEST_ACTION=");
-
- if (ptr) {
- test_action_str = ptr + 12;
- ptr = strchr(test_action_str, ' ');
-
- if (!ptr) {
- l_error("Malformed test action parameters section");
- return;
- }
-
- *ptr = '\0';
-
- test_action = (enum action) atoi(test_action_str);
- }
-
- ptr = strstr(cmdline, "DEBUG_FILTER=");
-
- if (ptr) {
- debug_filter = ptr + 14;
-
- ptr = strchr(debug_filter, '\'');
-
- if (!ptr) {
- l_error("Malformed debug filter section");
- return;
- }
-
- *ptr = '\0';
-
- if (debug_filter[0] != '\0') {
- enable_debug = true;
- l_debug_enable(debug_filter);
- setenv("HWSIM_DEBUG", "", true);
- }
- }
-
- ptr = strstr(cmdline, "TESTVERBOUT=");
-
- if (ptr) {
- verbose_opt = ptr + 13;
-
- ptr = strchr(verbose_opt, '\'');
- if (!ptr) {
- l_error("Malformed verbose parameter");
- return;
- }
-
- *ptr = '\0';
-
- l_info("Enable verbose output for %s", verbose_opt);
-
- verbose_apps = l_strsplit(verbose_opt, ',');
- }
-
- ptr = strstr(cmdline, "TESTHOME=");
-
- if (ptr) {
- exec_home = ptr + 4;
- ptr = strpbrk(exec_home + 9, " \r\n");
-
- if (ptr)
- *ptr = '\0';
- }
-
- ptr = strrchr(exec_home, '/');
-
- if (!ptr)
- exit(EXIT_FAILURE);
-
- i = ptr - exec_home;
-
- strncpy(top_level_path, exec_home + 5, i - 5);
- top_level_path[i - 5] = '\0';
-
- switch (test_action) {
- case ACTION_AUTO_TEST:
- if (native_hw)
- start_hw_discovery();
- else
- run_auto_tests();
- break;
- case ACTION_UNIT_TEST:
- run_unit_tests();
- break;
- }
-}
-
-static void usage(void)
-{
- l_info("test-runner - Automated test execution utility\n"
- "Usage:\n");
- l_info("\ttest-runner [options] [--] <command> [args]\n");
- l_info("Options:\n"
- "\t-q, --qemu <path> QEMU binary\n"
- "\t-k, --kernel <image> Kernel image (bzImage)\n"
- "\t-v, --verbose <apps> Comma separated list of "
- "applications to enable\n"
- "\t\t\t\tverbose output\n"
- "\t-h, --help Show help options\n"
- "\t-V, --valgrind Run valgrind on iwd. Note: \"-v"
- " iwd\" is required\n"
- "\t\t\t\tto see valgrind"
- " output\n"
- "\t-g, --gdb <iwd|hostapd> Run gdb on the specified"
- " executable\n"
- "\t-w, --hw <config> Run using a physical hardware "
- "configuration\n"
- "\t-s, --shell Boot into shell. If -A is used the"
- " environment\n"
- "\t\t\t\twill be setup exactly as it is"
- " in the test,\n"
- "\t\t\t\tbut no test will be run. If no"
- " test is specified\n"
- "\t\t\t\tthe 'shell' test"
- " will be used\n"
- "\t-l, --log <dir> Directory used for log output. "
- "This option sets \n"
- "\t\t\t\t--verbose on all apps");
- l_info("Commands:\n"
- "\t-A, --auto-tests <dirs> Comma separated list of the "
- "test configuration\n\t\t\t\t"
- "directories to run\n"
- "\t-U, --unit-tests <tests> Comma separated list of the "
- "unit tests to run\n");
-}
-
-static const struct option main_options[] = {
- { "auto-tests", required_argument, NULL, 'A' },
- { "unit-tests", optional_argument, NULL, 'U' },
- { "qemu", required_argument, NULL, 'q' },
- { "kernel", required_argument, NULL, 'k' },
- { "verbose", required_argument, NULL, 'v' },
- { "debug", optional_argument, NULL, 'd' },
- { "gdb", required_argument, NULL, 'g' },
- { "valgrind", no_argument, NULL, 'V' },
- { "hw", required_argument, NULL, 'w' },
- { "shell", optional_argument, NULL, 's' },
- { "log", required_argument, NULL, 'l' },
- { "help", no_argument, NULL, 'h' },
- { }
-};
-
-int main(int argc, char *argv[])
-{
- uint8_t actions = 0;
- struct tm *timeinfo;
- time_t t;
- char *gid;
- char *uid;
-
- l_log_set_stderr();
-
- if (getpid() == 1 && getppid() == 0) {
- if (!l_main_init())
- return EXIT_FAILURE;
-
- prepare_sandbox();
-
- run_tests();
-
- sync();
- l_info("Done running tests. Rebooting...");
-
- reboot(RB_AUTOBOOT);
- return EXIT_SUCCESS;
- }
-
- for (;;) {
- int opt;
-
- opt = getopt_long(argc, argv, "A:q:k:v:g:sl:UVdh", main_options,
- NULL);
- if (opt < 0)
- break;
-
- switch (opt) {
- case 'A':
- test_action = ACTION_AUTO_TEST;
- test_action_params = optarg;
- actions++;
- break;
- case 'U':
- test_action = ACTION_UNIT_TEST;
- test_action_params = optarg;
- actions++;
- break;
- case 'q':
- qemu_binary = optarg;
- break;
- case 'k':
- kernel_image = optarg;
- break;
- case 'd':
- enable_debug = true;
-
- if (optarg)
- debug_filter = optarg;
- else
- debug_filter = "*";
-
- l_debug_enable(debug_filter);
- break;
- case 'v':
- verbose_opt = optarg;
- verbose_apps = l_strsplit(optarg, ',');
- break;
- case 'V':
- valgrind = true;
- break;
- case 'g':
- gdb_opt = optarg;
- if (!gdb_opt || (strcmp(gdb_opt, "iwd") &&
- strcmp(gdb_opt, "hostapd") &&
- strcmp(gdb_opt, "hwsim"))) {
- l_error("--gdb can only be used with iwd"
- ", hwsim or hostapd");
- return EXIT_FAILURE;
- }
- break;
- case 'w':
- hw_config = l_settings_new();
- if (!l_settings_load_from_file(hw_config, optarg)) {
- l_error("could not read hw config from %s",
- optarg);
- l_settings_free(hw_config);
- return EXIT_FAILURE;
- }
- break;
- case 's':
- shell = true;
- break;
- case 'l':
- /*
- * Setup the log directory. This is created under the
- * passed in log dir (--log) in the format:
- * <logdir>/run-<year>-<month>-<day>-<PID>
- *
- * The created log dir is then chown'ed to the user
- * who started test-runner, as are all files created
- * under this directory.
- */
- log = true;
-
- if (!optarg)
- optarg = ".";
-
- time(&t);
- timeinfo = localtime(&t);
-
- gid = getenv("SUDO_GID");
- uid = getenv("SUDO_UID");
-
- if (!gid || !uid) {
- log_gid = getgid();
- log_uid = getuid();
- } else {
- log_gid = strtol(gid, NULL, 10);
- log_uid = strtol(uid, NULL, 10);
- }
-
- snprintf(log_dir, sizeof(log_dir), "%s/run-%d-%d-%d-%d",
- optarg, timeinfo->tm_year + 1900,
- timeinfo->tm_mon + 1, timeinfo->tm_mday,
- getpid());
- mkdir(log_dir, 0755);
-
- if (chown(log_dir, log_uid, log_gid) < 0)
- l_error("failed to fchown %s", log_dir);
-
- break;
- case 'h':
- usage();
- return EXIT_SUCCESS;
- default:
- return EXIT_FAILURE;
- }
- }
-
- if (argc - optind > 0) {
- l_error("Invalid command line parameters");
- return EXIT_FAILURE;
- }
-
- if (actions > 1) {
- l_error("Only one action can be specified");
- return EXIT_FAILURE;
- }
-
- if (!actions)
- test_action = ACTION_AUTO_TEST;
-
- own_binary = argv[0];
- test_argv = argv + optind;
- test_argc = argc - optind;
-
- if (!qemu_binary) {
- qemu_binary = find_qemu();
- if (!qemu_binary) {
- l_error("No default QEMU binary found");
- return EXIT_FAILURE;
- }
- }
-
- if (!kernel_image) {
- kernel_image = find_kernel();
- if (!kernel_image) {
- l_error("No default kernel image found");
- return EXIT_FAILURE;
- }
- }
-
- l_info("Using QEMU binary %s", qemu_binary);
- l_info("Using kernel image %s", kernel_image);
-
- if (!start_qemu())
- return EXIT_FAILURE;
-
- return EXIT_SUCCESS;
-}
--
2.21.1