[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