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