gkdbus: Fix underflow and unreachable code bug
[platform/upstream/glib.git] / gio / gsubprocesslauncher.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright © 2012 Red Hat, Inc.
4  * Copyright © 2012-2013 Canonical Limited
5  *
6  * SPDX-License-Identifier: LGPL-2.1-or-later
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * See the included COPYING file for more information.
14  *
15  * Authors: Colin Walters <walters@verbum.org>
16  *          Ryan Lortie <desrt@desrt.ca>
17  */
18
19 /**
20  * SECTION:gsubprocesslauncher
21  * @title: GSubprocess Launcher
22  * @short_description: Environment options for launching a child process
23  * @include: gio/gio.h
24  *
25  * This class contains a set of options for launching child processes,
26  * such as where its standard input and output will be directed, the
27  * argument list, the environment, and more.
28  *
29  * While the #GSubprocess class has high level functions covering
30  * popular cases, use of this class allows access to more advanced
31  * options.  It can also be used to launch multiple subprocesses with
32  * a similar configuration.
33  *
34  * Since: 2.40
35  */
36
37 #define ALL_STDIN_FLAGS         (G_SUBPROCESS_FLAGS_STDIN_PIPE |        \
38                                  G_SUBPROCESS_FLAGS_STDIN_INHERIT)
39 #define ALL_STDOUT_FLAGS        (G_SUBPROCESS_FLAGS_STDOUT_PIPE |       \
40                                  G_SUBPROCESS_FLAGS_STDOUT_SILENCE)
41 #define ALL_STDERR_FLAGS        (G_SUBPROCESS_FLAGS_STDERR_PIPE |       \
42                                  G_SUBPROCESS_FLAGS_STDERR_SILENCE |    \
43                                  G_SUBPROCESS_FLAGS_STDERR_MERGE)
44
45 #include "config.h"
46
47 #include "gsubprocesslauncher-private.h"
48 #include "gioenumtypes.h"
49 #include "gsubprocess.h"
50 #include "ginitable.h"
51 #include "gioerror.h"
52
53 #ifdef G_OS_UNIX
54 #include <unistd.h>
55 #include <fcntl.h>
56 #endif
57
58 typedef GObjectClass GSubprocessLauncherClass;
59
60 G_DEFINE_TYPE (GSubprocessLauncher, g_subprocess_launcher, G_TYPE_OBJECT)
61
62 static gboolean
63 verify_disposition (const gchar      *stream_name,
64                     GSubprocessFlags  filtered_flags,
65                     gint              fd,
66                     const gchar      *filename)
67 {
68   guint n_bits;
69
70   if (!filtered_flags)
71     n_bits = 0;
72   else if (((filtered_flags - 1) & filtered_flags) == 0)
73     n_bits = 1;
74   else
75     n_bits = 2; /* ...or more */
76
77   if (n_bits + (fd >= 0) + (filename != NULL) > 1)
78     {
79       GString *err;
80
81       err = g_string_new (NULL);
82       if (n_bits)
83         {
84           GFlagsClass *class;
85           guint i;
86
87           class = g_type_class_peek (G_TYPE_SUBPROCESS_FLAGS);
88
89           for (i = 0; i < class->n_values; i++)
90             {
91               const GFlagsValue *value = &class->values[i];
92
93               if (filtered_flags & value->value)
94                 g_string_append_printf (err, " %s", value->value_name);
95             }
96
97           g_type_class_unref (class);
98         }
99
100       if (fd >= 0)
101         g_string_append_printf (err, " g_subprocess_launcher_take_%s_fd()", stream_name);
102
103       if (filename)
104         g_string_append_printf (err, " g_subprocess_launcher_set_%s_file_path()", stream_name);
105
106       g_critical ("You may specify at most one disposition for the %s stream, but you specified:%s.",
107                   stream_name, err->str);
108       g_string_free (err, TRUE);
109
110       return FALSE;
111     }
112
113   return TRUE;
114 }
115
116 static gboolean
117 verify_flags (GSubprocessFlags flags)
118 {
119   return verify_disposition ("stdin", flags & ALL_STDIN_FLAGS, -1, NULL) &&
120          verify_disposition ("stdout", flags & ALL_STDOUT_FLAGS, -1, NULL) &&
121          verify_disposition ("stderr", flags & ALL_STDERR_FLAGS, -1, NULL);
122 }
123
124 static void
125 g_subprocess_launcher_set_property (GObject *object, guint prop_id,
126                                     const GValue *value, GParamSpec *pspec)
127 {
128   GSubprocessLauncher *launcher = G_SUBPROCESS_LAUNCHER (object);
129
130   g_assert (prop_id == 1);
131
132   if (verify_flags (g_value_get_flags (value)))
133     launcher->flags = g_value_get_flags (value);
134 }
135
136 static void
137 g_subprocess_launcher_dispose (GObject *object)
138 {
139   GSubprocessLauncher *self = G_SUBPROCESS_LAUNCHER (object);
140
141 #ifdef G_OS_UNIX
142   g_clear_pointer (&self->stdin_path, g_free);
143   g_clear_pointer (&self->stdout_path, g_free);
144   g_clear_pointer (&self->stderr_path, g_free);
145
146   g_subprocess_launcher_close (self);
147
148   if (self->child_setup_destroy_notify)
149     (* self->child_setup_destroy_notify) (self->child_setup_user_data);
150   self->child_setup_destroy_notify = NULL;
151   self->child_setup_user_data = NULL;
152 #endif
153
154   g_clear_pointer (&self->envp, g_strfreev);
155   g_clear_pointer (&self->cwd, g_free);
156
157   G_OBJECT_CLASS (g_subprocess_launcher_parent_class)->dispose (object);
158 }
159
160 static void
161 g_subprocess_launcher_init (GSubprocessLauncher  *self)
162 {
163   self->envp = g_get_environ ();
164
165 #ifdef G_OS_UNIX
166   self->stdin_fd = -1;
167   self->stdout_fd = -1;
168   self->stderr_fd = -1;
169   self->source_fds = g_array_new (FALSE, 0, sizeof (int));
170   self->target_fds = g_array_new (FALSE, 0, sizeof (int));
171 #endif
172 }
173
174 static void
175 g_subprocess_launcher_class_init (GSubprocessLauncherClass *class)
176 {
177   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
178
179   gobject_class->set_property = g_subprocess_launcher_set_property;
180   gobject_class->dispose = g_subprocess_launcher_dispose;
181
182   g_object_class_install_property (gobject_class, 1,
183                                    g_param_spec_flags ("flags", "Flags", "GSubprocessFlags for launched processes",
184                                                        G_TYPE_SUBPROCESS_FLAGS, 0, G_PARAM_WRITABLE |
185                                                        G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY));
186 }
187
188 /**
189  * g_subprocess_launcher_new:
190  * @flags: #GSubprocessFlags
191  *
192  * Creates a new #GSubprocessLauncher.
193  *
194  * The launcher is created with the default options.  A copy of the
195  * environment of the calling process is made at the time of this call
196  * and will be used as the environment that the process is launched in.
197  *
198  * Since: 2.40
199  **/
200 GSubprocessLauncher *
201 g_subprocess_launcher_new (GSubprocessFlags flags)
202 {
203   if (!verify_flags (flags))
204     return NULL;
205
206   return g_object_new (G_TYPE_SUBPROCESS_LAUNCHER,
207                        "flags", flags,
208                        NULL);
209 }
210
211 /**
212  * g_subprocess_launcher_set_environ:
213  * @self: a #GSubprocessLauncher
214  * @env: (array zero-terminated=1) (element-type filename) (transfer none):
215  *     the replacement environment
216  *
217  * Replace the entire environment of processes launched from this
218  * launcher with the given 'environ' variable.
219  *
220  * Typically you will build this variable by using g_listenv() to copy
221  * the process 'environ' and using the functions g_environ_setenv(),
222  * g_environ_unsetenv(), etc.
223  *
224  * As an alternative, you can use g_subprocess_launcher_setenv(),
225  * g_subprocess_launcher_unsetenv(), etc.
226  *
227  * Pass an empty array to set an empty environment. Pass %NULL to inherit the
228  * parent process’ environment. As of GLib 2.54, the parent process’ environment
229  * will be copied when g_subprocess_launcher_set_environ() is called.
230  * Previously, it was copied when the subprocess was executed. This means the
231  * copied environment may now be modified (using g_subprocess_launcher_setenv(),
232  * etc.) before launching the subprocess.
233  *
234  * On UNIX, all strings in this array can be arbitrary byte strings.
235  * On Windows, they should be in UTF-8.
236  *
237  * Since: 2.40
238  **/
239 void
240 g_subprocess_launcher_set_environ (GSubprocessLauncher  *self,
241                                    gchar               **env)
242 {
243   g_strfreev (self->envp);
244   self->envp = g_strdupv (env);
245
246   if (self->envp == NULL)
247     self->envp = g_get_environ ();
248 }
249
250 /**
251  * g_subprocess_launcher_setenv:
252  * @self: a #GSubprocessLauncher
253  * @variable: (type filename): the environment variable to set,
254  *     must not contain '='
255  * @value: (type filename): the new value for the variable
256  * @overwrite: whether to change the variable if it already exists
257  *
258  * Sets the environment variable @variable in the environment of
259  * processes launched from this launcher.
260  *
261  * On UNIX, both the variable's name and value can be arbitrary byte
262  * strings, except that the variable's name cannot contain '='.
263  * On Windows, they should be in UTF-8.
264  *
265  * Since: 2.40
266  **/
267 void
268 g_subprocess_launcher_setenv (GSubprocessLauncher *self,
269                               const gchar         *variable,
270                               const gchar         *value,
271                               gboolean             overwrite)
272 {
273   self->envp = g_environ_setenv (self->envp, variable, value, overwrite);
274 }
275
276 /**
277  * g_subprocess_launcher_unsetenv:
278  * @self: a #GSubprocessLauncher
279  * @variable: (type filename): the environment variable to unset,
280  *     must not contain '='
281  *
282  * Removes the environment variable @variable from the environment of
283  * processes launched from this launcher.
284  *
285  * On UNIX, the variable's name can be an arbitrary byte string not
286  * containing '='. On Windows, it should be in UTF-8.
287  *
288  * Since: 2.40
289  **/
290 void
291 g_subprocess_launcher_unsetenv (GSubprocessLauncher *self,
292                                 const gchar         *variable)
293 {
294   self->envp = g_environ_unsetenv (self->envp, variable);
295 }
296
297 /**
298  * g_subprocess_launcher_getenv:
299  * @self: a #GSubprocessLauncher
300  * @variable: (type filename): the environment variable to get
301  *
302  * Returns the value of the environment variable @variable in the
303  * environment of processes launched from this launcher.
304  *
305  * On UNIX, the returned string can be an arbitrary byte string.
306  * On Windows, it will be UTF-8.
307  *
308  * Returns: (nullable) (type filename): the value of the environment variable,
309  *     %NULL if unset
310  *
311  * Since: 2.40
312  **/
313 const gchar *
314 g_subprocess_launcher_getenv (GSubprocessLauncher *self,
315                               const gchar         *variable)
316 {
317   return g_environ_getenv (self->envp, variable);
318 }
319
320 /**
321  * g_subprocess_launcher_set_cwd:
322  * @self: a #GSubprocessLauncher
323  * @cwd: (type filename): the cwd for launched processes
324  *
325  * Sets the current working directory that processes will be launched
326  * with.
327  *
328  * By default processes are launched with the current working directory
329  * of the launching process at the time of launch.
330  *
331  * Since: 2.40
332  **/
333 void
334 g_subprocess_launcher_set_cwd (GSubprocessLauncher *self,
335                                const gchar         *cwd)
336 {
337   g_free (self->cwd);
338   self->cwd = g_strdup (cwd);
339 }
340
341 /**
342  * g_subprocess_launcher_set_flags:
343  * @self: a #GSubprocessLauncher
344  * @flags: #GSubprocessFlags
345  *
346  * Sets the flags on the launcher.
347  *
348  * The default flags are %G_SUBPROCESS_FLAGS_NONE.
349  *
350  * You may not set flags that specify conflicting options for how to
351  * handle a particular stdio stream (eg: specifying both
352  * %G_SUBPROCESS_FLAGS_STDIN_PIPE and
353  * %G_SUBPROCESS_FLAGS_STDIN_INHERIT).
354  *
355  * You may also not set a flag that conflicts with a previous call to a
356  * function like g_subprocess_launcher_set_stdin_file_path() or
357  * g_subprocess_launcher_take_stdout_fd().
358  *
359  * Since: 2.40
360  **/
361 void
362 g_subprocess_launcher_set_flags (GSubprocessLauncher *self,
363                                  GSubprocessFlags     flags)
364 {
365   const gchar *stdin_path = NULL, *stdout_path = NULL, *stderr_path = NULL;
366   gint stdin_fd = -1, stdout_fd = -1, stderr_fd = -1;
367
368 #ifdef G_OS_UNIX
369   stdin_fd = self->stdin_fd;
370   stdout_fd = self->stdout_fd;
371   stderr_fd = self->stderr_fd;
372   stdin_path = self->stdin_path;
373   stdout_path = self->stdout_path;
374   stderr_path = self->stderr_path;
375 #endif
376
377   if (verify_disposition ("stdin", flags & ALL_STDIN_FLAGS, stdin_fd, stdin_path) &&
378       verify_disposition ("stdout", flags & ALL_STDOUT_FLAGS, stdout_fd, stdout_path) &&
379       verify_disposition ("stderr", flags & ALL_STDERR_FLAGS, stderr_fd, stderr_path))
380     self->flags = flags;
381 }
382
383 #ifdef G_OS_UNIX
384 static void
385 assign_fd (gint *fd_ptr, gint fd)
386 {
387   gint flags;
388
389   if (*fd_ptr != -1)
390     close (*fd_ptr);
391
392   *fd_ptr = fd;
393
394   if (fd != -1)
395     {
396       /* best effort */
397       flags = fcntl (fd, F_GETFD);
398       if (~flags & FD_CLOEXEC)
399         fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
400     }
401 }
402
403 /**
404  * g_subprocess_launcher_set_stdin_file_path:
405  * @self: a #GSubprocessLauncher
406  * @path: (type filename) (nullable: a filename or %NULL
407  *
408  * Sets the file path to use as the stdin for spawned processes.
409  *
410  * If @path is %NULL then any previously given path is unset.
411  *
412  * The file must exist or spawning the process will fail.
413  *
414  * You may not set a stdin file path if a stdin fd is already set or if
415  * the launcher flags contain any flags directing stdin elsewhere.
416  *
417  * This feature is only available on UNIX.
418  *
419  * Since: 2.40
420  **/
421 void
422 g_subprocess_launcher_set_stdin_file_path (GSubprocessLauncher *self,
423                                            const gchar         *path)
424 {
425   if (verify_disposition ("stdin", self->flags & ALL_STDIN_FLAGS, self->stdin_fd, path))
426     {
427       g_free (self->stdin_path);
428       self->stdin_path = g_strdup (path);
429     }
430 }
431
432 /**
433  * g_subprocess_launcher_take_stdin_fd:
434  * @self: a #GSubprocessLauncher
435  * @fd: a file descriptor, or -1
436  *
437  * Sets the file descriptor to use as the stdin for spawned processes.
438  *
439  * If @fd is -1 then any previously given fd is unset.
440  *
441  * Note that if your intention is to have the stdin of the calling
442  * process inherited by the child then %G_SUBPROCESS_FLAGS_STDIN_INHERIT
443  * is a better way to go about doing that.
444  *
445  * The passed @fd is noted but will not be touched in the current
446  * process.  It is therefore necessary that it be kept open by the
447  * caller until the subprocess is spawned.  The file descriptor will
448  * also not be explicitly closed on the child side, so it must be marked
449  * O_CLOEXEC if that's what you want.
450  *
451  * You may not set a stdin fd if a stdin file path is already set or if
452  * the launcher flags contain any flags directing stdin elsewhere.
453  *
454  * This feature is only available on UNIX.
455  *
456  * Since: 2.40
457  **/
458 void
459 g_subprocess_launcher_take_stdin_fd (GSubprocessLauncher *self,
460                                      gint                 fd)
461 {
462   if (verify_disposition ("stdin", self->flags & ALL_STDIN_FLAGS, fd, self->stdin_path))
463     assign_fd (&self->stdin_fd, fd);
464 }
465
466 /**
467  * g_subprocess_launcher_set_stdout_file_path:
468  * @self: a #GSubprocessLauncher
469  * @path: (type filename) (nullable): a filename or %NULL
470  *
471  * Sets the file path to use as the stdout for spawned processes.
472  *
473  * If @path is %NULL then any previously given path is unset.
474  *
475  * The file will be created or truncated when the process is spawned, as
476  * would be the case if using '>' at the shell.
477  *
478  * You may not set a stdout file path if a stdout fd is already set or
479  * if the launcher flags contain any flags directing stdout elsewhere.
480  *
481  * This feature is only available on UNIX.
482  *
483  * Since: 2.40
484  **/
485 void
486 g_subprocess_launcher_set_stdout_file_path (GSubprocessLauncher *self,
487                                             const gchar         *path)
488 {
489   if (verify_disposition ("stdout", self->flags & ALL_STDOUT_FLAGS, self->stdout_fd, path))
490     {
491       g_free (self->stdout_path);
492       self->stdout_path = g_strdup (path);
493     }
494 }
495
496 /**
497  * g_subprocess_launcher_take_stdout_fd:
498  * @self: a #GSubprocessLauncher
499  * @fd: a file descriptor, or -1
500  *
501  * Sets the file descriptor to use as the stdout for spawned processes.
502  *
503  * If @fd is -1 then any previously given fd is unset.
504  *
505  * Note that the default behaviour is to pass stdout through to the
506  * stdout of the parent process.
507  *
508  * The passed @fd is noted but will not be touched in the current
509  * process.  It is therefore necessary that it be kept open by the
510  * caller until the subprocess is spawned.  The file descriptor will
511  * also not be explicitly closed on the child side, so it must be marked
512  * O_CLOEXEC if that's what you want.
513  *
514  * You may not set a stdout fd if a stdout file path is already set or
515  * if the launcher flags contain any flags directing stdout elsewhere.
516  *
517  * This feature is only available on UNIX.
518  *
519  * Since: 2.40
520  **/
521 void
522 g_subprocess_launcher_take_stdout_fd (GSubprocessLauncher *self,
523                                       gint                 fd)
524 {
525   if (verify_disposition ("stdout", self->flags & ALL_STDOUT_FLAGS, fd, self->stdout_path))
526     assign_fd (&self->stdout_fd, fd);
527 }
528
529 /**
530  * g_subprocess_launcher_set_stderr_file_path:
531  * @self: a #GSubprocessLauncher
532  * @path: (type filename) (nullable): a filename or %NULL
533  *
534  * Sets the file path to use as the stderr for spawned processes.
535  *
536  * If @path is %NULL then any previously given path is unset.
537  *
538  * The file will be created or truncated when the process is spawned, as
539  * would be the case if using '2>' at the shell.
540  *
541  * If you want to send both stdout and stderr to the same file then use
542  * %G_SUBPROCESS_FLAGS_STDERR_MERGE.
543  *
544  * You may not set a stderr file path if a stderr fd is already set or
545  * if the launcher flags contain any flags directing stderr elsewhere.
546  *
547  * This feature is only available on UNIX.
548  *
549  * Since: 2.40
550  **/
551 void
552 g_subprocess_launcher_set_stderr_file_path (GSubprocessLauncher *self,
553                                             const gchar         *path)
554 {
555   if (verify_disposition ("stderr", self->flags & ALL_STDERR_FLAGS, self->stderr_fd, path))
556     {
557       g_free (self->stderr_path);
558       self->stderr_path = g_strdup (path);
559     }
560 }
561
562 /**
563  * g_subprocess_launcher_take_stderr_fd:
564  * @self: a #GSubprocessLauncher
565  * @fd: a file descriptor, or -1
566  *
567  * Sets the file descriptor to use as the stderr for spawned processes.
568  *
569  * If @fd is -1 then any previously given fd is unset.
570  *
571  * Note that the default behaviour is to pass stderr through to the
572  * stderr of the parent process.
573  *
574  * The passed @fd belongs to the #GSubprocessLauncher.  It will be
575  * automatically closed when the launcher is finalized.  The file
576  * descriptor will also be closed on the child side when executing the
577  * spawned process.
578  *
579  * You may not set a stderr fd if a stderr file path is already set or
580  * if the launcher flags contain any flags directing stderr elsewhere.
581  *
582  * This feature is only available on UNIX.
583  *
584  * Since: 2.40
585  **/
586 void
587 g_subprocess_launcher_take_stderr_fd (GSubprocessLauncher *self,
588                                      gint                 fd)
589 {
590   if (verify_disposition ("stderr", self->flags & ALL_STDERR_FLAGS, fd, self->stderr_path))
591     assign_fd (&self->stderr_fd, fd);
592 }
593
594 /**
595  * g_subprocess_launcher_take_fd:
596  * @self: a #GSubprocessLauncher
597  * @source_fd: File descriptor in parent process
598  * @target_fd: Target descriptor for child process
599  *
600  * Transfer an arbitrary file descriptor from parent process to the
601  * child.  This function takes ownership of the @source_fd; it will be closed
602  * in the parent when @self is freed.
603  *
604  * By default, all file descriptors from the parent will be closed.
605  * This function allows you to create (for example) a custom `pipe()` or
606  * `socketpair()` before launching the process, and choose the target
607  * descriptor in the child.
608  *
609  * An example use case is GNUPG, which has a command line argument
610  * `--passphrase-fd` providing a file descriptor number where it expects
611  * the passphrase to be written.
612  */
613 void
614 g_subprocess_launcher_take_fd (GSubprocessLauncher   *self,
615                                gint                   source_fd,
616                                gint                   target_fd)
617 {
618   if (self->source_fds != NULL && self->target_fds != NULL)
619     {
620       g_array_append_val (self->source_fds, source_fd);
621       g_array_append_val (self->target_fds, target_fd);
622     }
623 }
624
625 /**
626  * g_subprocess_launcher_close:
627  * @self: a #GSubprocessLauncher
628  *
629  * Closes all the file descriptors previously passed to the object with
630  * g_subprocess_launcher_take_fd(), g_subprocess_launcher_take_stderr_fd(), etc.
631  *
632  * After calling this method, any subsequent calls to g_subprocess_launcher_spawn() or g_subprocess_launcher_spawnv() will
633  * return %G_IO_ERROR_CLOSED. This method is idempotent if
634  * called more than once.
635  *
636  * This function is called automatically when the #GSubprocessLauncher
637  * is disposed, but is provided separately so that garbage collected
638  * language bindings can call it earlier to guarantee when FDs are closed.
639  *
640  * Since: 2.68
641  */
642 void
643 g_subprocess_launcher_close (GSubprocessLauncher *self)
644 {
645   guint i;
646
647   g_return_if_fail (G_IS_SUBPROCESS_LAUNCHER (self));
648
649   if (self->stdin_fd != -1)
650     close (self->stdin_fd);
651   self->stdin_fd = -1;
652
653   if (self->stdout_fd != -1)
654     close (self->stdout_fd);
655   self->stdout_fd = -1;
656
657   if (self->stderr_fd != -1)
658     close (self->stderr_fd);
659   self->stderr_fd = -1;
660
661   if (self->source_fds)
662     {
663       g_assert (self->target_fds != NULL);
664       g_assert (self->source_fds->len == self->target_fds->len);
665
666       /* Note: Don’t close the target_fds, as they’re only valid FDs in the
667        * child process. This code never executes in the child process. */
668       for (i = 0; i < self->source_fds->len; i++)
669         (void) close (g_array_index (self->source_fds, int, i));
670
671       g_clear_pointer (&self->source_fds, g_array_unref);
672       g_clear_pointer (&self->target_fds, g_array_unref);
673     }
674
675   self->closed_fd = TRUE;
676 }
677
678 /**
679  * g_subprocess_launcher_set_child_setup: (skip)
680  * @self: a #GSubprocessLauncher
681  * @child_setup: (closure user_data): a #GSpawnChildSetupFunc to use as the child setup function
682  * @user_data: user data for @child_setup
683  * @destroy_notify: a #GDestroyNotify for @user_data
684  *
685  * Sets up a child setup function.
686  *
687  * The child setup function will be called after fork() but before
688  * exec() on the child's side.
689  *
690  * @destroy_notify will not be automatically called on the child's side
691  * of the fork().  It will only be called when the last reference on the
692  * #GSubprocessLauncher is dropped or when a new child setup function is
693  * given.
694  *
695  * %NULL can be given as @child_setup to disable the functionality.
696  *
697  * Child setup functions are only available on UNIX.
698  *
699  * Since: 2.40
700  **/
701 void
702 g_subprocess_launcher_set_child_setup (GSubprocessLauncher  *self,
703                                        GSpawnChildSetupFunc  child_setup,
704                                        gpointer              user_data,
705                                        GDestroyNotify        destroy_notify)
706 {
707   if (self->child_setup_destroy_notify)
708     (* self->child_setup_destroy_notify) (self->child_setup_user_data);
709
710   self->child_setup_func = child_setup;
711   self->child_setup_user_data = user_data;
712   self->child_setup_destroy_notify = destroy_notify;
713 }
714 #endif
715
716 /**
717  * g_subprocess_launcher_spawn:
718  * @self: a #GSubprocessLauncher
719  * @error: Error
720  * @argv0: Command line arguments
721  * @...: Continued arguments, %NULL terminated
722  *
723  * Creates a #GSubprocess given a provided varargs list of arguments.
724  *
725  * Since: 2.40
726  * Returns: (transfer full): A new #GSubprocess, or %NULL on error (and @error will be set)
727  **/
728 GSubprocess *
729 g_subprocess_launcher_spawn (GSubprocessLauncher  *launcher,
730                              GError              **error,
731                              const gchar          *argv0,
732                              ...)
733 {
734   GSubprocess *result;
735   GPtrArray *args;
736   const gchar *arg;
737   va_list ap;
738
739   g_return_val_if_fail (argv0 != NULL && argv0[0] != '\0', NULL);
740   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
741
742   args = g_ptr_array_new ();
743
744   va_start (ap, argv0);
745   g_ptr_array_add (args, (gchar *) argv0);
746   while ((arg = va_arg (ap, const gchar *)))
747     g_ptr_array_add (args, (gchar *) arg);
748
749   g_ptr_array_add (args, NULL);
750   va_end (ap);
751
752   result = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
753
754   g_ptr_array_free (args, TRUE);
755
756   return result;
757
758 }
759
760 /**
761  * g_subprocess_launcher_spawnv:
762  * @self: a #GSubprocessLauncher
763  * @argv: (array zero-terminated=1) (element-type filename): Command line arguments
764  * @error: Error
765  *
766  * Creates a #GSubprocess given a provided array of arguments.
767  *
768  * Since: 2.40
769  * Returns: (transfer full): A new #GSubprocess, or %NULL on error (and @error will be set)
770  **/
771 GSubprocess *
772 g_subprocess_launcher_spawnv (GSubprocessLauncher  *launcher,
773                               const gchar * const  *argv,
774                               GError              **error)
775 {
776   GSubprocess *subprocess;
777
778   g_return_val_if_fail (argv != NULL && argv[0] != NULL && argv[0][0] != '\0', NULL);
779
780 #ifdef G_OS_UNIX
781   if (launcher->closed_fd)
782     {
783       g_set_error (error,
784                    G_IO_ERROR,
785                    G_IO_ERROR_CLOSED,
786                    "Can't spawn a new child because a passed file descriptor has been closed.");
787       return NULL;
788     }
789 #endif
790
791   subprocess = g_object_new (G_TYPE_SUBPROCESS,
792                              "argv", argv,
793                              "flags", launcher->flags,
794                              NULL);
795   g_subprocess_set_launcher (subprocess, launcher);
796
797   if (!g_initable_init (G_INITABLE (subprocess), NULL, error))
798     {
799       g_object_unref (subprocess);
800       return NULL;
801     }
802
803   return subprocess;
804 }