[glib: 2/3] gspawn: Avoid considering out parameters as inputs




commit a84068d12aad768abf1bb3220d1d19ed8432b7c0
Author: Nicola Fontana <ntd entidi it>
Date:   Mon May 2 11:09:11 2022 +0200

    gspawn: Avoid considering out parameters as inputs
    
    The g_spawn_async_with_pipes_and_fds() API changes its behavior
    depending on the states of out parameters. Apart from the philosophical
    inconsistency, this poses some real problems, e.g. in Lua bindings:
    
        https://github.com/lgi-devs/lgi/issues/277
    
    This adds three new spawn flags to allow specifying the wanted behavior
    explicitly and does not assert on the state of the output parameters.

 glib/gspawn.c | 44 +++++++++++++++++++++++++++++---------------
 glib/gspawn.h | 35 ++++++++++++++++++++++++++++++++++-
 2 files changed, 63 insertions(+), 16 deletions(-)
---
diff --git a/glib/gspawn.c b/glib/gspawn.c
index a4ea758c48..5496b075d4 100644
--- a/glib/gspawn.c
+++ b/glib/gspawn.c
@@ -67,6 +67,10 @@
 #include "glibintl.h"
 #include "glib-unix.h"
 
+#define INHERITS_OR_NULL_STDIN  (G_SPAWN_STDIN_FROM_DEV_NULL | G_SPAWN_CHILD_INHERITS_STDIN)
+#define INHERITS_OR_NULL_STDOUT (G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_CHILD_INHERITS_STDOUT)
+#define INHERITS_OR_NULL_STDERR (G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_CHILD_INHERITS_STDERR)
+
 /* posix_spawn() is assumed the fastest way to spawn, but glibc's
  * implementation was buggy before glibc 2.24, so avoid it on old versions.
  */
@@ -728,17 +732,23 @@ g_spawn_async_with_pipes (const gchar          *working_directory,
  * @envp. If both %G_SPAWN_SEARCH_PATH and %G_SPAWN_SEARCH_PATH_FROM_ENVP
  * are used, the value from @envp takes precedence over the environment.
  *
+ * %G_SPAWN_CHILD_INHERITS_STDIN means that the child will inherit the parent's
+ * standard input (by default, the child's standard input is attached to
+ * `/dev/null`). %G_SPAWN_STDIN_FROM_DEV_NULL explicitly imposes the default
+ * behavior. Both flags cannot be enabled at the same time and, in both cases,
+ * the @stdin_pipe_out argument is ignored.
+ *
  * %G_SPAWN_STDOUT_TO_DEV_NULL means that the child's standard output
- * will be discarded, instead of going to the same location as the parent's
- * standard output. If you use this flag, @stdout_pipe_out must be %NULL.
+ * will be discarded (by default, it goes to the same location as the parent's
+ * standard output). %G_SPAWN_CHILD_INHERITS_STDOUT explicitly imposes the
+ * default behavior. Both flags cannot be enabled at the same time and, in
+ * both cases, the @stdout_pipe_out argument is ignored.
  *
  * %G_SPAWN_STDERR_TO_DEV_NULL means that the child's standard error
- * will be discarded, instead of going to the same location as the parent's
- * standard error. If you use this flag, @stderr_pipe_out must be %NULL.
- *
- * %G_SPAWN_CHILD_INHERITS_STDIN means that the child will inherit the parent's
- * standard input (by default, the child's standard input is attached to
- * `/dev/null`). If you use this flag, @stdin_pipe_out must be %NULL.
+ * will be discarded (by default, it goes to the same location as the parent's
+ * standard error). %G_SPAWN_CHILD_INHERITS_STDERR explicitly imposes the
+ * default behavior. Both flags cannot be enabled at the same time and, in
+ * both cases, the @stderr_pipe_out argument is ignored.
  *
  * It is valid to pass the same FD in multiple parameters (e.g. you can pass
  * a single FD for both @stdout_fd and @stderr_fd, and include it in
@@ -862,18 +872,22 @@ g_spawn_async_with_pipes_and_fds (const gchar           *working_directory,
 {
   g_return_val_if_fail (argv != NULL, FALSE);
   g_return_val_if_fail (argv[0] != NULL, FALSE);
-  g_return_val_if_fail (stdout_pipe_out == NULL ||
-                        !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
-  g_return_val_if_fail (stderr_pipe_out == NULL ||
-                        !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
-  /* can't inherit stdin if we have an input pipe. */
-  g_return_val_if_fail (stdin_pipe_out == NULL ||
-                        !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE);
+  /* can’t both inherit and set pipes to /dev/null */
+  g_return_val_if_fail ((flags & INHERITS_OR_NULL_STDIN) != INHERITS_OR_NULL_STDIN, FALSE);
+  g_return_val_if_fail ((flags & INHERITS_OR_NULL_STDOUT) != INHERITS_OR_NULL_STDOUT, FALSE);
+  g_return_val_if_fail ((flags & INHERITS_OR_NULL_STDERR) != INHERITS_OR_NULL_STDERR, FALSE);
   /* can’t use pipes and stdin/stdout/stderr FDs */
   g_return_val_if_fail (stdin_pipe_out == NULL || stdin_fd < 0, FALSE);
   g_return_val_if_fail (stdout_pipe_out == NULL || stdout_fd < 0, FALSE);
   g_return_val_if_fail (stderr_pipe_out == NULL || stderr_fd < 0, FALSE);
 
+  if ((flags & INHERITS_OR_NULL_STDIN) != 0)
+    stdin_pipe_out = NULL;
+  if ((flags & INHERITS_OR_NULL_STDOUT) != 0)
+    stdout_pipe_out = NULL;
+  if ((flags & INHERITS_OR_NULL_STDERR) != 0)
+    stderr_pipe_out = NULL;
+
   return fork_exec (!(flags & G_SPAWN_DO_NOT_REAP_CHILD),
                     working_directory,
                     (const gchar * const *) argv,
diff --git a/glib/gspawn.h b/glib/gspawn.h
index 3cad30765c..5f89c4dba8 100644
--- a/glib/gspawn.h
+++ b/glib/gspawn.h
@@ -162,6 +162,12 @@ typedef void (* GSpawnChildSetupFunc) (gpointer user_data);
  *     Since: 2.34
  * @G_SPAWN_CLOEXEC_PIPES: create all pipes with the `O_CLOEXEC` flag set.
  *     Since: 2.40
+ * @G_SPAWN_CHILD_INHERITS_STDOUT: the child will inherit the parent's standard output.
+ *     Since: 2.74
+ * @G_SPAWN_CHILD_INHERITS_STDERR: the child will inherit the parent's standard error.
+ *     Since: 2.74
+ * @G_SPAWN_STDIN_FROM_DEV_NULL: the child's standard input is attached to `/dev/null`.
+ *     Since: 2.74
  *
  * Flags passed to g_spawn_sync(), g_spawn_async() and g_spawn_async_with_pipes().
  */
@@ -178,7 +184,34 @@ typedef enum
   G_SPAWN_CHILD_INHERITS_STDIN   = 1 << 5,
   G_SPAWN_FILE_AND_ARGV_ZERO     = 1 << 6,
   G_SPAWN_SEARCH_PATH_FROM_ENVP  = 1 << 7,
-  G_SPAWN_CLOEXEC_PIPES          = 1 << 8
+  G_SPAWN_CLOEXEC_PIPES          = 1 << 8,
+
+  /**
+   * G_SPAWN_CHILD_INHERITS_STDOUT:
+   *
+   * The child will inherit the parent's standard output.
+   *
+   * Since: 2.74
+   */
+  G_SPAWN_CHILD_INHERITS_STDOUT  = 1 << 9,
+
+  /**
+   * G_SPAWN_CHILD_INHERITS_STDERR:
+   *
+   * The child will inherit the parent's standard error.
+   *
+   * Since: 2.74
+   */
+  G_SPAWN_CHILD_INHERITS_STDERR  = 1 << 10,
+
+  /**
+   * G_SPAWN_STDIN_FROM_DEV_NULL:
+   *
+   * The child's standard input is attached to `/dev/null`.
+   *
+   * Since: 2.74
+   */
+  G_SPAWN_STDIN_FROM_DEV_NULL    = 1 << 11
 } GSpawnFlags;
 
 GLIB_AVAILABLE_IN_ALL


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]