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