Coverage Report

Created: 2025-07-23 06:49

/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
}