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