diff mbox series

[V2,4/6] Allow to run a SWUpdate function in child process

Message ID 20230512123504.160169-5-sbabic@denx.de
State Accepted
Headers show
Series Cleanup and include restruct | expand

Commit Message

Stefano Babic May 12, 2023, 12:35 p.m. UTC
Add a generic way for running an internal function in a child process.
This is helpful in case some external functions will be integrated and
it is easier to run them in a separate process than in core. The
function has the easy footprint:

	fn(int argc, char **argv)

The stdout and stderr are still replaced and output is sent to
SWUpdate's logs else TRACE and ERROR.

Signed-off-by: Stefano Babic <sbabic@denx.de>
---
 core/pctl.c    | 78 +++++++++++++++++++++++++++++++++++++++-----------
 include/pctl.h |  1 +
 2 files changed, 62 insertions(+), 17 deletions(-)
diff mbox series

Patch

diff --git a/core/pctl.c b/core/pctl.c
index 2eeef0a..f4f5dd0 100644
--- a/core/pctl.c
+++ b/core/pctl.c
@@ -30,6 +30,12 @@ 
 #define WAIT_ANY (-1)
 #endif
 
+typedef struct {
+	int (*exec)(int argc, char **argv);
+	int argc;
+	char **argv;
+} bgtask;
+
 /* the array contains the pid of the subprocesses */
 #define MAX_PROCESSES	10
 static struct swupdate_task procs[MAX_PROCESSES];
@@ -240,12 +246,13 @@  void start_subprocess(sourcetype type, const char *name,
 }
 
 /*
- * run_system_cmd executes a shell script in background and intercepts
- * stdout and stderr of the script, writing then to TRACE and ERROR
- * This let the output of the scripts to be collected by SWUpdate
+ * run_cmd executes a shell script or an internal function in background
+ * in a separate process and intercepts stdout and stderr, writing then to
+ * TRACE and ERROR.
+ * This let the output of the scripts / functions to be collected by SWUpdate
  * tracing capabilities.
  */
-int run_system_cmd(const char *cmd)
+static int __run_cmd(const char *cmd, bgtask *fn)
 {
 	int ret = 0;
 	int const npipes = 4;
@@ -255,14 +262,33 @@  int run_system_cmd(const char *cmd)
 	int const PIPE_READ = 0;
 	int const PIPE_WRITE = 1;
 	int wstatus, i;
+	bool execute_function = !(cmd && strnlen(cmd, SWUPDATE_GENERAL_STRING_SIZE)) && fn;
 
-	if (!strnlen(cmd, SWUPDATE_GENERAL_STRING_SIZE))
-		return 0;
+	/*
+	 * There are two cases:
+	 * - an external command should be executed (cmd is not NULL)
+	 * - an internal SWUpdate function must be executed in bg process
+	 * Both cannot be executed, the external command has priority
+	 */
 
-	if (strnlen(cmd, SWUPDATE_GENERAL_STRING_SIZE) > SWUPDATE_GENERAL_STRING_SIZE) {
-		ERROR("Command string too long, skipping..");
-		/* do nothing */
-		return -EINVAL;
+	/*
+	 * Check parameter in case of external command or internal function
+	 * that should run in a separate process
+	 */
+	if (!execute_function) {
+		/*
+		 * If no cmd and function are passed, just return without error
+		 * like "nothing was successfully executed"
+		 */
+		if (!cmd)
+			return 0;
+		if (!strnlen(cmd, SWUPDATE_GENERAL_STRING_SIZE))
+			return 0;
+		if (strnlen(cmd, SWUPDATE_GENERAL_STRING_SIZE) > SWUPDATE_GENERAL_STRING_SIZE) {
+			ERROR("Command string too long, skipping..");
+			/* do nothing */
+			return -EINVAL;
+		}
 	}
 
 	/*
@@ -306,10 +332,15 @@  int run_system_cmd(const char *cmd)
 			close(pipes[i][PIPE_WRITE]);
 		}
 
-		ret = execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
-		if (ret) {
-			ERROR("Process %s cannot be started: %s", cmd, strerror(errno));
-			exit(1);
+		if (!execute_function) {
+			ret = execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
+			if (ret) {
+				ERROR("Process %s cannot be started: %s", cmd, strerror(errno));
+				exit(1);
+			}
+		} else {
+			ret = fn->exec(fn->argc, fn->argv);
+			exit(ret);
 		}
 	} else {
 		int fds[npipes];
@@ -397,12 +428,12 @@  int run_system_cmd(const char *cmd)
 
 		if (WIFEXITED(wstatus)) {
 			ret = WEXITSTATUS(wstatus);
-			TRACE("%s command returned %d", cmd, ret);
+			TRACE("%s command returned %d", cmd ? cmd : "", ret);
 		} else if (WIFSIGNALED(wstatus)) {
-			TRACE("(%s) killed by signal %d\n", cmd, WTERMSIG(wstatus));
+			TRACE("(%s) killed by signal %d\n", cmd ? : "", WTERMSIG(wstatus));
 			ret = -1;
 		} else {
-			TRACE("(%s) not exited nor killed!\n", cmd);
+			TRACE("(%s) not exited nor killed!\n", cmd ? cmd : "");
 			ret = -1;
 		}
 	}
@@ -410,6 +441,19 @@  int run_system_cmd(const char *cmd)
 	return ret;
 }
 
+int run_system_cmd(const char *cmd) {
+	return __run_cmd(cmd, NULL);
+}
+
+int run_function_background(void *fn, int argc, char **argv) {
+	bgtask bg;
+
+	bg.exec = fn;
+	bg.argc = argc;
+	bg.argv = argv;
+
+	return __run_cmd(NULL, &bg);
+}
 /*
  * The handler supervises the subprocesses
  * (Downloader, Webserver, Suricatta)
diff --git a/include/pctl.h b/include/pctl.h
index 82b6e63..8136ced 100644
--- a/include/pctl.h
+++ b/include/pctl.h
@@ -49,5 +49,6 @@  void sigchld_handler (int __attribute__ ((__unused__)) signum);
 int pctl_getfd_from_type(sourcetype s);
 const char *pctl_getname_from_type(sourcetype s);
 int run_system_cmd(const char *cmd);
+int run_function_background(void *fn, int argc, char **argv);
 
 #endif