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