Add some more cases to the app-id unit tests
[glib.git] / gio / gsubprocesslauncher.c
blob2c148f2f6d507704d6d93a6804f5d47ce823bd7b
1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright © 2012 Red Hat, Inc.
4 * Copyright © 2012-2013 Canonical Limited
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.
11 * See the included COPYING file for more information.
13 * Authors: Colin Walters <walters@verbum.org>
14 * Ryan Lortie <desrt@desrt.ca>
17 /**
18 * SECTION:gsubprocesslauncher
19 * @title: GSubprocess Launcher
20 * @short_description: Environment options for launching a child process
21 * @include: gio/gio.h
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.
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.
32 * Since: 2.40
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)
43 #include "config.h"
45 #include "gsubprocesslauncher-private.h"
46 #include "gioenumtypes.h"
47 #include "gsubprocess.h"
48 #include "ginitable.h"
50 #ifdef G_OS_UNIX
51 #include <unistd.h>
52 #include <fcntl.h>
53 #endif
55 typedef GObjectClass GSubprocessLauncherClass;
57 G_DEFINE_TYPE (GSubprocessLauncher, g_subprocess_launcher, G_TYPE_OBJECT);
59 static gboolean
60 verify_disposition (const gchar *stream_name,
61 GSubprocessFlags filtered_flags,
62 gint fd,
63 const gchar *filename)
65 guint n_bits;
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 */
74 if (n_bits + (fd >= 0) + (filename != NULL) > 1)
76 GString *err;
78 err = g_string_new (NULL);
79 if (n_bits)
81 GFlagsClass *class;
82 guint i;
84 class = g_type_class_peek (G_TYPE_SUBPROCESS_FLAGS);
86 for (i = 0; i < class->n_values; i++)
88 const GFlagsValue *value = &class->values[i];
90 if (filtered_flags & value->value)
91 g_string_append_printf (err, " %s", value->value_name);
94 g_type_class_unref (class);
97 if (fd >= 0)
98 g_string_append_printf (err, " g_subprocess_launcher_take_%s_fd()", stream_name);
100 if (filename)
101 g_string_append_printf (err, " g_subprocess_launcher_set_%s_file_path()", stream_name);
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);
107 return FALSE;
110 return TRUE;
113 static gboolean
114 verify_flags (GSubprocessFlags flags)
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);
121 static void
122 g_subprocess_launcher_set_property (GObject *object, guint prop_id,
123 const GValue *value, GParamSpec *pspec)
125 GSubprocessLauncher *launcher = G_SUBPROCESS_LAUNCHER (object);
127 g_assert (prop_id == 1);
129 if (verify_flags (g_value_get_flags (value)))
130 launcher->flags = g_value_get_flags (value);
133 static void
134 g_subprocess_launcher_finalize (GObject *object)
136 GSubprocessLauncher *self = G_SUBPROCESS_LAUNCHER (object);
138 #ifdef G_OS_UNIX
139 guint i;
141 g_free (self->stdin_path);
142 g_free (self->stdout_path);
143 g_free (self->stderr_path);
145 if (self->stdin_fd != -1)
146 close (self->stdin_fd);
148 if (self->stdout_fd != -1)
149 close (self->stdout_fd);
151 if (self->stderr_fd != -1)
152 close (self->stderr_fd);
154 if (self->basic_fd_assignments)
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);
160 if (self->needdup_fd_assignments)
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);
167 if (self->child_setup_destroy_notify)
168 (* self->child_setup_destroy_notify) (self->child_setup_user_data);
169 #endif
171 g_strfreev (self->envp);
172 g_free (self->cwd);
174 G_OBJECT_CLASS (g_subprocess_launcher_parent_class)->finalize (object);
177 static void
178 g_subprocess_launcher_init (GSubprocessLauncher *self)
180 self->envp = g_get_environ ();
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
191 static void
192 g_subprocess_launcher_class_init (GSubprocessLauncherClass *class)
194 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
196 gobject_class->set_property = g_subprocess_launcher_set_property;
197 gobject_class->finalize = g_subprocess_launcher_finalize;
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));
206 * g_subprocess_launcher_new:
207 * @flags: #GSubprocessFlags
209 * Creates a new #GSubprocessLauncher.
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.
215 * Since: 2.40
217 GSubprocessLauncher *
218 g_subprocess_launcher_new (GSubprocessFlags flags)
220 if (!verify_flags (flags))
221 return NULL;
223 return g_object_new (G_TYPE_SUBPROCESS_LAUNCHER,
224 "flags", flags,
225 NULL);
229 * g_subprocess_launcher_set_environ:
230 * @self: a #GSubprocess
231 * @env: (array zero-terminated=1): the replacement environment
233 * Replace the entire environment of processes launched from this
234 * launcher with the given 'environ' variable.
236 * Typically you will build this variable by using g_listenv() to copy
237 * the process 'environ' and using the functions g_environ_setenv(),
238 * g_environ_unsetenv(), etc.
240 * As an alternative, you can use g_subprocess_launcher_setenv(),
241 * g_subprocess_launcher_unsetenv(), etc.
243 * Pass %NULL to inherit the parent process' environment. Pass an
244 * empty array to set an empty environment.
246 * On UNIX, all strings in this array can be arbitrary byte strings.
247 * On Windows, they should be in UTF-8.
249 * Since: 2.40
251 void
252 g_subprocess_launcher_set_environ (GSubprocessLauncher *self,
253 gchar **env)
255 g_strfreev (self->envp);
256 self->envp = g_strdupv (env);
260 * g_subprocess_launcher_setenv:
261 * @self: a #GSubprocess
262 * @variable: the environment variable to set, must not contain '='
263 * @value: the new value for the variable
264 * @overwrite: whether to change the variable if it already exists
266 * Sets the environment variable @variable in the environment of
267 * processes launched from this launcher.
269 * On UNIX, both the variable's name and value can be arbitrary byte
270 * strings, except that the variable's name cannot contain '='.
271 * On Windows, they should be in UTF-8.
273 * Since: 2.40
275 void
276 g_subprocess_launcher_setenv (GSubprocessLauncher *self,
277 const gchar *variable,
278 const gchar *value,
279 gboolean overwrite)
281 self->envp = g_environ_setenv (self->envp, variable, value, overwrite);
285 * g_subprocess_launcher_unsetenv:
286 * @self: a #GSubprocess
287 * @variable: the environment variable to unset, must not contain '='
289 * Removes the environment variable @variable from the environment of
290 * processes launched from this launcher.
292 * On UNIX, the variable's name can be an arbitrary byte string not
293 * containing '='. On Windows, it should be in UTF-8.
295 * Since: 2.40
297 void
298 g_subprocess_launcher_unsetenv (GSubprocessLauncher *self,
299 const gchar *variable)
301 self->envp = g_environ_unsetenv (self->envp, variable);
305 * g_subprocess_launcher_getenv:
306 * @self: a #GSubprocess
307 * @variable: the environment variable to get
309 * Returns the value of the environment variable @variable in the
310 * environment of processes launched from this launcher.
312 * On UNIX, the returned string can be an arbitrary byte string.
313 * On Windows, it will be UTF-8.
315 * Returns: the value of the environment variable, %NULL if unset
317 * Since: 2.40
319 const gchar *
320 g_subprocess_launcher_getenv (GSubprocessLauncher *self,
321 const gchar *variable)
323 return g_environ_getenv (self->envp, variable);
327 * g_subprocess_launcher_set_cwd:
328 * @self: a #GSubprocess
329 * @cwd: (type filename): the cwd for launched processes
331 * Sets the current working directory that processes will be launched
332 * with.
334 * By default processes are launched with the current working directory
335 * of the launching process at the time of launch.
337 * Since: 2.40
339 void
340 g_subprocess_launcher_set_cwd (GSubprocessLauncher *self,
341 const gchar *cwd)
343 g_free (self->cwd);
344 self->cwd = g_strdup (cwd);
348 * g_subprocess_launcher_set_flags:
349 * @self: a #GSubprocessLauncher
350 * @flags: #GSubprocessFlags
352 * Sets the flags on the launcher.
354 * The default flags are %G_SUBPROCESS_FLAGS_NONE.
356 * You may not set flags that specify conflicting options for how to
357 * handle a particular stdio stream (eg: specifying both
358 * %G_SUBPROCESS_FLAGS_STDIN_PIPE and
359 * %G_SUBPROCESS_FLAGS_STDIN_INHERIT).
361 * You may also not set a flag that conflicts with a previous call to a
362 * function like g_subprocess_launcher_set_stdin_file_path() or
363 * g_subprocess_launcher_take_stdout_fd().
365 * Since: 2.40
367 void
368 g_subprocess_launcher_set_flags (GSubprocessLauncher *self,
369 GSubprocessFlags flags)
371 const gchar *stdin_path = NULL, *stdout_path = NULL, *stderr_path = NULL;
372 gint stdin_fd = -1, stdout_fd = -1, stderr_fd = -1;
374 #ifdef G_OS_UNIX
375 stdin_fd = self->stdin_fd;
376 stdout_fd = self->stdout_fd;
377 stderr_fd = self->stderr_fd;
378 stdin_path = self->stdin_path;
379 stdout_path = self->stdout_path;
380 stderr_path = self->stderr_path;
381 #endif
383 if (verify_disposition ("stdin", flags & ALL_STDIN_FLAGS, stdin_fd, stdin_path) &&
384 verify_disposition ("stdout", flags & ALL_STDOUT_FLAGS, stdout_fd, stdout_path) &&
385 verify_disposition ("stderr", flags & ALL_STDERR_FLAGS, stderr_fd, stderr_path))
386 self->flags = flags;
389 #ifdef G_OS_UNIX
390 static void
391 assign_fd (gint *fd_ptr, gint fd)
393 gint flags;
395 if (*fd_ptr != -1)
396 close (*fd_ptr);
398 *fd_ptr = fd;
400 if (fd != -1)
402 /* best effort */
403 flags = fcntl (fd, F_GETFD);
404 if (~flags & FD_CLOEXEC)
405 fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
410 * g_subprocess_launcher_set_stdin_file_path:
411 * @self: a #GSubprocessLauncher
412 * @path: (type filename) (nullable: a filename or %NULL
414 * Sets the file path to use as the stdin for spawned processes.
416 * If @path is %NULL then any previously given path is unset.
418 * The file must exist or spawning the process will fail.
420 * You may not set a stdin file path if a stdin fd is already set or if
421 * the launcher flags contain any flags directing stdin elsewhere.
423 * This feature is only available on UNIX.
425 * Since: 2.40
427 void
428 g_subprocess_launcher_set_stdin_file_path (GSubprocessLauncher *self,
429 const gchar *path)
431 if (verify_disposition ("stdin", self->flags & ALL_STDIN_FLAGS, self->stdin_fd, path))
433 g_free (self->stdin_path);
434 self->stdin_path = g_strdup (path);
439 * g_subprocess_launcher_take_stdin_fd:
440 * @self: a #GSubprocessLauncher
441 * @fd: a file descriptor, or -1
443 * Sets the file descriptor to use as the stdin for spawned processes.
445 * If @fd is -1 then any previously given fd is unset.
447 * Note that if your intention is to have the stdin of the calling
448 * process inherited by the child then %G_SUBPROCESS_FLAGS_STDIN_INHERIT
449 * is a better way to go about doing that.
451 * The passed @fd is noted but will not be touched in the current
452 * process. It is therefore necessary that it be kept open by the
453 * caller until the subprocess is spawned. The file descriptor will
454 * also not be explicitly closed on the child side, so it must be marked
455 * O_CLOEXEC if that's what you want.
457 * You may not set a stdin fd if a stdin file path is already set or if
458 * the launcher flags contain any flags directing stdin elsewhere.
460 * This feature is only available on UNIX.
462 * Since: 2.40
464 void
465 g_subprocess_launcher_take_stdin_fd (GSubprocessLauncher *self,
466 gint fd)
468 if (verify_disposition ("stdin", self->flags & ALL_STDIN_FLAGS, fd, self->stdin_path))
469 assign_fd (&self->stdin_fd, fd);
473 * g_subprocess_launcher_set_stdout_file_path:
474 * @self: a #GSubprocessLauncher
475 * @path: (type filename) (nullable): a filename or %NULL
477 * Sets the file path to use as the stdout for spawned processes.
479 * If @path is %NULL then any previously given path is unset.
481 * The file will be created or truncated when the process is spawned, as
482 * would be the case if using '>' at the shell.
484 * You may not set a stdout file path if a stdout fd is already set or
485 * if the launcher flags contain any flags directing stdout elsewhere.
487 * This feature is only available on UNIX.
489 * Since: 2.40
491 void
492 g_subprocess_launcher_set_stdout_file_path (GSubprocessLauncher *self,
493 const gchar *path)
495 if (verify_disposition ("stdout", self->flags & ALL_STDOUT_FLAGS, self->stdout_fd, path))
497 g_free (self->stdout_path);
498 self->stdout_path = g_strdup (path);
503 * g_subprocess_launcher_take_stdout_fd:
504 * @self: a #GSubprocessLauncher
505 * @fd: a file descriptor, or -1
507 * Sets the file descriptor to use as the stdout for spawned processes.
509 * If @fd is -1 then any previously given fd is unset.
511 * Note that the default behaviour is to pass stdout through to the
512 * stdout of the parent process.
514 * The passed @fd is noted but will not be touched in the current
515 * process. It is therefore necessary that it be kept open by the
516 * caller until the subprocess is spawned. The file descriptor will
517 * also not be explicitly closed on the child side, so it must be marked
518 * O_CLOEXEC if that's what you want.
520 * You may not set a stdout fd if a stdout file path is already set or
521 * if the launcher flags contain any flags directing stdout elsewhere.
523 * This feature is only available on UNIX.
525 * Since: 2.40
527 void
528 g_subprocess_launcher_take_stdout_fd (GSubprocessLauncher *self,
529 gint fd)
531 if (verify_disposition ("stdout", self->flags & ALL_STDOUT_FLAGS, fd, self->stdout_path))
532 assign_fd (&self->stdout_fd, fd);
536 * g_subprocess_launcher_set_stderr_file_path:
537 * @self: a #GSubprocessLauncher
538 * @path: (type filename) (nullable): a filename or %NULL
540 * Sets the file path to use as the stderr for spawned processes.
542 * If @path is %NULL then any previously given path is unset.
544 * The file will be created or truncated when the process is spawned, as
545 * would be the case if using '2>' at the shell.
547 * If you want to send both stdout and stderr to the same file then use
548 * %G_SUBPROCESS_FLAGS_STDERR_MERGE.
550 * You may not set a stderr file path if a stderr fd is already set or
551 * if the launcher flags contain any flags directing stderr elsewhere.
553 * This feature is only available on UNIX.
555 * Since: 2.40
557 void
558 g_subprocess_launcher_set_stderr_file_path (GSubprocessLauncher *self,
559 const gchar *path)
561 if (verify_disposition ("stderr", self->flags & ALL_STDERR_FLAGS, self->stderr_fd, path))
563 g_free (self->stderr_path);
564 self->stderr_path = g_strdup (path);
569 * g_subprocess_launcher_take_stderr_fd:
570 * @self: a #GSubprocessLauncher
571 * @fd: a file descriptor, or -1
573 * Sets the file descriptor to use as the stderr for spawned processes.
575 * If @fd is -1 then any previously given fd is unset.
577 * Note that the default behaviour is to pass stderr through to the
578 * stderr of the parent process.
580 * The passed @fd belongs to the #GSubprocessLauncher. It will be
581 * automatically closed when the launcher is finalized. The file
582 * descriptor will also be closed on the child side when executing the
583 * spawned process.
585 * You may not set a stderr fd if a stderr file path is already set or
586 * if the launcher flags contain any flags directing stderr elsewhere.
588 * This feature is only available on UNIX.
590 * Since: 2.40
592 void
593 g_subprocess_launcher_take_stderr_fd (GSubprocessLauncher *self,
594 gint fd)
596 if (verify_disposition ("stderr", self->flags & ALL_STDERR_FLAGS, fd, self->stderr_path))
597 assign_fd (&self->stderr_fd, fd);
601 * g_subprocess_launcher_take_fd:
602 * @self: a #GSubprocessLauncher
603 * @source_fd: File descriptor in parent process
604 * @target_fd: Target descriptor for child process
606 * Transfer an arbitrary file descriptor from parent process to the
607 * child. This function takes "ownership" of the fd; it will be closed
608 * in the parent when @self is freed.
610 * By default, all file descriptors from the parent will be closed.
611 * This function allows you to create (for example) a custom pipe() or
612 * socketpair() before launching the process, and choose the target
613 * descriptor in the child.
615 * An example use case is GNUPG, which has a command line argument
616 * --passphrase-fd providing a file descriptor number where it expects
617 * the passphrase to be written.
619 void
620 g_subprocess_launcher_take_fd (GSubprocessLauncher *self,
621 gint source_fd,
622 gint target_fd)
624 if (source_fd == target_fd)
626 g_array_append_val (self->basic_fd_assignments, source_fd);
628 else
630 g_array_append_val (self->needdup_fd_assignments, source_fd);
631 g_array_append_val (self->needdup_fd_assignments, target_fd);
636 * g_subprocess_launcher_set_child_setup:
637 * @self: a #GSubprocessLauncher
638 * @child_setup: a #GSpawnChildSetupFunc to use as the child setup function
639 * @user_data: user data for @child_setup
640 * @destroy_notify: a #GDestroyNotify for @user_data
642 * Sets up a child setup function.
644 * The child setup function will be called after fork() but before
645 * exec() on the child's side.
647 * @destroy_notify will not be automatically called on the child's side
648 * of the fork(). It will only be called when the last reference on the
649 * #GSubprocessLauncher is dropped or when a new child setup function is
650 * given.
652 * %NULL can be given as @child_setup to disable the functionality.
654 * Child setup functions are only available on UNIX.
656 * Since: 2.40
658 void
659 g_subprocess_launcher_set_child_setup (GSubprocessLauncher *self,
660 GSpawnChildSetupFunc child_setup,
661 gpointer user_data,
662 GDestroyNotify destroy_notify)
664 if (self->child_setup_destroy_notify)
665 (* self->child_setup_destroy_notify) (self->child_setup_user_data);
667 self->child_setup_func = child_setup;
668 self->child_setup_user_data = user_data;
669 self->child_setup_destroy_notify = destroy_notify;
671 #endif
674 * g_subprocess_launcher_spawn:
675 * @self: a #GSubprocessLauncher
676 * @error: Error
677 * @argv0: Command line arguments
678 * @...: Continued arguments, %NULL terminated
680 * Creates a #GSubprocess given a provided varargs list of arguments.
682 * Since: 2.40
683 * Returns: (transfer full): A new #GSubprocess, or %NULL on error (and @error will be set)
685 GSubprocess *
686 g_subprocess_launcher_spawn (GSubprocessLauncher *launcher,
687 GError **error,
688 const gchar *argv0,
689 ...)
691 GSubprocess *result;
692 GPtrArray *args;
693 const gchar *arg;
694 va_list ap;
696 g_return_val_if_fail (argv0 != NULL && argv0[0] != '\0', NULL);
697 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
699 args = g_ptr_array_new ();
701 va_start (ap, argv0);
702 g_ptr_array_add (args, (gchar *) argv0);
703 while ((arg = va_arg (ap, const gchar *)))
704 g_ptr_array_add (args, (gchar *) arg);
706 g_ptr_array_add (args, NULL);
707 va_end (ap);
709 result = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
711 g_ptr_array_free (args, TRUE);
713 return result;
718 * g_subprocess_launcher_spawnv:
719 * @self: a #GSubprocessLauncher
720 * @argv: (array zero-terminated=1) (element-type utf8): Command line arguments
721 * @error: Error
723 * Creates a #GSubprocess given a provided array of arguments.
725 * Since: 2.40
726 * Returns: (transfer full): A new #GSubprocess, or %NULL on error (and @error will be set)
728 GSubprocess *
729 g_subprocess_launcher_spawnv (GSubprocessLauncher *launcher,
730 const gchar * const *argv,
731 GError **error)
733 GSubprocess *subprocess;
735 g_return_val_if_fail (argv != NULL && argv[0] != NULL && argv[0][0] != '\0', NULL);
737 subprocess = g_object_new (G_TYPE_SUBPROCESS,
738 "argv", argv,
739 "flags", launcher->flags,
740 NULL);
741 g_subprocess_set_launcher (subprocess, launcher);
743 if (!g_initable_init (G_INITABLE (subprocess), NULL, error))
745 g_object_unref (subprocess);
746 return NULL;
749 return subprocess;