Branch data Line data Source code
1 : : /* GIO - GLib Input, Output and Streaming Library
2 : : *
3 : : * Copyright © 2012 Red Hat, Inc.
4 : : * Copyright © 2012-2013 Canonical Limited
5 : : *
6 : : * SPDX-License-Identifier: LGPL-2.1-or-later
7 : : *
8 : : * This library is free software; you can redistribute it and/or
9 : : * modify it under the terms of the GNU Lesser General Public
10 : : * License as published by the Free Software Foundation; either
11 : : * version 2.1 of the License, or (at your option) any later version.
12 : : *
13 : : * See the included COPYING file for more information.
14 : : *
15 : : * Authors: Colin Walters <walters@verbum.org>
16 : : * Ryan Lortie <desrt@desrt.ca>
17 : : */
18 : :
19 : : /**
20 : : * GSubprocessLauncher:
21 : : *
22 : : * This class contains a set of options for launching child processes,
23 : : * such as where its standard input and output will be directed, the
24 : : * argument list, the environment, and more.
25 : : *
26 : : * While the [class@Gio.Subprocess] class has high level functions covering
27 : : * popular cases, use of this class allows access to more advanced
28 : : * options. It can also be used to launch multiple subprocesses with
29 : : * a similar configuration.
30 : : *
31 : : * Since: 2.40
32 : : */
33 : :
34 : : #define ALL_STDIN_FLAGS (G_SUBPROCESS_FLAGS_STDIN_PIPE | \
35 : : G_SUBPROCESS_FLAGS_STDIN_INHERIT)
36 : : #define ALL_STDOUT_FLAGS (G_SUBPROCESS_FLAGS_STDOUT_PIPE | \
37 : : G_SUBPROCESS_FLAGS_STDOUT_SILENCE)
38 : : #define ALL_STDERR_FLAGS (G_SUBPROCESS_FLAGS_STDERR_PIPE | \
39 : : G_SUBPROCESS_FLAGS_STDERR_SILENCE | \
40 : : G_SUBPROCESS_FLAGS_STDERR_MERGE)
41 : :
42 : : #include "config.h"
43 : :
44 : : #include "gsubprocesslauncher-private.h"
45 : : #include "gioenumtypes.h"
46 : : #include "gsubprocess.h"
47 : : #include "ginitable.h"
48 : : #include "gioerror.h"
49 : :
50 : : #ifdef G_OS_UNIX
51 : : #include <unistd.h>
52 : : #include <fcntl.h>
53 : : #endif
54 : :
55 : : typedef GObjectClass GSubprocessLauncherClass;
56 : :
57 : 104 : G_DEFINE_TYPE (GSubprocessLauncher, g_subprocess_launcher, G_TYPE_OBJECT)
58 : :
59 : : static gboolean
60 : 134 : verify_disposition (const gchar *stream_name,
61 : : GSubprocessFlags filtered_flags,
62 : : gint fd,
63 : : const gchar *filename)
64 : : {
65 : : guint n_bits;
66 : :
67 : 134 : if (!filtered_flags)
68 : 117 : n_bits = 0;
69 : 17 : else if (((filtered_flags - 1) & filtered_flags) == 0)
70 : 17 : n_bits = 1;
71 : : else
72 : 0 : n_bits = 2; /* ...or more */
73 : :
74 : 134 : if (n_bits + (fd >= 0) + (filename != NULL) > 1)
75 : : {
76 : : GString *err;
77 : :
78 : 0 : err = g_string_new (NULL);
79 : 0 : if (n_bits)
80 : : {
81 : : GFlagsClass *class;
82 : : guint i;
83 : :
84 : 0 : class = g_type_class_peek (G_TYPE_SUBPROCESS_FLAGS);
85 : :
86 : 0 : for (i = 0; i < class->n_values; i++)
87 : : {
88 : 0 : const GFlagsValue *value = &class->values[i];
89 : :
90 : 0 : if (filtered_flags & value->value)
91 : 0 : g_string_append_printf (err, " %s", value->value_name);
92 : : }
93 : :
94 : 0 : g_type_class_unref (class);
95 : : }
96 : :
97 : 0 : if (fd >= 0)
98 : 0 : g_string_append_printf (err, " g_subprocess_launcher_take_%s_fd()", stream_name);
99 : :
100 : 0 : if (filename)
101 : 0 : g_string_append_printf (err, " g_subprocess_launcher_set_%s_file_path()", stream_name);
102 : :
103 : 0 : g_critical ("You may specify at most one disposition for the %s stream, but you specified:%s.",
104 : : stream_name, err->str);
105 : 0 : g_string_free (err, TRUE);
106 : :
107 : 0 : return FALSE;
108 : : }
109 : :
110 : 134 : return TRUE;
111 : : }
112 : :
113 : : static gboolean
114 : 41 : verify_flags (GSubprocessFlags flags)
115 : : {
116 : 82 : return verify_disposition ("stdin", flags & ALL_STDIN_FLAGS, -1, NULL) &&
117 : 82 : verify_disposition ("stdout", flags & ALL_STDOUT_FLAGS, -1, NULL) &&
118 : 41 : verify_disposition ("stderr", flags & ALL_STDERR_FLAGS, -1, NULL);
119 : : }
120 : :
121 : : static void
122 : 21 : g_subprocess_launcher_set_property (GObject *object, guint prop_id,
123 : : const GValue *value, GParamSpec *pspec)
124 : : {
125 : 21 : GSubprocessLauncher *launcher = G_SUBPROCESS_LAUNCHER (object);
126 : :
127 : 21 : g_assert (prop_id == 1);
128 : :
129 : 21 : if (verify_flags (g_value_get_flags (value)))
130 : 21 : launcher->flags = g_value_get_flags (value);
131 : 21 : }
132 : :
133 : : static void
134 : 21 : g_subprocess_launcher_dispose (GObject *object)
135 : : {
136 : 21 : GSubprocessLauncher *self = G_SUBPROCESS_LAUNCHER (object);
137 : :
138 : : #ifdef G_OS_UNIX
139 : 21 : g_clear_pointer (&self->stdin_path, g_free);
140 : 21 : g_clear_pointer (&self->stdout_path, g_free);
141 : 21 : g_clear_pointer (&self->stderr_path, g_free);
142 : :
143 : 21 : g_subprocess_launcher_close (self);
144 : :
145 : 21 : if (self->child_setup_destroy_notify)
146 : 0 : (* self->child_setup_destroy_notify) (self->child_setup_user_data);
147 : 21 : self->child_setup_destroy_notify = NULL;
148 : 21 : self->child_setup_user_data = NULL;
149 : : #endif
150 : :
151 : 21 : g_clear_pointer (&self->envp, g_strfreev);
152 : 21 : g_clear_pointer (&self->cwd, g_free);
153 : :
154 : 21 : G_OBJECT_CLASS (g_subprocess_launcher_parent_class)->dispose (object);
155 : 21 : }
156 : :
157 : : static void
158 : 21 : g_subprocess_launcher_init (GSubprocessLauncher *self)
159 : : {
160 : 21 : self->envp = g_get_environ ();
161 : :
162 : : #ifdef G_OS_UNIX
163 : 21 : self->stdin_fd = -1;
164 : 21 : self->stdout_fd = -1;
165 : 21 : self->stderr_fd = -1;
166 : 21 : self->source_fds = g_array_new (FALSE, 0, sizeof (int));
167 : 21 : self->target_fds = g_array_new (FALSE, 0, sizeof (int));
168 : : #endif
169 : 21 : }
170 : :
171 : : static void
172 : 9 : g_subprocess_launcher_class_init (GSubprocessLauncherClass *class)
173 : : {
174 : 9 : GObjectClass *gobject_class = G_OBJECT_CLASS (class);
175 : :
176 : 9 : gobject_class->set_property = g_subprocess_launcher_set_property;
177 : 9 : gobject_class->dispose = g_subprocess_launcher_dispose;
178 : :
179 : : /**
180 : : * GSubprocessLauncher:flags:
181 : : *
182 : : * [flags@Gio.SubprocessFlags] for launched processes.
183 : : *
184 : : * Since: 2.40
185 : : */
186 : 9 : g_object_class_install_property (gobject_class, 1,
187 : : g_param_spec_flags ("flags", NULL, NULL,
188 : : G_TYPE_SUBPROCESS_FLAGS, 0, G_PARAM_WRITABLE |
189 : : G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY));
190 : 9 : }
191 : :
192 : : /**
193 : : * g_subprocess_launcher_new:
194 : : * @flags: #GSubprocessFlags
195 : : *
196 : : * Creates a new #GSubprocessLauncher.
197 : : *
198 : : * The launcher is created with the default options. A copy of the
199 : : * environment of the calling process is made at the time of this call
200 : : * and will be used as the environment that the process is launched in.
201 : : *
202 : : * Since: 2.40
203 : : **/
204 : : GSubprocessLauncher *
205 : 20 : g_subprocess_launcher_new (GSubprocessFlags flags)
206 : : {
207 : 20 : if (!verify_flags (flags))
208 : 0 : return NULL;
209 : :
210 : 20 : return g_object_new (G_TYPE_SUBPROCESS_LAUNCHER,
211 : : "flags", flags,
212 : : NULL);
213 : : }
214 : :
215 : : /**
216 : : * g_subprocess_launcher_set_environ:
217 : : * @self: a #GSubprocessLauncher
218 : : * @env: (array zero-terminated=1) (element-type filename) (transfer none):
219 : : * the replacement environment
220 : : *
221 : : * Replace the entire environment of processes launched from this
222 : : * launcher with the given 'environ' variable.
223 : : *
224 : : * Typically you will build this variable by using g_listenv() to copy
225 : : * the process 'environ' and using the functions g_environ_setenv(),
226 : : * g_environ_unsetenv(), etc.
227 : : *
228 : : * As an alternative, you can use g_subprocess_launcher_setenv(),
229 : : * g_subprocess_launcher_unsetenv(), etc.
230 : : *
231 : : * Pass an empty array to set an empty environment. Pass %NULL to inherit the
232 : : * parent process’ environment. As of GLib 2.54, the parent process’ environment
233 : : * will be copied when g_subprocess_launcher_set_environ() is called.
234 : : * Previously, it was copied when the subprocess was executed. This means the
235 : : * copied environment may now be modified (using g_subprocess_launcher_setenv(),
236 : : * etc.) before launching the subprocess.
237 : : *
238 : : * On UNIX, all strings in this array can be arbitrary byte strings.
239 : : * On Windows, they should be in UTF-8.
240 : : *
241 : : * Since: 2.40
242 : : **/
243 : : void
244 : 4 : g_subprocess_launcher_set_environ (GSubprocessLauncher *self,
245 : : gchar **env)
246 : : {
247 : 4 : g_strfreev (self->envp);
248 : 4 : self->envp = g_strdupv (env);
249 : :
250 : 4 : if (self->envp == NULL)
251 : 3 : self->envp = g_get_environ ();
252 : 4 : }
253 : :
254 : : /**
255 : : * g_subprocess_launcher_setenv:
256 : : * @self: a #GSubprocessLauncher
257 : : * @variable: (type filename): the environment variable to set,
258 : : * must not contain '='
259 : : * @value: (type filename): the new value for the variable
260 : : * @overwrite: whether to change the variable if it already exists
261 : : *
262 : : * Sets the environment variable @variable in the environment of
263 : : * processes launched from this launcher.
264 : : *
265 : : * On UNIX, both the variable's name and value can be arbitrary byte
266 : : * strings, except that the variable's name cannot contain '='.
267 : : * On Windows, they should be in UTF-8.
268 : : *
269 : : * Since: 2.40
270 : : **/
271 : : void
272 : 5 : g_subprocess_launcher_setenv (GSubprocessLauncher *self,
273 : : const gchar *variable,
274 : : const gchar *value,
275 : : gboolean overwrite)
276 : : {
277 : 5 : self->envp = g_environ_setenv (self->envp, variable, value, overwrite);
278 : 5 : }
279 : :
280 : : /**
281 : : * g_subprocess_launcher_unsetenv:
282 : : * @self: a #GSubprocessLauncher
283 : : * @variable: (type filename): the environment variable to unset,
284 : : * must not contain '='
285 : : *
286 : : * Removes the environment variable @variable from the environment of
287 : : * processes launched from this launcher.
288 : : *
289 : : * On UNIX, the variable's name can be an arbitrary byte string not
290 : : * containing '='. On Windows, it should be in UTF-8.
291 : : *
292 : : * Since: 2.40
293 : : **/
294 : : void
295 : 3 : g_subprocess_launcher_unsetenv (GSubprocessLauncher *self,
296 : : const gchar *variable)
297 : : {
298 : 3 : self->envp = g_environ_unsetenv (self->envp, variable);
299 : 3 : }
300 : :
301 : : /**
302 : : * g_subprocess_launcher_getenv:
303 : : * @self: a #GSubprocessLauncher
304 : : * @variable: (type filename): 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 : : * On UNIX, the returned string can be an arbitrary byte string.
310 : : * On Windows, it will be UTF-8.
311 : : *
312 : : * Returns: (nullable) (type filename): the value of the environment variable,
313 : : * %NULL if unset
314 : : *
315 : : * Since: 2.40
316 : : **/
317 : : const gchar *
318 : 4 : g_subprocess_launcher_getenv (GSubprocessLauncher *self,
319 : : const gchar *variable)
320 : : {
321 : 4 : return g_environ_getenv (self->envp, variable);
322 : : }
323 : :
324 : : /**
325 : : * g_subprocess_launcher_set_cwd:
326 : : * @self: a #GSubprocessLauncher
327 : : * @cwd: (type filename): 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 : 1 : g_subprocess_launcher_set_cwd (GSubprocessLauncher *self,
339 : : const gchar *cwd)
340 : : {
341 : 1 : g_free (self->cwd);
342 : 1 : self->cwd = g_strdup (cwd);
343 : 1 : }
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 : 3 : g_subprocess_launcher_set_flags (GSubprocessLauncher *self,
367 : : GSubprocessFlags flags)
368 : : {
369 : 3 : const gchar *stdin_path = NULL, *stdout_path = NULL, *stderr_path = NULL;
370 : 3 : gint stdin_fd = -1, stdout_fd = -1, stderr_fd = -1;
371 : :
372 : : #ifdef G_OS_UNIX
373 : 3 : stdin_fd = self->stdin_fd;
374 : 3 : stdout_fd = self->stdout_fd;
375 : 3 : stderr_fd = self->stderr_fd;
376 : 3 : stdin_path = self->stdin_path;
377 : 3 : stdout_path = self->stdout_path;
378 : 3 : stderr_path = self->stderr_path;
379 : : #endif
380 : :
381 : 6 : if (verify_disposition ("stdin", flags & ALL_STDIN_FLAGS, stdin_fd, stdin_path) &&
382 : 6 : verify_disposition ("stdout", flags & ALL_STDOUT_FLAGS, stdout_fd, stdout_path) &&
383 : 3 : verify_disposition ("stderr", flags & ALL_STDERR_FLAGS, stderr_fd, stderr_path))
384 : 3 : self->flags = flags;
385 : 3 : }
386 : :
387 : : #ifdef G_OS_UNIX
388 : : static void
389 : 1 : assign_fd (gint *fd_ptr, gint fd)
390 : : {
391 : : gint flags;
392 : :
393 : 1 : if (*fd_ptr != -1)
394 : 0 : close (*fd_ptr);
395 : :
396 : 1 : *fd_ptr = fd;
397 : :
398 : 1 : if (fd != -1)
399 : : {
400 : : /* best effort */
401 : 1 : flags = fcntl (fd, F_GETFD);
402 : 1 : if (~flags & FD_CLOEXEC)
403 : 1 : fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
404 : : }
405 : 1 : }
406 : :
407 : : /**
408 : : * g_subprocess_launcher_set_stdin_file_path:
409 : : * @self: a #GSubprocessLauncher
410 : : * @path: (type filename) (nullable): 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 : 0 : g_subprocess_launcher_set_stdin_file_path (GSubprocessLauncher *self,
427 : : const gchar *path)
428 : : {
429 : 0 : if (verify_disposition ("stdin", self->flags & ALL_STDIN_FLAGS, self->stdin_fd, path))
430 : : {
431 : 0 : g_free (self->stdin_path);
432 : 0 : self->stdin_path = g_strdup (path);
433 : : }
434 : 0 : }
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 : 0 : g_subprocess_launcher_take_stdin_fd (GSubprocessLauncher *self,
464 : : gint fd)
465 : : {
466 : 0 : if (verify_disposition ("stdin", self->flags & ALL_STDIN_FLAGS, fd, self->stdin_path))
467 : 0 : assign_fd (&self->stdin_fd, fd);
468 : 0 : }
469 : :
470 : : /**
471 : : * g_subprocess_launcher_set_stdout_file_path:
472 : : * @self: a #GSubprocessLauncher
473 : : * @path: (type filename) (nullable): 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 : 1 : g_subprocess_launcher_set_stdout_file_path (GSubprocessLauncher *self,
491 : : const gchar *path)
492 : : {
493 : 1 : if (verify_disposition ("stdout", self->flags & ALL_STDOUT_FLAGS, self->stdout_fd, path))
494 : : {
495 : 1 : g_free (self->stdout_path);
496 : 1 : self->stdout_path = g_strdup (path);
497 : : }
498 : 1 : }
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 : 1 : g_subprocess_launcher_take_stdout_fd (GSubprocessLauncher *self,
527 : : gint fd)
528 : : {
529 : 1 : if (verify_disposition ("stdout", self->flags & ALL_STDOUT_FLAGS, fd, self->stdout_path))
530 : 1 : assign_fd (&self->stdout_fd, fd);
531 : 1 : }
532 : :
533 : : /**
534 : : * g_subprocess_launcher_set_stderr_file_path:
535 : : * @self: a #GSubprocessLauncher
536 : : * @path: (type filename) (nullable): 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 : 0 : g_subprocess_launcher_set_stderr_file_path (GSubprocessLauncher *self,
557 : : const gchar *path)
558 : : {
559 : 0 : if (verify_disposition ("stderr", self->flags & ALL_STDERR_FLAGS, self->stderr_fd, path))
560 : : {
561 : 0 : g_free (self->stderr_path);
562 : 0 : self->stderr_path = g_strdup (path);
563 : : }
564 : 0 : }
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 : 0 : g_subprocess_launcher_take_stderr_fd (GSubprocessLauncher *self,
592 : : gint fd)
593 : : {
594 : 0 : if (verify_disposition ("stderr", self->flags & ALL_STDERR_FLAGS, fd, self->stderr_path))
595 : 0 : assign_fd (&self->stderr_fd, fd);
596 : 0 : }
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 @source_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 : 15 : g_subprocess_launcher_take_fd (GSubprocessLauncher *self,
619 : : gint source_fd,
620 : : gint target_fd)
621 : : {
622 : 15 : if (self->source_fds != NULL && self->target_fds != NULL)
623 : : {
624 : 15 : g_array_append_val (self->source_fds, source_fd);
625 : 15 : g_array_append_val (self->target_fds, target_fd);
626 : : }
627 : 15 : }
628 : :
629 : : /**
630 : : * g_subprocess_launcher_close:
631 : : * @self: a #GSubprocessLauncher
632 : : *
633 : : * Closes all the file descriptors previously passed to the object with
634 : : * g_subprocess_launcher_take_fd(), g_subprocess_launcher_take_stderr_fd(), etc.
635 : : *
636 : : * After calling this method, any subsequent calls to g_subprocess_launcher_spawn() or g_subprocess_launcher_spawnv() will
637 : : * return %G_IO_ERROR_CLOSED. This method is idempotent if
638 : : * called more than once.
639 : : *
640 : : * This function is called automatically when the #GSubprocessLauncher
641 : : * is disposed, but is provided separately so that garbage collected
642 : : * language bindings can call it earlier to guarantee when FDs are closed.
643 : : *
644 : : * Since: 2.68
645 : : */
646 : : void
647 : 22 : g_subprocess_launcher_close (GSubprocessLauncher *self)
648 : : {
649 : : guint i;
650 : :
651 : 22 : g_return_if_fail (G_IS_SUBPROCESS_LAUNCHER (self));
652 : :
653 : 22 : if (self->stdin_fd != -1)
654 : 0 : close (self->stdin_fd);
655 : 22 : self->stdin_fd = -1;
656 : :
657 : 22 : if (self->stdout_fd != -1)
658 : 1 : close (self->stdout_fd);
659 : 22 : self->stdout_fd = -1;
660 : :
661 : 22 : if (self->stderr_fd != -1)
662 : 0 : close (self->stderr_fd);
663 : 22 : self->stderr_fd = -1;
664 : :
665 : 22 : if (self->source_fds)
666 : : {
667 : 21 : g_assert (self->target_fds != NULL);
668 : 21 : g_assert (self->source_fds->len == self->target_fds->len);
669 : :
670 : : /* Note: Don’t close the target_fds, as they’re only valid FDs in the
671 : : * child process. This code never executes in the child process. */
672 : 36 : for (i = 0; i < self->source_fds->len; i++)
673 : 15 : (void) close (g_array_index (self->source_fds, int, i));
674 : :
675 : 21 : g_clear_pointer (&self->source_fds, g_array_unref);
676 : 21 : g_clear_pointer (&self->target_fds, g_array_unref);
677 : : }
678 : :
679 : 22 : self->closed_fd = TRUE;
680 : : }
681 : :
682 : : /**
683 : : * g_subprocess_launcher_set_child_setup: (skip)
684 : : * @self: a #GSubprocessLauncher
685 : : * @child_setup: (closure user_data): a #GSpawnChildSetupFunc to use as the child setup function
686 : : * @user_data: user data for @child_setup
687 : : * @destroy_notify: a #GDestroyNotify for @user_data
688 : : *
689 : : * Sets up a child setup function.
690 : : *
691 : : * The child setup function will be called after fork() but before
692 : : * exec() on the child's side.
693 : : *
694 : : * @destroy_notify will not be automatically called on the child's side
695 : : * of the fork(). It will only be called when the last reference on the
696 : : * #GSubprocessLauncher is dropped or when a new child setup function is
697 : : * given.
698 : : *
699 : : * %NULL can be given as @child_setup to disable the functionality.
700 : : *
701 : : * Child setup functions are only available on UNIX.
702 : : *
703 : : * Since: 2.40
704 : : **/
705 : : void
706 : 4 : g_subprocess_launcher_set_child_setup (GSubprocessLauncher *self,
707 : : GSpawnChildSetupFunc child_setup,
708 : : gpointer user_data,
709 : : GDestroyNotify destroy_notify)
710 : : {
711 : 4 : if (self->child_setup_destroy_notify)
712 : 0 : (* self->child_setup_destroy_notify) (self->child_setup_user_data);
713 : :
714 : 4 : self->child_setup_func = child_setup;
715 : 4 : self->child_setup_user_data = user_data;
716 : 4 : self->child_setup_destroy_notify = destroy_notify;
717 : 4 : }
718 : : #endif
719 : :
720 : : /**
721 : : * g_subprocess_launcher_spawn:
722 : : * @self: a #GSubprocessLauncher
723 : : * @error: Error
724 : : * @argv0: Command line arguments
725 : : * @...: Continued arguments, %NULL terminated
726 : : *
727 : : * Creates a #GSubprocess given a provided varargs list of arguments.
728 : : *
729 : : * Since: 2.40
730 : : * Returns: (transfer full): A new #GSubprocess, or %NULL on error (and @error will be set)
731 : : **/
732 : : GSubprocess *
733 : 3 : g_subprocess_launcher_spawn (GSubprocessLauncher *launcher,
734 : : GError **error,
735 : : const gchar *argv0,
736 : : ...)
737 : : {
738 : : GSubprocess *result;
739 : : GPtrArray *args;
740 : : const gchar *arg;
741 : : va_list ap;
742 : :
743 : 3 : g_return_val_if_fail (argv0 != NULL && argv0[0] != '\0', NULL);
744 : 3 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
745 : :
746 : 3 : args = g_ptr_array_new ();
747 : :
748 : 3 : va_start (ap, argv0);
749 : 3 : g_ptr_array_add (args, (gchar *) argv0);
750 : 6 : while ((arg = va_arg (ap, const gchar *)))
751 : 3 : g_ptr_array_add (args, (gchar *) arg);
752 : :
753 : 3 : g_ptr_array_add (args, NULL);
754 : 3 : va_end (ap);
755 : :
756 : 3 : result = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) args->pdata, error);
757 : :
758 : 3 : g_ptr_array_free (args, TRUE);
759 : :
760 : 3 : return result;
761 : :
762 : : }
763 : :
764 : : /**
765 : : * g_subprocess_launcher_spawnv:
766 : : * @self: a #GSubprocessLauncher
767 : : * @argv: (array zero-terminated=1) (element-type filename): Command line arguments
768 : : * @error: Error
769 : : *
770 : : * Creates a #GSubprocess given a provided array of arguments.
771 : : *
772 : : * Since: 2.40
773 : : * Returns: (transfer full): A new #GSubprocess, or %NULL on error (and @error will be set)
774 : : **/
775 : : GSubprocess *
776 : 22 : g_subprocess_launcher_spawnv (GSubprocessLauncher *launcher,
777 : : const gchar * const *argv,
778 : : GError **error)
779 : : {
780 : : GSubprocess *subprocess;
781 : :
782 : 22 : g_return_val_if_fail (argv != NULL && argv[0] != NULL && argv[0][0] != '\0', NULL);
783 : :
784 : : #ifdef G_OS_UNIX
785 : 22 : if (launcher->closed_fd)
786 : : {
787 : 1 : g_set_error (error,
788 : : G_IO_ERROR,
789 : : G_IO_ERROR_CLOSED,
790 : : "Can't spawn a new child because a passed file descriptor has been closed.");
791 : 1 : return NULL;
792 : : }
793 : : #endif
794 : :
795 : 21 : subprocess = g_object_new (G_TYPE_SUBPROCESS,
796 : : "argv", argv,
797 : 21 : "flags", launcher->flags,
798 : : NULL);
799 : 21 : g_subprocess_set_launcher (subprocess, launcher);
800 : :
801 : 21 : if (!g_initable_init (G_INITABLE (subprocess), NULL, error))
802 : : {
803 : 0 : g_object_unref (subprocess);
804 : 0 : return NULL;
805 : : }
806 : :
807 : 21 : return subprocess;
808 : : }
|