~ubuntu-branches/ubuntu/vivid/gnome-desktop3/vivid-proposed

« back to all changes in this revision

Viewing changes to libgnome-desktop/libgsystem/gsystem-subprocess.c

  • Committer: Package Import Robot
  • Author(s): Tim Lunn
  • Date: 2014-09-12 07:22:38 UTC
  • mfrom: (1.6.4) (31.1.1 utopic-proposed)
  • Revision ID: package-import@ubuntu.com-20140912072238-fv5g0rpwuk5yynip
Tags: 3.12.2-2ubuntu1
* New upstream release (LP: #1372346)
* Merge with Debian, Remaining changes:
  - debian/patches:
    + 04_compute_average_color.patch: Compute the avergage color in
      gnome-desktop itself, not in unity to fix some races (LP #963140)
    + tweak_color_computation.patch, Patch from Gord, no patch header,
      no bug link.
    + git_revert_draw_background.patch
    + ubuntu_language.patch, Ported relevant bits from g-c-c 
      52_region_language.patch, as required for gnome 3.8 region panel
    + ubuntu_language_list_from_SUPPORTED.patch,
      adds api to get list of available languages from SUPPORTED file.
      To be used by gnome 3.8 region panel language installation.
  - debian/rules:
    + drop obsolete --disable-scrollkeeper configure flag
  - debian/libgnome-desktop-3-10.symbols:
    + Add symbols included in Ubuntu patches
  - debian/control.in:
    + Mark gnome-desktop3-data Multi-Arch: foreign
* Dropped changes:
  - 02_refuse_to_break_GL_compositors.patch:
    + xrandr code has moved into libunity-settings-daemon now

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 
2
 
 
3
/* GIO - GLib Input, Output and Streaming Library
 
4
 *
 
5
 * Copyright © 2012 Red Hat, Inc.
 
6
 * Copyright © 2012 Canonical Limited
 
7
 *
 
8
 * This program is free software: you can redistribute it and/or modify
 
9
 * it under the terms of the GNU Lesser General Public License as published
 
10
 * by the Free Software Foundation; either version 2 of the licence or (at
 
11
 * 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
#include "config.h"
 
20
 
 
21
#define _GSYSTEM_NO_LOCAL_ALLOC
 
22
#include "libgsystem.h"
 
23
 
 
24
#if GLIB_CHECK_VERSION(2,34,0)
 
25
 
 
26
/**
 
27
 * SECTION:gssubprocess
 
28
 * @title: GSSubprocess
 
29
 * @short_description: Create child processes and monitor their status
 
30
 *
 
31
 * This class wraps the lower-level g_spawn_async_with_pipes() API,
 
32
 * providing a more modern GIO-style API, such as returning
 
33
 * #GInputStream objects for child output pipes.
 
34
 *
 
35
 * One major advantage that GIO brings over the core GLib library is
 
36
 * comprehensive API for asynchronous I/O, such
 
37
 * g_output_stream_splice_async().  This makes GSubprocess
 
38
 * significantly more powerful and flexible than equivalent APIs in
 
39
 * some other languages such as the <literal>subprocess.py</literal>
 
40
 * included with Python.  For example, using #GSubprocess one could
 
41
 * create two child processes, reading standard output from the first,
 
42
 * processing it, and writing to the input stream of the second, all
 
43
 * without blocking the main loop.
 
44
 *
 
45
 * Since: 2.36
 
46
 */
 
47
 
 
48
#include "config.h"
 
49
 
 
50
#include "gsystem-subprocess.h"
 
51
#include "gsystem-subprocess-context-private.h"
 
52
 
 
53
#include <string.h>
 
54
#ifdef G_OS_UNIX
 
55
#include <gio/gunixoutputstream.h>
 
56
#include <gio/gfiledescriptorbased.h>
 
57
#include <gio/gunixinputstream.h>
 
58
#include <glib-unix.h>
 
59
#endif
 
60
#include <fcntl.h>
 
61
#ifdef G_OS_WIN32
 
62
#define _WIN32_WINNT 0x0500
 
63
#include <windows.h>
 
64
#include "giowin32-priv.h"
 
65
#endif
 
66
 
 
67
#ifndef O_BINARY
 
68
#define O_BINARY 0
 
69
#endif
 
70
 
 
71
static void initable_iface_init (GInitableIface         *initable_iface);
 
72
 
 
73
typedef GObjectClass GSSubprocessClass;
 
74
 
 
75
#ifdef G_OS_UNIX
 
76
static void
 
77
gs_subprocess_unix_queue_waitpid (GSSubprocess  *self);
 
78
#endif
 
79
 
 
80
struct _GSSubprocess
 
81
{
 
82
  GObject parent;
 
83
 
 
84
  GSSubprocessContext *context;
 
85
  GPid pid;
 
86
 
 
87
  guint pid_valid : 1;
 
88
  guint reaped_child : 1;
 
89
  guint unused : 30;
 
90
 
 
91
  /* These are the streams created if a pipe is requested via flags. */
 
92
  GOutputStream *stdin_pipe;
 
93
  GInputStream  *stdout_pipe;
 
94
  GInputStream  *stderr_pipe;
 
95
};
 
96
 
 
97
G_DEFINE_TYPE_WITH_CODE (GSSubprocess, gs_subprocess, G_TYPE_OBJECT,
 
98
                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init));
 
99
 
 
100
enum
 
101
{
 
102
  PROP_0,
 
103
  PROP_CONTEXT,
 
104
  N_PROPS
 
105
};
 
106
 
 
107
static GParamSpec *gs_subprocess_pspecs[N_PROPS];
 
108
 
 
109
static void
 
110
gs_subprocess_init (GSSubprocess  *self)
 
111
{
 
112
}
 
113
 
 
114
static void
 
115
gs_subprocess_finalize (GObject *object)
 
116
{
 
117
  GSSubprocess *self = GS_SUBPROCESS (object);
 
118
 
 
119
  if (self->pid_valid)
 
120
    {
 
121
#ifdef G_OS_UNIX
 
122
      /* Here we need to actually call waitpid() to clean up the
 
123
       * zombie.  In case the child hasn't actually exited, defer this
 
124
       * cleanup to the worker thread.
 
125
       */
 
126
      if (!self->reaped_child)
 
127
        gs_subprocess_unix_queue_waitpid (self);
 
128
#endif
 
129
      g_spawn_close_pid (self->pid);
 
130
    }
 
131
 
 
132
  g_clear_object (&self->stdin_pipe);
 
133
  g_clear_object (&self->stdout_pipe);
 
134
  g_clear_object (&self->stderr_pipe);
 
135
 
 
136
  if (G_OBJECT_CLASS (gs_subprocess_parent_class)->finalize != NULL)
 
137
    G_OBJECT_CLASS (gs_subprocess_parent_class)->finalize (object);
 
138
}
 
139
 
 
140
static void
 
141
gs_subprocess_set_property (GObject      *object,
 
142
                           guint         prop_id,
 
143
                           const GValue *value,
 
144
                           GParamSpec   *pspec)
 
145
{
 
146
  GSSubprocess *self = GS_SUBPROCESS (object);
 
147
 
 
148
  switch (prop_id)
 
149
    {
 
150
    case PROP_CONTEXT:
 
151
      self->context = g_value_dup_object (value);
 
152
      break;
 
153
 
 
154
    default:
 
155
      g_assert_not_reached ();
 
156
    }
 
157
}
 
158
 
 
159
static void
 
160
gs_subprocess_get_property (GObject    *object,
 
161
                           guint       prop_id,
 
162
                           GValue     *value,
 
163
                           GParamSpec *pspec)
 
164
{
 
165
  GSSubprocess *self = GS_SUBPROCESS (object);
 
166
 
 
167
  switch (prop_id)
 
168
    {
 
169
    case PROP_CONTEXT:
 
170
      g_value_set_object (value, self->context);
 
171
      break;
 
172
 
 
173
    default:
 
174
      g_assert_not_reached ();
 
175
    }
 
176
}
 
177
 
 
178
static void
 
179
gs_subprocess_class_init (GSSubprocessClass *class)
 
180
{
 
181
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
 
182
 
 
183
  gobject_class->finalize = gs_subprocess_finalize;
 
184
  gobject_class->get_property = gs_subprocess_get_property;
 
185
  gobject_class->set_property = gs_subprocess_set_property;
 
186
 
 
187
  /**
 
188
   * GSSubprocess:context:
 
189
   *
 
190
   *
 
191
   * Since: 2.36
 
192
   */
 
193
  gs_subprocess_pspecs[PROP_CONTEXT] = g_param_spec_object ("context", "Context", "Subprocess options", GS_TYPE_SUBPROCESS_CONTEXT,
 
194
                                                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
 
195
                                                           G_PARAM_STATIC_STRINGS);
 
196
 
 
197
  g_object_class_install_properties (gobject_class, N_PROPS, gs_subprocess_pspecs);
 
198
}
 
199
 
 
200
#ifdef G_OS_UNIX
 
201
 
 
202
static gboolean
 
203
gs_subprocess_unix_waitpid_dummy (gpointer data)
 
204
{
 
205
  return FALSE;
 
206
}
 
207
 
 
208
static void
 
209
gs_subprocess_unix_queue_waitpid (GSSubprocess  *self)
 
210
{
 
211
  GMainContext *worker_context;
 
212
  GSource *waitpid_source;
 
213
 
 
214
#ifdef GLIB_COMPILATION
 
215
  worker_context = GLIB_PRIVATE_CALL (g_get_worker_context) ();
 
216
#else
 
217
  worker_context = g_main_context_get_thread_default ();
 
218
#endif
 
219
  waitpid_source = g_child_watch_source_new (self->pid); 
 
220
  g_source_set_callback (waitpid_source, gs_subprocess_unix_waitpid_dummy, NULL, NULL);
 
221
  g_source_attach (waitpid_source, worker_context);
 
222
  g_source_unref (waitpid_source);
 
223
}
 
224
 
 
225
#endif
 
226
 
 
227
static GInputStream *
 
228
platform_input_stream_from_spawn_fd (gint fd)
 
229
{
 
230
  if (fd < 0)
 
231
    return NULL;
 
232
 
 
233
#ifdef G_OS_UNIX
 
234
  return g_unix_input_stream_new (fd, TRUE);
 
235
#else
 
236
  return g_win32_input_stream_new_from_fd (fd, TRUE);
 
237
#endif
 
238
}
 
239
 
 
240
static GOutputStream *
 
241
platform_output_stream_from_spawn_fd (gint fd)
 
242
{
 
243
  if (fd < 0)
 
244
    return NULL;
 
245
 
 
246
#ifdef G_OS_UNIX
 
247
  return g_unix_output_stream_new (fd, TRUE);
 
248
#else
 
249
  return g_win32_output_stream_new_from_fd (fd, TRUE);
 
250
#endif
 
251
}
 
252
 
 
253
#ifdef G_OS_UNIX
 
254
static gint
 
255
unix_open_file (const char  *filename,
 
256
                gint         mode,
 
257
                GError     **error)
 
258
{
 
259
  gint my_fd;
 
260
 
 
261
  do
 
262
    my_fd = open (filename, mode | O_BINARY | O_CLOEXEC, 0666);
 
263
  while (my_fd == -1 && errno == EINTR);
 
264
 
 
265
  /* If we return -1 we should also set the error */
 
266
  if (my_fd < 0)
 
267
    {
 
268
      gint saved_errno = errno;
 
269
      char *display_name;
 
270
 
 
271
      display_name = g_filename_display_name (filename);
 
272
      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (saved_errno),
 
273
                   "Error opening file '%s': %s", display_name,
 
274
                   g_strerror (saved_errno));
 
275
      g_free (display_name);
 
276
      /* fall through... */
 
277
    }
 
278
 
 
279
  return my_fd;
 
280
}
 
281
#endif
 
282
 
 
283
typedef struct
 
284
{
 
285
  gint                   fds[3];
 
286
  GArray                *inherit_fds;
 
287
  GSpawnChildSetupFunc   child_setup_func;
 
288
  gpointer               child_setup_data;
 
289
} ChildData;
 
290
 
 
291
static void
 
292
child_setup (gpointer user_data)
 
293
{
 
294
  ChildData *child_data = user_data;
 
295
  guint i;
 
296
  gint result;
 
297
 
 
298
  /* We're on the child side now.  "Rename" the file descriptors in
 
299
   * child_data.fds[] to stdin/stdout/stderr.
 
300
   *
 
301
   * We don't close the originals.  It's possible that the originals
 
302
   * should not be closed and if they should be closed then they should
 
303
   * have been created O_CLOEXEC.
 
304
   */
 
305
  for (i = 0; i < 3; i++)
 
306
    {
 
307
      if (child_data->fds[i] != -1 && child_data->fds[i] != (int) i)
 
308
        {
 
309
          do
 
310
            result = dup2 (child_data->fds[i], i);
 
311
          while (G_UNLIKELY (result == -1 && errno == EINTR));
 
312
        }
 
313
    }
 
314
 
 
315
  /* Unset the CLOEXEC flag for the child *should* inherit */
 
316
  for (i = 0; i < child_data->inherit_fds->len; i++)
 
317
    {
 
318
      int fd = g_array_index (child_data->inherit_fds, int, i);
 
319
      int flags;
 
320
 
 
321
      do
 
322
        flags = fcntl (fd, F_GETFL);
 
323
      while (G_UNLIKELY (flags == -1 && errno == EINTR));
 
324
 
 
325
      flags &= ~FD_CLOEXEC;
 
326
      
 
327
      do
 
328
        result = fcntl (fd, F_SETFD, flags);
 
329
      while (G_UNLIKELY (result == -1 && errno == EINTR));
 
330
    }
 
331
 
 
332
  if (child_data->child_setup_func)
 
333
    child_data->child_setup_func (child_data->child_setup_data);
 
334
}
 
335
 
 
336
static gboolean
 
337
initable_init (GInitable     *initable,
 
338
               GCancellable  *cancellable,
 
339
               GError       **error)
 
340
{
 
341
  GSSubprocess *self = GS_SUBPROCESS (initable);
 
342
  ChildData child_data = { { -1, -1, -1 } };
 
343
  gint *pipe_ptrs[3] = { NULL, NULL, NULL };
 
344
  gint pipe_fds[3] = { -1, -1, -1 };
 
345
  gint close_fds[3] = { -1, -1, -1 };
 
346
  GSpawnFlags spawn_flags = 0;
 
347
  gboolean success = FALSE;
 
348
  guint i;
 
349
 
 
350
  if (g_cancellable_set_error_if_cancelled (cancellable, error))
 
351
    return FALSE;
 
352
 
 
353
  /* We must setup the three fds that will end up in the child as stdin,
 
354
   * stdout and stderr.
 
355
   *
 
356
   * First, stdin.
 
357
   */
 
358
#ifdef G_OS_UNIX
 
359
  if (self->context->stdin_fd != -1)
 
360
    child_data.fds[0] = self->context->stdin_fd;
 
361
  else if (self->context->stdin_path != NULL)
 
362
    {
 
363
      child_data.fds[0] = close_fds[0] = unix_open_file (self->context->stdin_path, 
 
364
                                                         O_RDONLY, error);
 
365
      if (child_data.fds[0] == -1)
 
366
        goto out;
 
367
    }
 
368
  else
 
369
#endif
 
370
  if (self->context->stdin_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_NULL)
 
371
    ; /* nothing */
 
372
  else if (self->context->stdin_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT)
 
373
    spawn_flags |= G_SPAWN_CHILD_INHERITS_STDIN;
 
374
  else if (self->context->stdin_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_PIPE)
 
375
    pipe_ptrs[0] = &pipe_fds[0];
 
376
  else
 
377
    g_assert_not_reached ();
 
378
 
 
379
  /* Next, stdout. */
 
380
#ifdef G_OS_UNIX
 
381
  if (self->context->stdout_fd != -1)
 
382
    child_data.fds[1] = self->context->stdout_fd;
 
383
  else if (self->context->stdout_path != NULL)
 
384
    {
 
385
      child_data.fds[1] = close_fds[1] = unix_open_file (self->context->stdout_path, 
 
386
                                                         O_CREAT | O_WRONLY, error);
 
387
      if (child_data.fds[1] == -1)
 
388
        goto out;
 
389
    }
 
390
  else
 
391
#endif
 
392
  if (self->context->stdout_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_NULL)
 
393
    spawn_flags |= G_SPAWN_STDOUT_TO_DEV_NULL;
 
394
  else if (self->context->stdout_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT)
 
395
    ; /* Nothing */
 
396
  else if (self->context->stdout_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_PIPE)
 
397
    pipe_ptrs[1] = &pipe_fds[1];
 
398
  else
 
399
    g_assert_not_reached ();
 
400
 
 
401
  /* Finally, stderr. */
 
402
#ifdef G_OS_UNIX
 
403
  if (self->context->stderr_fd != -1)
 
404
    child_data.fds[2] = self->context->stderr_fd;
 
405
  else if (self->context->stderr_path != NULL)
 
406
    {
 
407
      child_data.fds[2] = close_fds[2] = unix_open_file (self->context->stderr_path, 
 
408
                                                         O_CREAT | O_WRONLY, error);
 
409
      if (child_data.fds[2] == -1)
 
410
        goto out;
 
411
    }
 
412
  else
 
413
#endif
 
414
  if (self->context->stderr_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_NULL)
 
415
    spawn_flags |= G_SPAWN_STDERR_TO_DEV_NULL;
 
416
  else if (self->context->stderr_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT)
 
417
    ; /* Nothing */
 
418
  else if (self->context->stderr_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_PIPE)
 
419
    pipe_ptrs[2] = &pipe_fds[2];
 
420
  else if (self->context->stderr_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE)
 
421
    /* This will work because stderr gets setup after stdout. */
 
422
    child_data.fds[2] = 1;
 
423
  else
 
424
    g_assert_not_reached ();
 
425
 
 
426
  child_data.inherit_fds = self->context->inherit_fds;
 
427
 
 
428
  if (self->context->keep_descriptors)
 
429
    spawn_flags |= G_SPAWN_LEAVE_DESCRIPTORS_OPEN;
 
430
 
 
431
  if (self->context->search_path)
 
432
    spawn_flags |= G_SPAWN_SEARCH_PATH;
 
433
  else if (self->context->search_path_from_envp)
 
434
    spawn_flags |= G_SPAWN_SEARCH_PATH_FROM_ENVP;
 
435
  else if (!g_path_is_absolute (((gchar**)self->context->argv)[0]))
 
436
    spawn_flags |= G_SPAWN_SEARCH_PATH;
 
437
 
 
438
  if (self->context->has_argv0)
 
439
    spawn_flags |= G_SPAWN_FILE_AND_ARGV_ZERO;
 
440
 
 
441
  spawn_flags |= G_SPAWN_DO_NOT_REAP_CHILD;
 
442
#ifdef GLIB_COMPILATION
 
443
  spawn_flags |= G_SPAWN_CLOEXEC_PIPES;
 
444
#endif
 
445
 
 
446
  child_data.child_setup_func = self->context->child_setup_func;
 
447
  child_data.child_setup_data = self->context->child_setup_data;
 
448
  success = g_spawn_async_with_pipes (self->context->cwd,
 
449
                                      (char**)self->context->argv,
 
450
                                      self->context->envp,
 
451
                                      spawn_flags,
 
452
                                      child_setup, &child_data,
 
453
                                      &self->pid,
 
454
                                      pipe_ptrs[0], pipe_ptrs[1], pipe_ptrs[2],
 
455
                                      error);
 
456
  if (success)
 
457
    self->pid_valid = TRUE;
 
458
 
 
459
out:
 
460
  for (i = 0; i < 3; i++)
 
461
    if (close_fds[i] != -1)
 
462
      close (close_fds[i]);
 
463
 
 
464
  for (i = 0; i < self->context->postfork_close_fds->len; i++)
 
465
    (void) close (g_array_index (self->context->postfork_close_fds, int, i));
 
466
 
 
467
  self->stdin_pipe = platform_output_stream_from_spawn_fd (pipe_fds[0]);
 
468
  self->stdout_pipe = platform_input_stream_from_spawn_fd (pipe_fds[1]);
 
469
  self->stderr_pipe = platform_input_stream_from_spawn_fd (pipe_fds[2]);
 
470
 
 
471
  return success;
 
472
}
 
473
 
 
474
static void
 
475
initable_iface_init (GInitableIface *initable_iface)
 
476
{
 
477
  initable_iface->init = initable_init;
 
478
}
 
479
 
 
480
/**
 
481
 * gs_subprocess_new:
 
482
 *
 
483
 * Create a new process, using the parameters specified by
 
484
 * GSSubprocessContext.
 
485
 *
 
486
 * Returns: (transfer full): A newly created %GSSubprocess, or %NULL on error (and @error will be set)
 
487
 *
 
488
 * Since: 2.36
 
489
 */
 
490
GSSubprocess *
 
491
gs_subprocess_new (GSSubprocessContext   *context,
 
492
                   GCancellable          *cancellable,
 
493
                   GError               **error)
 
494
{
 
495
  return g_initable_new (GS_TYPE_SUBPROCESS,
 
496
                         cancellable, error,
 
497
                         "context", context,
 
498
                         NULL);
 
499
}
 
500
 
 
501
/**
 
502
 * gs_subprocess_get_pid:
 
503
 * @self: a #GSSubprocess
 
504
 *
 
505
 * The identifier for this child process; it is valid as long as the
 
506
 * process @self is referenced.  In particular, do
 
507
 * <emphasis>not</emphasis> call g_spawn_close_pid() on this value;
 
508
 * that is handled internally.
 
509
 *
 
510
 * On some Unix versions, it is possible for there to be a race
 
511
 * condition where waitpid() may have been called to collect the child
 
512
 * before any watches (such as that installed by
 
513
 * gs_subprocess_add_watch()) have fired.  If you are planning to use
 
514
 * native functions such as kill() on the pid, your program should
 
515
 * gracefully handle an %ESRCH result to mitigate this.
 
516
 *
 
517
 * If you want to request process termination, using the high level
 
518
 * gs_subprocess_request_exit() and gs_subprocess_force_exit() API is
 
519
 * recommended.
 
520
 *
 
521
 * Returns: Operating-system specific identifier for child process
 
522
 *
 
523
 * Since: 2.36
 
524
 */
 
525
GPid
 
526
gs_subprocess_get_pid (GSSubprocess     *self)
 
527
{
 
528
  g_return_val_if_fail (GS_IS_SUBPROCESS (self), 0);
 
529
 
 
530
  return self->pid;
 
531
}
 
532
 
 
533
/**
 
534
 * gs_subprocess_get_stdin_pipe:
 
535
 *
 
536
 * Returns: (transfer none): Pipe
 
537
 */
 
538
GOutputStream *
 
539
gs_subprocess_get_stdin_pipe (GSSubprocess       *self)
 
540
{
 
541
  g_return_val_if_fail (GS_IS_SUBPROCESS (self), NULL);
 
542
  g_return_val_if_fail (self->stdin_pipe, NULL);
 
543
 
 
544
  return self->stdin_pipe;
 
545
}
 
546
 
 
547
/**
 
548
 * gs_subprocess_get_stdout_pipe:
 
549
 *
 
550
 * Returns: (transfer none): Pipe
 
551
 */
 
552
GInputStream *
 
553
gs_subprocess_get_stdout_pipe (GSSubprocess      *self)
 
554
{
 
555
  g_return_val_if_fail (GS_IS_SUBPROCESS (self), NULL);
 
556
  g_return_val_if_fail (self->stdout_pipe, NULL);
 
557
 
 
558
  return self->stdout_pipe;
 
559
}
 
560
 
 
561
/**
 
562
 * gs_subprocess_get_stderr_pipe:
 
563
 *
 
564
 * Returns: (transfer none): Pipe
 
565
 */
 
566
GInputStream *
 
567
gs_subprocess_get_stderr_pipe (GSSubprocess      *self)
 
568
{
 
569
  g_return_val_if_fail (GS_IS_SUBPROCESS (self), NULL);
 
570
  g_return_val_if_fail (self->stderr_pipe, NULL);
 
571
 
 
572
  return self->stderr_pipe;
 
573
}
 
574
 
 
575
typedef struct {
 
576
  GSSubprocess *self;
 
577
  GCancellable *cancellable;
 
578
  GSimpleAsyncResult *result;
 
579
} GSSubprocessWatchData;
 
580
 
 
581
static gboolean
 
582
gs_subprocess_on_child_exited (GPid       pid,
 
583
                              gint       status_code,
 
584
                              gpointer   user_data)
 
585
{
 
586
  GSSubprocessWatchData *data = user_data;
 
587
  GError *error = NULL;
 
588
  
 
589
  if (g_cancellable_set_error_if_cancelled (data->cancellable, &error))
 
590
    {
 
591
      g_simple_async_result_take_error (data->result, error);
 
592
    }
 
593
  else
 
594
    {
 
595
      data->self->reaped_child = TRUE;
 
596
 
 
597
      g_simple_async_result_set_op_res_gssize (data->result, status_code);
 
598
    }
 
599
 
 
600
  g_simple_async_result_complete (data->result);
 
601
 
 
602
  g_object_unref (data->result);
 
603
  g_object_unref (data->self);
 
604
  g_free (data);
 
605
 
 
606
  return FALSE;
 
607
}
 
608
 
 
609
/**
 
610
 * gs_subprocess_wait:
 
611
 * @self: a #GSSubprocess
 
612
 * @cancellable: a #GCancellable
 
613
 * @callback: Invoked when process exits, or @cancellable is cancelled
 
614
 * @user_data: Data for @callback
 
615
 *
 
616
 * Start an asynchronous wait for the subprocess @self to exit.
 
617
 *
 
618
 * Since: 2.36
 
619
 */
 
620
void
 
621
gs_subprocess_wait (GSSubprocess                *self,
 
622
                   GCancellable               *cancellable,
 
623
                   GAsyncReadyCallback         callback,
 
624
                   gpointer                    user_data)
 
625
{
 
626
  GSource *source;
 
627
  GSSubprocessWatchData *data;
 
628
 
 
629
  data = g_new0 (GSSubprocessWatchData, 1);
 
630
 
 
631
  data->self = g_object_ref (self);
 
632
  data->result = g_simple_async_result_new ((GObject*)self, callback, user_data,
 
633
                                            gs_subprocess_wait);
 
634
 
 
635
  source = g_child_watch_source_new (self->pid);
 
636
 
 
637
  g_source_set_callback (source, (GSourceFunc)gs_subprocess_on_child_exited,
 
638
                         data, NULL);
 
639
  if (cancellable)
 
640
    {
 
641
      GSource *cancellable_source;
 
642
 
 
643
      data->cancellable = g_object_ref (cancellable);
 
644
 
 
645
      cancellable_source = g_cancellable_source_new (cancellable);
 
646
      g_source_add_child_source (source, cancellable_source);
 
647
      g_source_unref (cancellable_source);
 
648
    }
 
649
 
 
650
  g_source_attach (source, g_main_context_get_thread_default ());
 
651
  g_source_unref (source);
 
652
}
 
653
 
 
654
/**
 
655
 * gs_subprocess_wait_finish:
 
656
 * @self: a #GSSubprocess
 
657
 * @result: a #GAsyncResult
 
658
 * @out_exit_status: (out): Exit status of the process encoded in platform-specific way
 
659
 * @error: a #GError
 
660
 *
 
661
 * The exit status of the process will be stored in @out_exit_status.
 
662
 * See the documentation of g_spawn_check_exit_status() for more
 
663
 * details.
 
664
 *
 
665
 * Note that @error is not set if the process exits abnormally; you
 
666
 * must use g_spawn_check_exit_status() for that.
 
667
 *
 
668
 * Since: 2.36
 
669
 */
 
670
gboolean
 
671
gs_subprocess_wait_finish (GSSubprocess                *self,
 
672
                          GAsyncResult               *result,
 
673
                          int                        *out_exit_status,
 
674
                          GError                    **error)
 
675
{
 
676
  GSimpleAsyncResult *simple;
 
677
 
 
678
  simple = G_SIMPLE_ASYNC_RESULT (result);
 
679
 
 
680
  if (g_simple_async_result_propagate_error (simple, error))
 
681
    return FALSE;
 
682
 
 
683
  *out_exit_status = g_simple_async_result_get_op_res_gssize (simple);
 
684
  
 
685
  return TRUE;
 
686
}
 
687
 
 
688
typedef struct {
 
689
  GMainLoop *loop;
 
690
  gint *exit_status_ptr;
 
691
  gboolean caught_error;
 
692
  GError **error;
 
693
} GSSubprocessSyncWaitData;
 
694
 
 
695
static void
 
696
gs_subprocess_on_sync_wait_complete (GObject       *object,
 
697
                                    GAsyncResult  *result,
 
698
                                    gpointer       user_data)
 
699
{
 
700
  GSSubprocessSyncWaitData *data = user_data;
 
701
 
 
702
  if (!gs_subprocess_wait_finish ((GSSubprocess*)object, result, 
 
703
                                 data->exit_status_ptr, data->error))
 
704
    data->caught_error = TRUE;
 
705
 
 
706
  g_main_loop_quit (data->loop);
 
707
}
 
708
 
 
709
/**
 
710
 * gs_subprocess_wait_sync:
 
711
 * @self: a #GSSubprocess
 
712
 * @out_exit_status: (out): Platform-specific exit code
 
713
 * @cancellable: a #GCancellable
 
714
 * @error: a #GError
 
715
 *
 
716
 * Synchronously wait for the subprocess to terminate, returning the
 
717
 * status code in @out_exit_status.  See the documentation of
 
718
 * g_spawn_check_exit_status() for how to interpret it.  Note that if
 
719
 * @error is set, then @out_exit_status will be left uninitialized.
 
720
 * 
 
721
 * Returns: %TRUE on success, %FALSE if @cancellable was cancelled
 
722
 *
 
723
 * Since: 2.36
 
724
 */
 
725
gboolean
 
726
gs_subprocess_wait_sync (GSSubprocess        *self,
 
727
                        int                *out_exit_status,
 
728
                        GCancellable       *cancellable,
 
729
                        GError            **error)
 
730
{
 
731
  gboolean ret = FALSE;
 
732
  gboolean pushed_thread_default = FALSE;
 
733
  GMainContext *context = NULL;
 
734
  GSSubprocessSyncWaitData data;
 
735
 
 
736
  memset (&data, 0, sizeof (data));
 
737
 
 
738
  g_return_val_if_fail (GS_IS_SUBPROCESS (self), FALSE);
 
739
 
 
740
  if (g_cancellable_set_error_if_cancelled (cancellable, error))
 
741
    return FALSE;
 
742
 
 
743
  context = g_main_context_new ();
 
744
  g_main_context_push_thread_default (context);
 
745
  pushed_thread_default = TRUE;
 
746
 
 
747
  data.exit_status_ptr = out_exit_status;
 
748
  data.loop = g_main_loop_new (context, TRUE);
 
749
  data.error = error;
 
750
 
 
751
  gs_subprocess_wait (self, cancellable,
 
752
                     gs_subprocess_on_sync_wait_complete, &data);
 
753
 
 
754
  g_main_loop_run (data.loop);
 
755
 
 
756
  if (data.caught_error)
 
757
    goto out;
 
758
 
 
759
  ret = TRUE;
 
760
 out:
 
761
  if (pushed_thread_default)
 
762
    g_main_context_pop_thread_default (context);
 
763
  if (context)
 
764
    g_main_context_unref (context);
 
765
  if (data.loop)
 
766
    g_main_loop_unref (data.loop);
 
767
 
 
768
  return ret;
 
769
}
 
770
 
 
771
/**
 
772
 * gs_subprocess_wait_sync_check:
 
773
 * @self: a #GSSubprocess
 
774
 * @cancellable: a #GCancellable
 
775
 * @error: a #GError
 
776
 *
 
777
 * Combines gs_subprocess_wait_sync() with g_spawn_check_exit_status().
 
778
 * 
 
779
 * Returns: %TRUE on success, %FALSE if process exited abnormally, or @cancellable was cancelled
 
780
 *
 
781
 * Since: 2.36
 
782
 */
 
783
gboolean
 
784
gs_subprocess_wait_sync_check (GSSubprocess        *self,
 
785
                              GCancellable       *cancellable,
 
786
                              GError            **error)
 
787
{
 
788
  gboolean ret = FALSE;
 
789
  int exit_status;
 
790
 
 
791
  if (!gs_subprocess_wait_sync (self, &exit_status, cancellable, error))
 
792
    goto out;
 
793
 
 
794
  if (!g_spawn_check_exit_status (exit_status, error))
 
795
    goto out;
 
796
 
 
797
  ret = TRUE;
 
798
 out:
 
799
  return ret;
 
800
}
 
801
 
 
802
/**
 
803
 * gs_subprocess_request_exit:
 
804
 * @self: a #GSSubprocess
 
805
 *
 
806
 * This API uses an operating-system specific mechanism to request
 
807
 * that the subprocess gracefully exit.  This API is not available on
 
808
 * all operating systems; for those not supported, it will do nothing
 
809
 * and return %FALSE.  Portable code should handle this situation
 
810
 * gracefully.  For example, if you are communicating via input or
 
811
 * output pipe with the child, many programs will automatically exit
 
812
 * when one of their standard input or output are closed.
 
813
 *
 
814
 * On Unix, this API sends %SIGTERM.
 
815
 *
 
816
 * A %TRUE return value does <emphasis>not</emphasis> mean the
 
817
 * subprocess has exited, merely that an exit request was initiated.
 
818
 * You can use gs_subprocess_add_watch() to monitor the status of the
 
819
 * process after calling this function.
 
820
 *
 
821
 * This function returns %TRUE if the process has already exited.
 
822
 *
 
823
 * Returns: %TRUE if the operation is supported, %FALSE otherwise.
 
824
 *
 
825
 * Since: 2.36
 
826
 */
 
827
gboolean
 
828
gs_subprocess_request_exit (GSSubprocess *self)
 
829
{
 
830
  g_return_val_if_fail (GS_IS_SUBPROCESS (self), FALSE);
 
831
 
 
832
#ifdef G_OS_UNIX
 
833
  (void) kill (self->pid, SIGTERM);
 
834
  return TRUE;
 
835
#else
 
836
  return FALSE;
 
837
#endif
 
838
}
 
839
 
 
840
/**
 
841
 * gs_subprocess_force_exit:
 
842
 * @self: a #GSSubprocess
 
843
 *
 
844
 * Use an operating-system specific method to attempt an immediate,
 
845
 * forceful termination of the process.  There is no mechanism to
 
846
 * determine whether or not the request itself was successful;
 
847
 * however, you can use gs_subprocess_wait() to monitor the status of
 
848
 * the process after calling this function.
 
849
 *
 
850
 * On Unix, this function sends %SIGKILL.
 
851
 */
 
852
void
 
853
gs_subprocess_force_exit (GSSubprocess *self)
 
854
{
 
855
  g_return_if_fail (GS_IS_SUBPROCESS (self));
 
856
 
 
857
#if !defined(GLIB_COMPIATION)
 
858
  {
 
859
    int ret;
 
860
    do
 
861
      ret = kill (self->pid, SIGKILL);
 
862
    while (ret == -1 && errno == EINTR);
 
863
  }
 
864
#elif defined(G_OS_UNIX)
 
865
  GLIB_PRIVATE_CALL (g_main_send_signal) (self->pid, SIGKILL);
 
866
#else
 
867
  TerminateProcess (self->pid, 1);
 
868
#endif
 
869
}
 
870
 
 
871
GSSubprocess *
 
872
gs_subprocess_new_simple_argl (GSSubprocessStreamDisposition stdout_disposition,
 
873
                              GSSubprocessStreamDisposition  stderr_disposition,
 
874
                               GCancellable                 *cancellable,
 
875
                              GError                       **error,
 
876
                              const gchar                   *first_arg,
 
877
                              ...)
 
878
{
 
879
  va_list args;
 
880
  GSSubprocess *result;
 
881
  GSSubprocessContext *context;
 
882
 
 
883
  va_start (args, first_arg);
 
884
  context = gs_subprocess_context_newa (first_arg, args);
 
885
  va_end (args);
 
886
  result = gs_subprocess_new (context, cancellable, error);
 
887
  g_object_unref (context);
 
888
  
 
889
  return result;
 
890
}
 
891
 
 
892
/**
 
893
 * gs_subprocess_new_simple_argv:
 
894
 * @argv: (array zero-terminated=1) (element-type utf8): Argument array
 
895
 * @stdout_disposition: Where to redirect stdout
 
896
 * @stderr_disposition: Where to redirect stdout
 
897
 * @error: a #GError
 
898
 *
 
899
 * Create a new subprocess using the provided argument array and
 
900
 * stream dispositions.
 
901
 */
 
902
GSSubprocess *
 
903
gs_subprocess_new_simple_argv (gchar                       **argv,
 
904
                              GSSubprocessStreamDisposition  stdout_disposition,
 
905
                              GSSubprocessStreamDisposition  stderr_disposition,
 
906
                               GCancellable                 *cancellable,
 
907
                              GError                      **error)
 
908
{
 
909
  GSSubprocessContext *context;
 
910
  GSSubprocess *result;
 
911
 
 
912
  context = gs_subprocess_context_new (argv);
 
913
  gs_subprocess_context_set_stdout_disposition (context, stdout_disposition);
 
914
  gs_subprocess_context_set_stderr_disposition (context, stderr_disposition);
 
915
 
 
916
  result = gs_subprocess_new (context, cancellable, error);
 
917
  g_object_unref (context);
 
918
 
 
919
  return result;
 
920
}
 
921
 
 
922
/**
 
923
 * gs_subprocess_simple_run_sync:
 
924
 * @cwd: Current working directory
 
925
 * @stdin_disposition: What to do with standard input
 
926
 * @cancellable: a #GCancellable
 
927
 * @error: a #GError
 
928
 * @first_arg: First argument
 
929
 * @...: Remaining arguments, %NULL terminated
 
930
 *
 
931
 * Run a process synchronously, throw an error if it fails.
 
932
 */
 
933
gboolean
 
934
gs_subprocess_simple_run_sync (const char                    *cwd,
 
935
                               GSSubprocessStreamDisposition  stdin_disposition,
 
936
                               GCancellable                  *cancellable,
 
937
                               GError                       **error,
 
938
                               const char                    *first_arg,
 
939
                               ...)
 
940
{
 
941
  gboolean ret = FALSE;
 
942
  va_list args;
 
943
  GSSubprocess *proc = NULL;
 
944
  GSSubprocessContext *context = NULL;
 
945
 
 
946
  va_start (args, first_arg);
 
947
  context = gs_subprocess_context_newa (first_arg, args);
 
948
  va_end (args);
 
949
  gs_subprocess_context_set_stdin_disposition (context, stdin_disposition);
 
950
  gs_subprocess_context_set_cwd (context, cwd);
 
951
  proc = gs_subprocess_new (context, cancellable, error);
 
952
  if (!proc)
 
953
    goto out;
 
954
 
 
955
  if (!gs_subprocess_wait_sync_check (proc, cancellable, error))
 
956
    goto out;
 
957
 
 
958
  ret = TRUE;
 
959
 out:
 
960
  g_object_unref (context);
 
961
  if (proc)
 
962
    g_object_unref (proc);
 
963
  return ret;
 
964
}
 
965
 
 
966
#endif