[PATCH 1/3] src/lib: add module probing helper functions
Colin King
colin.king at canonical.com
Thu Nov 8 14:45:09 UTC 2018
From: Colin Ian King <colin.king at canonical.com>
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 <colin.king at canonical.com>
---
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 <fcntl.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/utsname.h>
+
+#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;
+}
--
2.19.1
More information about the fwts-devel
mailing list