[1/3] src/lib: add module probing helper functions
diff mbox series

Message ID 20181108144511.12678-2-colin.king@canonical.com
State Accepted
Headers show
Series
  • Remove modprobe, replace with module system calls
Related show

Commit Message

Colin King Nov. 8, 2018, 2:45 p.m. UTC
From: Colin Ian King <colin.king@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@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

Comments

Alex Hung Nov. 13, 2018, 7:03 a.m. UTC | #1
On 2018-11-08 10:45 p.m., Colin King wrote:
> From: Colin Ian King <colin.king@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@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;
> +}
> 


Acked-by: Alex Hung <alex.hung@canonical.com>
ivanhu Nov. 13, 2018, 7:51 a.m. UTC | #2
On 11/8/18 10:45 PM, Colin King wrote:
> From: Colin Ian King <colin.king@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@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;
> +}


Acked-by: Ivan Hu <ivan.hu@canonical.com>

Patch
diff mbox series

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;
+}