1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
3
* Copyright (C) 2012 Colin Walters <walters@verbum.org>
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the
17
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
* Boston, MA 02111-1307, USA.
23
#include "libgsystem.h"
25
#if GLIB_CHECK_VERSION(2,34,0)
28
#include <gio/gunixoutputstream.h>
29
#include <gio/gfiledescriptorbased.h>
30
#include <gio/gunixinputstream.h>
31
#include <glib-unix.h>
35
* SECTION:gssubprocesscontext
36
* @title: GSSubprocess Context
37
* @short_description: Environment options for launching a child process
39
* This class contains a set of options for launching child processes,
40
* such as where its standard input and output will be directed, the
41
* argument list, the environment, and more.
43
* While the #GSSubprocess class has high level functions covering
44
* popular cases, use of this class allows access to more advanced
45
* options. It can also be used to launch multiple subprocesses with
46
* a similar configuration.
53
#include "gsystem-subprocess-context-private.h"
54
#include "gsystem-subprocess.h"
58
typedef GObjectClass GSSubprocessContextClass;
60
G_DEFINE_TYPE (GSSubprocessContext, gs_subprocess_context, G_TYPE_OBJECT);
69
static GParamSpec *gs_subprocess_context_pspecs[N_PROPS];
72
* gs_subprocess_context_new:
73
* @argv: Argument list
75
* Returns: (transfer full): A new instance of a #GSSubprocessContext.
78
gs_subprocess_context_new (gchar **argv)
80
g_return_val_if_fail (argv != NULL && argv[0] != NULL, NULL);
82
return g_object_new (GS_TYPE_SUBPROCESS_CONTEXT,
88
gs_subprocess_context_newv (const gchar *first_arg,
91
GSSubprocessContext *result;
94
g_return_val_if_fail (first_arg != NULL, NULL);
96
va_start (args, first_arg);
97
result = gs_subprocess_context_newa (first_arg, args);
104
* gs_subprocess_context_newa:
105
* @first_arg: First argument
108
* Returns: (transfer full): A new instance of a #GSSubprocessContext.
110
GSSubprocessContext *
111
gs_subprocess_context_newa (const gchar *first_arg,
114
GSSubprocessContext *result;
117
g_return_val_if_fail (first_arg != NULL, NULL);
119
argv = g_ptr_array_new ();
121
g_ptr_array_add (argv, (gchar*)first_arg);
122
while ((first_arg = va_arg (args, const gchar *)) != NULL);
123
g_ptr_array_add (argv, NULL);
125
result = gs_subprocess_context_new ((gchar**)argv->pdata);
131
GSSubprocessContext *
132
gs_subprocess_context_new_argv0 (const gchar *argv0,
135
GSSubprocessContext *result;
136
GPtrArray *real_argv;
139
g_return_val_if_fail (argv0 != NULL, NULL);
140
g_return_val_if_fail (argv != NULL && argv[0] != NULL, NULL);
142
real_argv = g_ptr_array_new ();
143
g_ptr_array_add (real_argv, (gchar*)argv0);
144
for (iter = argv; *iter; iter++)
145
g_ptr_array_add (real_argv, (gchar*) *iter);
146
g_ptr_array_add (real_argv, NULL);
148
result = g_object_new (GS_TYPE_SUBPROCESS_CONTEXT,
149
"argv", real_argv->pdata,
151
result->has_argv0 = TRUE;
158
gs_subprocess_context_init (GSSubprocessContext *self)
161
self->stdout_fd = -1;
162
self->stderr_fd = -1;
163
self->stdout_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT;
164
self->stderr_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT;
165
self->postfork_close_fds = g_array_new (FALSE, FALSE, sizeof (int));
166
self->inherit_fds = g_array_new (FALSE, FALSE, sizeof (int));
170
gs_subprocess_context_finalize (GObject *object)
172
GSSubprocessContext *self = GS_SUBPROCESS_CONTEXT (object);
174
g_strfreev (self->argv);
175
g_strfreev (self->envp);
178
g_free (self->stdin_path);
179
g_free (self->stdout_path);
180
g_free (self->stderr_path);
182
g_array_unref (self->postfork_close_fds);
183
g_array_unref (self->inherit_fds);
185
if (G_OBJECT_CLASS (gs_subprocess_context_parent_class)->finalize != NULL)
186
G_OBJECT_CLASS (gs_subprocess_context_parent_class)->finalize (object);
190
gs_subprocess_context_set_property (GObject *object,
195
GSSubprocessContext *self = GS_SUBPROCESS_CONTEXT (object);
200
self->argv = (gchar**) g_value_dup_boxed (value);
204
g_assert_not_reached ();
209
gs_subprocess_context_get_property (GObject *object,
214
GSSubprocessContext *self = GS_SUBPROCESS_CONTEXT (object);
219
g_value_set_boxed (value, self->argv);
223
g_assert_not_reached ();
228
gs_subprocess_context_class_init (GSSubprocessContextClass *class)
230
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
232
gobject_class->finalize = gs_subprocess_context_finalize;
233
gobject_class->get_property = gs_subprocess_context_get_property;
234
gobject_class->set_property = gs_subprocess_context_set_property;
237
* GSSubprocessContext:argv:
239
* Array of arguments passed to child process; must have at least
240
* one element. The first element has special handling - if it is
241
* an not absolute path ( as determined by g_path_is_absolute() ),
242
* then the system search path will be used. See
243
* %G_SPAWN_SEARCH_PATH.
245
* Note that in order to use the Unix-specific argv0 functionality,
246
* you must use the setter function
247
* gs_subprocess_context_set_args_and_argv0(). For more information
248
* about this, see %G_SPAWN_FILE_AND_ARGV_ZERO.
252
gs_subprocess_context_pspecs[PROP_ARGV] = g_param_spec_boxed ("argv", "Arguments", "Arguments for child process", G_TYPE_STRV,
253
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
255
g_object_class_install_properties (gobject_class, N_PROPS, gs_subprocess_context_pspecs);
259
* gs_subprocess_context_argv_append:
263
* Append an argument to the child's argument vector.
266
gs_subprocess_context_argv_append (GSSubprocessContext *self,
269
GPtrArray *new_argv = g_ptr_array_new ();
272
for (iter = self->argv; *iter; iter++)
273
g_ptr_array_add (new_argv, *iter);
274
g_ptr_array_add (new_argv, g_strdup (arg));
275
g_ptr_array_add (new_argv, NULL);
277
/* Don't free elements */
279
self->argv = (char**)g_ptr_array_free (new_argv, FALSE);
285
* gs_subprocess_context_set_environment:
287
* @environ: (array zero-terminated=1) (element-type utf8): Environment KEY=VALUE pairs
289
* Replace the environment that will be used for the child process.
290
* The default is to inherit the current process.
293
gs_subprocess_context_set_environment (GSSubprocessContext *self,
296
g_strfreev (self->envp);
297
self->envp = g_strdupv (env);
301
gs_subprocess_context_set_cwd (GSSubprocessContext *self,
305
self->cwd = g_strdup (cwd);
309
gs_subprocess_context_set_keep_descriptors (GSSubprocessContext *self,
310
gboolean keep_descriptors)
313
self->keep_descriptors = keep_descriptors ? 1 : 0;
317
gs_subprocess_context_set_search_path (GSSubprocessContext *self,
318
gboolean search_path,
319
gboolean search_path_from_envp)
321
self->search_path = search_path ? 1 : 0;
322
self->search_path_from_envp = search_path_from_envp ? 1 : 0;
326
gs_subprocess_context_set_stdin_disposition (GSSubprocessContext *self,
327
GSSubprocessStreamDisposition disposition)
329
g_return_if_fail (disposition != GS_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE);
330
self->stdin_disposition = disposition;
334
gs_subprocess_context_set_stdout_disposition (GSSubprocessContext *self,
335
GSSubprocessStreamDisposition disposition)
337
g_return_if_fail (disposition != GS_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE);
338
self->stdout_disposition = disposition;
342
gs_subprocess_context_set_stderr_disposition (GSSubprocessContext *self,
343
GSSubprocessStreamDisposition disposition)
345
self->stderr_disposition = disposition;
350
gs_subprocess_context_set_stdin_file_path (GSSubprocessContext *self,
353
self->stdin_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL;
354
g_free (self->stdin_path);
355
self->stdin_path = g_strdup (path);
359
gs_subprocess_context_set_stdin_fd (GSSubprocessContext *self,
362
self->stdin_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL;
367
gs_subprocess_context_set_stdout_file_path (GSSubprocessContext *self,
370
self->stdout_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL;
371
g_free (self->stdout_path);
372
self->stdout_path = g_strdup (path);
376
gs_subprocess_context_set_stdout_fd (GSSubprocessContext *self,
379
self->stdout_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL;
380
self->stdout_fd = fd;
384
gs_subprocess_context_set_stderr_file_path (GSSubprocessContext *self,
387
self->stderr_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL;
388
g_free (self->stderr_path);
389
self->stderr_path = g_strdup (path);
393
gs_subprocess_context_set_stderr_fd (GSSubprocessContext *self,
396
self->stderr_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL;
397
self->stderr_fd = fd;
403
* gs_subprocess_context_set_child_setup: (skip)
405
* @child_setup: Function to call in the newly forked child, before execve()
406
* @user_data: Data passed to child
408
* FIXME - note extensive restricitons on GSpawnChildSetupFunc here
411
gs_subprocess_context_set_child_setup (GSSubprocessContext *self,
412
GSpawnChildSetupFunc child_setup,
415
self->child_setup_func = child_setup;
416
self->child_setup_data = user_data;
420
open_pipe_internal (GSSubprocessContext *self,
428
g_return_val_if_fail (out_stream != NULL, FALSE);
429
g_return_val_if_fail (out_fdno != NULL, FALSE);
431
if (!g_unix_open_pipe (pipefds, FD_CLOEXEC, error))
436
*out_stream = g_unix_input_stream_new (pipefds[0], TRUE);
437
*out_fdno = pipefds[1];
441
*out_stream = g_unix_output_stream_new (pipefds[1], TRUE);
442
*out_fdno = pipefds[0];
444
g_array_append_val (self->inherit_fds, *out_fdno);
445
g_array_append_val (self->postfork_close_fds, *out_fdno);
451
* gs_subprocess_context_open_pipe_read:
453
* @out_stream: (out) (transfer full): A newly referenced output stream
454
* @out_fdno: (out): File descriptor number for the subprocess side of the pipe
456
* This allows you to open a pipe between the parent and child
457
* processes, independent of the standard streams. For this function,
458
* the pipe is set up so that the parent can read, and the child can
459
* write. For the opposite version, see
460
* gs_subprocess_context_open_pipe_write().
462
* The returned @out_fdno is the file descriptor number that the child
463
* will see; you need to communicate this number via a separate
464
* channel, such as the argument list. For example, if you're using
465
* this pipe to send a password, provide
466
* <literal>--password-fd=<fdno string></literal>.
468
* Returns: %TRUE on success, %FALSE on error (and @error will be set)
471
gs_subprocess_context_open_pipe_read (GSSubprocessContext *self,
472
GInputStream **out_stream,
476
return open_pipe_internal (self, TRUE, (void**)out_stream, out_fdno, error);
480
* gs_subprocess_context_open_pipe_write:
482
* @out_stream: (out) (transfer full): A newly referenced stream
483
* @out_fdno: (out): File descriptor number for the subprocess side of the pipe
485
* Like gs_subprocess_context_open_pipe_read(), but returns a writable
486
* channel from which the child process can read.
488
* Returns: %TRUE on success, %FALSE on error (and @error will be set)
491
gs_subprocess_context_open_pipe_write (GSSubprocessContext *self,
492
GOutputStream **out_stream,
496
return open_pipe_internal (self, FALSE, (void**)out_stream, out_fdno, error);