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