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
G_DEFINE_TYPE(GSubprocessLauncher,g_subprocess_launcher,G_TYPE_OBJECT)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
verify_flags(GSubprocessFlags flags)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
g_subprocess_launcher_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)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
g_subprocess_launcher_finalize(GObject * object)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
g_subprocess_launcher_init(GSubprocessLauncher * self)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
g_subprocess_launcher_class_init(GSubprocessLauncherClass * class)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 *
g_subprocess_launcher_new(GSubprocessFlags flags)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
g_subprocess_launcher_set_environ(GSubprocessLauncher * self,gchar ** env)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
g_subprocess_launcher_setenv(GSubprocessLauncher * self,const gchar * variable,const gchar * value,gboolean overwrite)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
g_subprocess_launcher_unsetenv(GSubprocessLauncher * self,const gchar * variable)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 *
g_subprocess_launcher_getenv(GSubprocessLauncher * self,const gchar * variable)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
g_subprocess_launcher_set_cwd(GSubprocessLauncher * self,const gchar * cwd)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
g_subprocess_launcher_set_flags(GSubprocessLauncher * self,GSubprocessFlags flags)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
assign_fd(gint * fd_ptr,gint fd)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
g_subprocess_launcher_set_stdin_file_path(GSubprocessLauncher * self,const gchar * path)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
g_subprocess_launcher_take_stdin_fd(GSubprocessLauncher * self,gint fd)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
g_subprocess_launcher_set_stdout_file_path(GSubprocessLauncher * self,const gchar * path)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
g_subprocess_launcher_take_stdout_fd(GSubprocessLauncher * self,gint fd)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
g_subprocess_launcher_set_stderr_file_path(GSubprocessLauncher * self,const gchar * path)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
g_subprocess_launcher_take_stderr_fd(GSubprocessLauncher * self,gint fd)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
g_subprocess_launcher_take_fd(GSubprocessLauncher * self,gint source_fd,gint target_fd)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
g_subprocess_launcher_set_child_setup(GSubprocessLauncher * self,GSpawnChildSetupFunc child_setup,gpointer user_data,GDestroyNotify destroy_notify)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 *
g_subprocess_launcher_spawn(GSubprocessLauncher * launcher,GError ** error,const gchar * argv0,...)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 *
g_subprocess_launcher_spawnv(GSubprocessLauncher * launcher,const gchar * const * argv,GError ** error)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 }
762