From patchwork Thu Nov 8 14:45:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Colin Ian King X-Patchwork-Id: 994920 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=fwts-devel-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42rR0F2vmcz9sBh; Fri, 9 Nov 2018 01:45:17 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1gKlYY-0002Cw-T9; Thu, 08 Nov 2018 14:45:14 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1gKlYX-0002CN-1P for fwts-devel@lists.ubuntu.com; Thu, 08 Nov 2018 14:45:13 +0000 Received: from 1.general.cking.uk.vpn ([10.172.193.212] helo=localhost) by youngberry.canonical.com with esmtpsa (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.76) (envelope-from ) id 1gKlYW-00063e-Jq; Thu, 08 Nov 2018 14:45:12 +0000 From: Colin King To: fwts-devel@lists.ubuntu.com Subject: [PATCH 1/3] src/lib: add module probing helper functions Date: Thu, 8 Nov 2018 14:45:09 +0000 Message-Id: <20181108144511.12678-2-colin.king@canonical.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181108144511.12678-1-colin.king@canonical.com> References: <20181108144511.12678-1-colin.king@canonical.com> MIME-Version: 1.0 X-BeenThere: fwts-devel@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Firmware Test Suite Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: fwts-devel-bounces@lists.ubuntu.com Sender: "fwts-devel" From: Colin Ian King Rather than load/unload modules with modrobe instead use direct system calls to perform these actions. This allows us to have finer control of the error handling and it is faster too. Signed-off-by: Colin Ian King Acked-by: Alex Hung Acked-by: Ivan Hu --- src/lib/include/fwts.h | 1 + src/lib/include/fwts_modprobe.h | 29 ++++ src/lib/src/Makefile.am | 1 + src/lib/src/fwts_modprobe.c | 235 ++++++++++++++++++++++++++++++++ 4 files changed, 266 insertions(+) create mode 100644 src/lib/include/fwts_modprobe.h create mode 100644 src/lib/src/fwts_modprobe.c diff --git a/src/lib/include/fwts.h b/src/lib/include/fwts.h index 62834ec3..3f343ef2 100644 --- a/src/lib/include/fwts.h +++ b/src/lib/include/fwts.h @@ -203,5 +203,6 @@ #include "fwts_safe_mem.h" #include "fwts_devicetree.h" #include "fwts_pm_debug.h" +#include "fwts_modprobe.h" #endif diff --git a/src/lib/include/fwts_modprobe.h b/src/lib/include/fwts_modprobe.h new file mode 100644 index 00000000..5a1c6e27 --- /dev/null +++ b/src/lib/include/fwts_modprobe.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 Canonical + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef __FWTS_MODPROBE_H__ +#define __FWTS_MODPROBE_H__ + +#include "fwts_framework.h" + +int fwts_module_loaded(fwts_framework *fw, const char *module, bool *loaded); +int fwts_module_load(fwts_framework *fw, const char *module); +int fwts_module_unload(fwts_framework *fw, const char *module); + +#endif diff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am index 54de7f44..9858d04c 100644 --- a/src/lib/src/Makefile.am +++ b/src/lib/src/Makefile.am @@ -92,6 +92,7 @@ libfwts_la_SOURCES = \ fwts_log_xml.c \ fwts_memorymap.c \ fwts_mmap.c \ + fwts_modprobe.c \ fwts_multiproc.c \ fwts_oops.c \ fwts_pci.c \ diff --git a/src/lib/src/fwts_modprobe.c b/src/lib/src/fwts_modprobe.c new file mode 100644 index 00000000..03e3a5f1 --- /dev/null +++ b/src/lib/src/fwts_modprobe.c @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2018 Canonical + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fwts.h" + +/* + * fwts_module_find() + * recursively search for module from the basepath start + * and return false if not found, and true if found. If + * found, the full path of the module is set in the string + * path. + */ +static bool fwts_module_find( + const char *module, + const char *basepath, + char *path, + const size_t path_len) +{ + DIR *dir; + struct dirent *de; + + dir = opendir(basepath); + if (!dir) + return false; + + while ((de = readdir(dir)) != NULL) { + char newpath[PATH_MAX]; + + if (de->d_name[0] == '.') + continue; + + switch (de->d_type) { + case DT_DIR: + (void)snprintf(newpath, sizeof(newpath), "%s/%s", + basepath, de->d_name); + if (fwts_module_find(module, newpath, path, path_len)) { + (void)closedir(dir); + return true; + } + break; + case DT_REG: + if (!strcmp(de->d_name, module)) { + (void)snprintf(path, path_len, "%s/%s", basepath, module); + (void)closedir(dir); + return true; + } + break; + default: + break; + } + } + + (void)closedir(dir); + return false; +} + +/* + * sys_finit_module() + * system call wrapper for finit_module + */ +static inline int sys_finit_module( + int fd, + const char *param_values, + int flags) +{ + errno = 0; + return syscall(__NR_finit_module, fd, param_values, flags); +} + +/* + * sys_delete_module() + * system call wrapper for delete_module + */ +static inline int sys_delete_module( + const char *name, + int flags) +{ + errno = 0; + return syscall(__NR_delete_module, name, flags); +} + +/* + * fwts_module_loaded() + * check if module is loaded, the name (without .ko suffix) is + * provided in string module. Boolean loaded is set to true if + * the module is loaded, false otherwise. Returns FWTS_OK if + * all went OK, FWTS_ERROR if something went wrong. + */ +int fwts_module_loaded(fwts_framework *fw, const char *module, bool *loaded) +{ + FILE *fp; + char buffer[1024]; + + *loaded = false; + fp = fopen("/proc/modules", "r"); + if (!fp) { + fwts_log_error(fw, "Cannot open /proc/modules, errno=%d (%s)\n", + errno, strerror(errno)); + return FWTS_ERROR; + } + + (void)memset(buffer, 0, sizeof(buffer)); + while (fgets(buffer, sizeof(buffer) - 1, fp) != NULL) { + char *ptr = strchr(buffer, ' '); + + if (*ptr) + *ptr = '\0'; + + if (!strcmp(buffer, module)) { + *loaded = true; + break; + } + } + (void)fclose(fp); + + return FWTS_OK; +} + +/* + * fwts_module_load() + * load a module. The module name (without the .ko) suffix + * is to provided in string module. Returns FWTS_OK if + * succeeded (or the module is already loaded) and FWTS_ERROR + * if the load failed. + */ +int fwts_module_load(fwts_framework *fw, const char *module) +{ + struct utsname u; + const size_t modlen = strlen(module); + char module_ko[modlen + 4]; + char path[PATH_MAX]; + char modpath[PATH_MAX]; + const char *params = ""; + int fd; + bool loaded = false; + + /* + * No need to unload if it's not already loaded + */ + if (fwts_module_loaded(fw, module, &loaded) == FWTS_OK) { + if (loaded) + return FWTS_OK; + } + + /* + * Set up module root path and try to find the named module + */ + if (uname(&u) < 0) { + fwts_log_error(fw, "Call to uname failed, errno=%d (%s)\n", + errno, strerror(errno)); + return FWTS_ERROR; + } + (void)snprintf(module_ko, sizeof(module_ko), "%s.ko", module); + (void)snprintf(modpath, sizeof(modpath), "/lib/modules/%s", u.release); + if (!fwts_module_find(module_ko, modpath, path, sizeof(path))) { + fwts_log_error(fw, "Cannot find module %s\n", module); + return FWTS_ERROR; + } + + /* + * We've found it, now try and load it + */ + fd = open(path, O_RDONLY); + if (fd < 0) { + fwts_log_error(fw, "Cannot open module %s, errno=%d (%s)\n", + path, errno, strerror(errno)); + return FWTS_ERROR; + } + if (sys_finit_module(fd, params, 0) < 0) { + fwts_log_error(fw, "Cannot load module %s, errno=%d (%s)\n", + path, errno, strerror(errno)); + (void)close(fd); + return FWTS_ERROR; + } + (void)close(fd); + + return FWTS_OK; +} + +/* + * fwts_module_unload() + * unload a module. The module name (without the .ko) suffix + * is to provided in string module. Returns FWTS_OK if + * succeeded (or the module is not previously loaded) and + * FWTS_ERROR if the unload failed. + */ +int fwts_module_unload(fwts_framework *fw, const char *module) +{ + bool loaded = false; + int ret; + + /* + * No need to unload if it's not already loaded + */ + if (fwts_module_loaded(fw, module, &loaded) == FWTS_OK) { + if (!loaded) + return FWTS_OK; + } + + ret = sys_delete_module(module, O_NONBLOCK); + if (ret < 0) { + fwts_log_error(fw, "Cannot unload module %s, errno=%d (%s)\n", + module, errno, strerror(errno)); + return FWTS_ERROR; + } + return FWTS_OK; +}