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

« back to all changes in this revision

Viewing changes to libgnome-desktop/libgsystem/gsystem-subprocess-context.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
 * Copyright (C) 2012 Colin Walters <walters@verbum.org>
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Lesser General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Lesser General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Lesser General Public
 
16
 * License along with this library; if not, write to the
 
17
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
18
 * Boston, MA 02111-1307, USA.
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
 
 
23
#include "libgsystem.h"
 
24
 
 
25
#if GLIB_CHECK_VERSION(2,34,0)
 
26
 
 
27
#ifdef G_OS_UNIX
 
28
#include <gio/gunixoutputstream.h>
 
29
#include <gio/gfiledescriptorbased.h>
 
30
#include <gio/gunixinputstream.h>
 
31
#include <glib-unix.h>
 
32
#endif
 
33
 
 
34
/**
 
35
 * SECTION:gssubprocesscontext
 
36
 * @title: GSSubprocess Context
 
37
 * @short_description: Environment options for launching a child process
 
38
 *
 
39
 * This class contains a set of options for launching child processes,
 
40
 * such as where its standard input and output will be directed, the
 
41
 * argument list, the environment, and more.
 
42
 *
 
43
 * While the #GSSubprocess class has high level functions covering
 
44
 * popular cases, use of this class allows access to more advanced
 
45
 * options.  It can also be used to launch multiple subprocesses with
 
46
 * a similar configuration.
 
47
 *
 
48
 * Since: 2.36
 
49
 */
 
50
 
 
51
#include "config.h"
 
52
 
 
53
#include "gsystem-subprocess-context-private.h"
 
54
#include "gsystem-subprocess.h"
 
55
 
 
56
#include <string.h>
 
57
 
 
58
typedef GObjectClass GSSubprocessContextClass;
 
59
 
 
60
G_DEFINE_TYPE (GSSubprocessContext, gs_subprocess_context, G_TYPE_OBJECT);
 
61
 
 
62
enum
 
63
{
 
64
  PROP_0,
 
65
  PROP_ARGV,
 
66
  N_PROPS
 
67
};
 
68
 
 
69
static GParamSpec *gs_subprocess_context_pspecs[N_PROPS];
 
70
 
 
71
/**
 
72
 * gs_subprocess_context_new:
 
73
 * @argv: Argument list
 
74
 *
 
75
 * Returns: (transfer full): A new instance of a #GSSubprocessContext.
 
76
 */
 
77
GSSubprocessContext *
 
78
gs_subprocess_context_new (gchar           **argv)
 
79
{
 
80
  g_return_val_if_fail (argv != NULL && argv[0] != NULL, NULL);
 
81
 
 
82
  return g_object_new (GS_TYPE_SUBPROCESS_CONTEXT,
 
83
                       "argv", argv,
 
84
                       NULL);
 
85
}
 
86
 
 
87
GSSubprocessContext *
 
88
gs_subprocess_context_newv (const gchar  *first_arg,
 
89
                           ...)
 
90
{
 
91
  GSSubprocessContext *result;
 
92
  va_list args;
 
93
 
 
94
  g_return_val_if_fail (first_arg != NULL, NULL);
 
95
 
 
96
  va_start (args, first_arg);
 
97
  result = gs_subprocess_context_newa (first_arg, args);
 
98
  va_end (args);
 
99
  
 
100
  return result;
 
101
}
 
102
 
 
103
/**
 
104
 * gs_subprocess_context_newa:
 
105
 * @first_arg: First argument
 
106
 * @args: a va_list
 
107
 *
 
108
 * Returns: (transfer full): A new instance of a #GSSubprocessContext.
 
109
 */
 
110
GSSubprocessContext *
 
111
gs_subprocess_context_newa (const gchar *first_arg,
 
112
                           va_list      args)
 
113
{
 
114
  GSSubprocessContext *result;
 
115
  GPtrArray *argv;
 
116
 
 
117
  g_return_val_if_fail (first_arg != NULL, NULL);
 
118
 
 
119
  argv = g_ptr_array_new ();
 
120
  do
 
121
    g_ptr_array_add (argv, (gchar*)first_arg);
 
122
  while ((first_arg = va_arg (args, const gchar *)) != NULL);
 
123
  g_ptr_array_add (argv, NULL);
 
124
 
 
125
  result = gs_subprocess_context_new ((gchar**)argv->pdata);
 
126
  
 
127
  return result;
 
128
}
 
129
 
 
130
#ifdef G_OS_UNIX
 
131
GSSubprocessContext *
 
132
gs_subprocess_context_new_argv0 (const gchar      *argv0,
 
133
                                gchar           **argv)
 
134
{
 
135
  GSSubprocessContext *result;
 
136
  GPtrArray *real_argv;
 
137
  gchar **iter;
 
138
  
 
139
  g_return_val_if_fail (argv0 != NULL, NULL);
 
140
  g_return_val_if_fail (argv != NULL && argv[0] != NULL, NULL);
 
141
  
 
142
  real_argv = g_ptr_array_new ();
 
143
  g_ptr_array_add (real_argv, (gchar*)argv0);
 
144
  for (iter = argv; *iter; iter++)
 
145
    g_ptr_array_add (real_argv, (gchar*) *iter);
 
146
  g_ptr_array_add (real_argv, NULL);
 
147
 
 
148
  result = g_object_new (GS_TYPE_SUBPROCESS_CONTEXT,
 
149
                         "argv", real_argv->pdata,
 
150
                         NULL);
 
151
  result->has_argv0 = TRUE;
 
152
 
 
153
  return result;
 
154
}
 
155
#endif
 
156
 
 
157
static void
 
158
gs_subprocess_context_init (GSSubprocessContext  *self)
 
159
{
 
160
  self->stdin_fd = -1;
 
161
  self->stdout_fd = -1;
 
162
  self->stderr_fd = -1;
 
163
  self->stdout_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT;
 
164
  self->stderr_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT;
 
165
  self->postfork_close_fds = g_array_new (FALSE, FALSE, sizeof (int));
 
166
  self->inherit_fds = g_array_new (FALSE, FALSE, sizeof (int));
 
167
}
 
168
 
 
169
static void
 
170
gs_subprocess_context_finalize (GObject *object)
 
171
{
 
172
  GSSubprocessContext *self = GS_SUBPROCESS_CONTEXT (object);
 
173
 
 
174
  g_strfreev (self->argv);
 
175
  g_strfreev (self->envp);
 
176
  g_free (self->cwd);
 
177
 
 
178
  g_free (self->stdin_path);
 
179
  g_free (self->stdout_path);
 
180
  g_free (self->stderr_path);
 
181
 
 
182
  g_array_unref (self->postfork_close_fds);
 
183
  g_array_unref (self->inherit_fds);
 
184
 
 
185
  if (G_OBJECT_CLASS (gs_subprocess_context_parent_class)->finalize != NULL)
 
186
    G_OBJECT_CLASS (gs_subprocess_context_parent_class)->finalize (object);
 
187
}
 
188
 
 
189
static void
 
190
gs_subprocess_context_set_property (GObject      *object,
 
191
                                   guint         prop_id,
 
192
                                   const GValue *value,
 
193
                                   GParamSpec   *pspec)
 
194
{
 
195
  GSSubprocessContext *self = GS_SUBPROCESS_CONTEXT (object);
 
196
 
 
197
  switch (prop_id)
 
198
    {
 
199
    case PROP_ARGV:
 
200
      self->argv = (gchar**) g_value_dup_boxed (value);
 
201
      break;
 
202
 
 
203
    default:
 
204
      g_assert_not_reached ();
 
205
    }
 
206
}
 
207
 
 
208
static void
 
209
gs_subprocess_context_get_property (GObject    *object,
 
210
                                   guint       prop_id,
 
211
                                   GValue     *value,
 
212
                                   GParamSpec *pspec)
 
213
{
 
214
  GSSubprocessContext *self = GS_SUBPROCESS_CONTEXT (object);
 
215
 
 
216
  switch (prop_id)
 
217
    {
 
218
    case PROP_ARGV:
 
219
      g_value_set_boxed (value, self->argv);
 
220
      break;
 
221
 
 
222
    default:
 
223
      g_assert_not_reached ();
 
224
    }
 
225
}
 
226
 
 
227
static void
 
228
gs_subprocess_context_class_init (GSSubprocessContextClass *class)
 
229
{
 
230
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
 
231
 
 
232
  gobject_class->finalize = gs_subprocess_context_finalize;
 
233
  gobject_class->get_property = gs_subprocess_context_get_property;
 
234
  gobject_class->set_property = gs_subprocess_context_set_property;
 
235
 
 
236
  /**
 
237
   * GSSubprocessContext:argv:
 
238
   *
 
239
   * Array of arguments passed to child process; must have at least
 
240
   * one element.  The first element has special handling - if it is
 
241
   * an not absolute path ( as determined by g_path_is_absolute() ),
 
242
   * then the system search path will be used.  See
 
243
   * %G_SPAWN_SEARCH_PATH.
 
244
   * 
 
245
   * Note that in order to use the Unix-specific argv0 functionality,
 
246
   * you must use the setter function
 
247
   * gs_subprocess_context_set_args_and_argv0().  For more information
 
248
   * about this, see %G_SPAWN_FILE_AND_ARGV_ZERO.
 
249
   *
 
250
   * Since: 2.36
 
251
   */
 
252
  gs_subprocess_context_pspecs[PROP_ARGV] = g_param_spec_boxed ("argv", "Arguments", "Arguments for child process", G_TYPE_STRV,
 
253
                                                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
254
 
 
255
  g_object_class_install_properties (gobject_class, N_PROPS, gs_subprocess_context_pspecs);
 
256
}
 
257
 
 
258
/**
 
259
 * gs_subprocess_context_argv_append:
 
260
 * @self:
 
261
 * @arg: An argument
 
262
 *
 
263
 * Append an argument to the child's argument vector.
 
264
 */
 
265
void
 
266
gs_subprocess_context_argv_append (GSSubprocessContext  *self,
 
267
                                   const gchar          *arg)
 
268
{
 
269
  GPtrArray *new_argv = g_ptr_array_new ();
 
270
  gchar **iter;
 
271
 
 
272
  for (iter = self->argv; *iter; iter++)
 
273
    g_ptr_array_add (new_argv, *iter);
 
274
  g_ptr_array_add (new_argv, g_strdup (arg));
 
275
  g_ptr_array_add (new_argv, NULL);
 
276
 
 
277
  /* Don't free elements */
 
278
  g_free (self->argv);
 
279
  self->argv = (char**)g_ptr_array_free (new_argv, FALSE);
 
280
}
 
281
 
 
282
/* Environment */
 
283
 
 
284
/**
 
285
 * gs_subprocess_context_set_environment:
 
286
 * @self:
 
287
 * @environ: (array zero-terminated=1) (element-type utf8): Environment KEY=VALUE pairs
 
288
 *
 
289
 * Replace the environment that will be used for the child process.
 
290
 * The default is to inherit the current process.
 
291
 */
 
292
void
 
293
gs_subprocess_context_set_environment (GSSubprocessContext           *self,
 
294
                                       gchar                        **env)
 
295
{
 
296
  g_strfreev (self->envp);
 
297
  self->envp = g_strdupv (env);
 
298
}
 
299
 
 
300
void
 
301
gs_subprocess_context_set_cwd (GSSubprocessContext           *self,
 
302
                              const gchar                  *cwd)
 
303
{
 
304
  g_free (self->cwd);
 
305
  self->cwd = g_strdup (cwd);
 
306
}
 
307
 
 
308
void
 
309
gs_subprocess_context_set_keep_descriptors (GSSubprocessContext           *self,
 
310
                                           gboolean                      keep_descriptors)
 
311
 
 
312
{
 
313
  self->keep_descriptors = keep_descriptors ? 1 : 0;
 
314
}
 
315
 
 
316
void
 
317
gs_subprocess_context_set_search_path (GSSubprocessContext           *self,
 
318
                                      gboolean                      search_path,
 
319
                                      gboolean                      search_path_from_envp)
 
320
{
 
321
  self->search_path = search_path ? 1 : 0;
 
322
  self->search_path_from_envp = search_path_from_envp ? 1 : 0;
 
323
}
 
324
 
 
325
void
 
326
gs_subprocess_context_set_stdin_disposition (GSSubprocessContext           *self,
 
327
                                            GSSubprocessStreamDisposition  disposition)
 
328
{
 
329
  g_return_if_fail (disposition != GS_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE);
 
330
  self->stdin_disposition = disposition;
 
331
}
 
332
 
 
333
void
 
334
gs_subprocess_context_set_stdout_disposition (GSSubprocessContext           *self,
 
335
                                             GSSubprocessStreamDisposition  disposition)
 
336
{
 
337
  g_return_if_fail (disposition != GS_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE);
 
338
  self->stdout_disposition = disposition;
 
339
}
 
340
 
 
341
void
 
342
gs_subprocess_context_set_stderr_disposition (GSSubprocessContext           *self,
 
343
                                             GSSubprocessStreamDisposition  disposition)
 
344
{
 
345
  self->stderr_disposition = disposition;
 
346
}
 
347
 
 
348
#ifdef G_OS_UNIX
 
349
void
 
350
gs_subprocess_context_set_stdin_file_path (GSSubprocessContext           *self,
 
351
                                          const gchar                  *path)
 
352
{
 
353
  self->stdin_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL;
 
354
  g_free (self->stdin_path);
 
355
  self->stdin_path = g_strdup (path);
 
356
}
 
357
 
 
358
void
 
359
gs_subprocess_context_set_stdin_fd        (GSSubprocessContext           *self,
 
360
                                          gint                          fd)
 
361
{
 
362
  self->stdin_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL;
 
363
  self->stdin_fd = fd;
 
364
}
 
365
 
 
366
void
 
367
gs_subprocess_context_set_stdout_file_path (GSSubprocessContext           *self,
 
368
                                           const gchar                  *path)
 
369
{
 
370
  self->stdout_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL;
 
371
  g_free (self->stdout_path);
 
372
  self->stdout_path = g_strdup (path);
 
373
}
 
374
 
 
375
void
 
376
gs_subprocess_context_set_stdout_fd (GSSubprocessContext           *self,
 
377
                                    gint                          fd)
 
378
{
 
379
  self->stdout_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL;
 
380
  self->stdout_fd = fd;
 
381
}
 
382
 
 
383
void
 
384
gs_subprocess_context_set_stderr_file_path (GSSubprocessContext           *self,
 
385
                                           const gchar                  *path)
 
386
{
 
387
  self->stderr_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL;
 
388
  g_free (self->stderr_path);
 
389
  self->stderr_path = g_strdup (path);
 
390
}
 
391
 
 
392
void
 
393
gs_subprocess_context_set_stderr_fd        (GSSubprocessContext           *self,
 
394
                                           gint                          fd)
 
395
{
 
396
  self->stderr_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL;
 
397
  self->stderr_fd = fd;
 
398
}
 
399
#endif
 
400
 
 
401
#ifdef G_OS_UNIX
 
402
/**
 
403
 * gs_subprocess_context_set_child_setup: (skip)
 
404
 * @self:
 
405
 * @child_setup: Function to call in the newly forked child, before execve()
 
406
 * @user_data: Data passed to child
 
407
 *
 
408
 * FIXME - note extensive restricitons on GSpawnChildSetupFunc here
 
409
 */
 
410
void
 
411
gs_subprocess_context_set_child_setup (GSSubprocessContext           *self,
 
412
                                      GSpawnChildSetupFunc          child_setup,
 
413
                                      gpointer                      user_data)
 
414
{
 
415
  self->child_setup_func = child_setup;
 
416
  self->child_setup_data = user_data;
 
417
}
 
418
 
 
419
static gboolean
 
420
open_pipe_internal (GSSubprocessContext         *self,
 
421
                    gboolean                     for_read,
 
422
                    void                       **out_stream,
 
423
                    gint                        *out_fdno,
 
424
                    GError                     **error)
 
425
{
 
426
  int pipefds[2];
 
427
 
 
428
  g_return_val_if_fail (out_stream != NULL, FALSE);
 
429
  g_return_val_if_fail (out_fdno != NULL, FALSE);
 
430
 
 
431
  if (!g_unix_open_pipe (pipefds, FD_CLOEXEC, error))
 
432
    return FALSE;
 
433
 
 
434
  if (for_read)
 
435
    {
 
436
      *out_stream = g_unix_input_stream_new (pipefds[0], TRUE);
 
437
      *out_fdno = pipefds[1];
 
438
    }
 
439
  else
 
440
    {
 
441
      *out_stream = g_unix_output_stream_new (pipefds[1], TRUE);
 
442
      *out_fdno = pipefds[0];
 
443
    }
 
444
  g_array_append_val (self->inherit_fds, *out_fdno);
 
445
  g_array_append_val (self->postfork_close_fds, *out_fdno);
 
446
 
 
447
  return TRUE;
 
448
}
 
449
 
 
450
/**
 
451
 * gs_subprocess_context_open_pipe_read:
 
452
 * @self:
 
453
 * @out_stream: (out) (transfer full): A newly referenced output stream
 
454
 * @out_fdno: (out): File descriptor number for the subprocess side of the pipe
 
455
 *
 
456
 * This allows you to open a pipe between the parent and child
 
457
 * processes, independent of the standard streams.  For this function,
 
458
 * the pipe is set up so that the parent can read, and the child can
 
459
 * write.  For the opposite version, see
 
460
 * gs_subprocess_context_open_pipe_write().
 
461
 *
 
462
 * The returned @out_fdno is the file descriptor number that the child
 
463
 * will see; you need to communicate this number via a separate
 
464
 * channel, such as the argument list.  For example, if you're using
 
465
 * this pipe to send a password, provide
 
466
 * <literal>--password-fd=&lt;fdno string&gt;</literal>.
 
467
 *
 
468
 * Returns: %TRUE on success, %FALSE on error (and @error will be set)
 
469
 */
 
470
gboolean
 
471
gs_subprocess_context_open_pipe_read (GSSubprocessContext         *self,
 
472
                                      GInputStream               **out_stream,
 
473
                                      gint                        *out_fdno,
 
474
                                      GError                     **error)
 
475
{
 
476
  return open_pipe_internal (self, TRUE, (void**)out_stream, out_fdno, error);
 
477
}
 
478
 
 
479
/**
 
480
 * gs_subprocess_context_open_pipe_write:
 
481
 * @self:
 
482
 * @out_stream: (out) (transfer full): A newly referenced stream
 
483
 * @out_fdno: (out): File descriptor number for the subprocess side of the pipe
 
484
 *
 
485
 * Like gs_subprocess_context_open_pipe_read(), but returns a writable
 
486
 * channel from which the child process can read.
 
487
 *
 
488
 * Returns: %TRUE on success, %FALSE on error (and @error will be set)
 
489
 */
 
490
gboolean
 
491
gs_subprocess_context_open_pipe_write (GSSubprocessContext         *self,
 
492
                                       GOutputStream              **out_stream,
 
493
                                       gint                        *out_fdno,
 
494
                                       GError                     **error)
 
495
{
 
496
  return open_pipe_internal (self, FALSE, (void**)out_stream, out_fdno, error);
 
497
}
 
498
 
 
499
#endif
 
500
 
 
501
#endif