Browse Source

libobs: Add os_process_pipe_create2

This new API uses the os_process_args_t object rather than a string for
more safe and sane command line argument handling.
derrod 1 year ago
parent
commit
9bc3082402
3 changed files with 88 additions and 6 deletions
  1. 22 6
      libobs/util/pipe-posix.c
  2. 64 0
      libobs/util/pipe-windows.c
  3. 2 0
      libobs/util/pipe.h

+ 22 - 6
libobs/util/pipe-posix.c

@@ -31,14 +31,14 @@ struct os_process_pipe {
 	FILE *err_file;
 };
 
-os_process_pipe_t *os_process_pipe_create(const char *cmd_line,
-					  const char *type)
+os_process_pipe_t *os_process_pipe_create_internal(const char *bin, char **argv,
+						   const char *type)
 {
 	struct os_process_pipe process_pipe = {0};
 	struct os_process_pipe *out;
 	posix_spawn_file_actions_t file_actions;
 
-	if (!cmd_line || !type) {
+	if (!bin || !argv || !type) {
 		return NULL;
 	}
 
@@ -94,9 +94,8 @@ os_process_pipe_t *os_process_pipe_create(const char *cmd_line,
 					 STDERR_FILENO);
 
 	int pid;
-	char *argv[4] = {"sh", "-c", (char *)cmd_line, NULL};
-
-	int ret = posix_spawn(&pid, "/bin/sh", &file_actions, NULL, argv, NULL);
+	int ret = posix_spawn(&pid, bin, &file_actions, NULL,
+			      (char *const *)argv, NULL);
 
 	posix_spawn_file_actions_destroy(&file_actions);
 
@@ -127,6 +126,23 @@ os_process_pipe_t *os_process_pipe_create(const char *cmd_line,
 	return out;
 }
 
+os_process_pipe_t *os_process_pipe_create(const char *cmd_line,
+					  const char *type)
+{
+	if (!cmd_line)
+		return NULL;
+
+	char *argv[3] = {"-c", (char *)cmd_line, NULL};
+	return os_process_pipe_create_internal("/bin/sh", argv, type);
+}
+
+os_process_pipe_t *os_process_pipe_create2(const os_process_args_t *args,
+					   const char *type)
+{
+	char **argv = os_process_args_get_argv(args);
+	return os_process_pipe_create_internal(argv[0], argv, type);
+}
+
 int os_process_pipe_destroy(os_process_pipe_t *pp)
 {
 	int ret = 0;

+ 64 - 0
libobs/util/pipe-windows.c

@@ -19,6 +19,7 @@
 
 #include "platform.h"
 #include "bmem.h"
+#include "dstr.h"
 #include "pipe.h"
 
 struct os_process_pipe {
@@ -145,6 +146,69 @@ error:
 	return NULL;
 }
 
+static inline void add_backslashes(struct dstr *str, size_t count)
+{
+	while (count--)
+		dstr_cat_ch(str, '\\');
+}
+
+os_process_pipe_t *os_process_pipe_create2(const os_process_args_t *args,
+					   const char *type)
+{
+	struct dstr cmd_line = {0};
+
+	/* Convert list to command line as Windows does not have any API that
+	 * allows us to just pass argc/argv. */
+	char **argv = os_process_args_get_argv(args);
+
+	/* Based on Python subprocess module implementation. */
+	while (*argv) {
+		size_t bs_count = 0;
+		const char *arg = *argv;
+		bool needs_quotes = strlen(arg) == 0 ||
+				    strstr(arg, " ") != NULL ||
+				    strstr(arg, "\t") != NULL;
+
+		if (cmd_line.len)
+			dstr_cat_ch(&cmd_line, ' ');
+		if (needs_quotes)
+			dstr_cat_ch(&cmd_line, '"');
+
+		while (*arg) {
+			if (*arg == '\\') {
+				bs_count++;
+			} else if (*arg == '"') {
+				add_backslashes(&cmd_line, bs_count * 2);
+				dstr_cat(&cmd_line, "\\\"");
+				bs_count = 0;
+			} else {
+				if (bs_count) {
+					add_backslashes(&cmd_line, bs_count);
+					bs_count = 0;
+				}
+				dstr_cat_ch(&cmd_line, *arg);
+			}
+
+			arg++;
+		}
+
+		if (bs_count)
+			add_backslashes(&cmd_line, bs_count);
+
+		if (needs_quotes) {
+			add_backslashes(&cmd_line, bs_count);
+			dstr_cat_ch(&cmd_line, '"');
+		}
+
+		argv++;
+	}
+
+	os_process_pipe_t *ret = os_process_pipe_create(cmd_line.array, type);
+
+	dstr_free(&cmd_line);
+	return ret;
+}
+
 int os_process_pipe_destroy(os_process_pipe_t *pp)
 {
 	int ret = 0;

+ 2 - 0
libobs/util/pipe.h

@@ -30,6 +30,8 @@ typedef struct os_process_args os_process_args_t;
 
 EXPORT os_process_pipe_t *os_process_pipe_create(const char *cmd_line,
 						 const char *type);
+EXPORT os_process_pipe_t *os_process_pipe_create2(const os_process_args_t *args,
+						  const char *type);
 EXPORT int os_process_pipe_destroy(os_process_pipe_t *pp);
 
 EXPORT size_t os_process_pipe_read(os_process_pipe_t *pp, uint8_t *data,