4
* Copyright (C) 2011 Collabora Ltd.
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU Lesser General Public License as
8
* published by the Free Software Foundation; either version 2.1 of
9
* the License, or (at your option) any later version.
11
* This program is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21
* Author: Stef Walter <stefw@collabora.co.uk>
26
#define DEBUG_FLAG GCR_DEBUG_GNUPG
27
#include "gcr-debug.h"
28
#include "gcr-gnupg-process.h"
29
#include "gcr-marshal.h"
32
#include <glib/gi18n-lib.h>
40
* GcrGnupgProcessFlags:
41
* @GCR_GNUPG_PROCESS_NONE: No flags
42
* @GCR_GNUPG_PROCESS_RESPECT_LOCALE: Respect the user's locale when running gnupg.
43
* @GCR_GNUPG_PROCESS_WITH_STATUS: Ask the process to send status records.
44
* @GCR_GNUPG_PROCESS_WITH_ATTRIBUTES: Ask the process to output attribute data.
46
* Flags for running a gnupg process.
73
static gint signals[NUM_SIGNALS] = { 0, };
75
typedef struct _GnupgSource {
77
GPollFD polls[NUM_FDS]; /* The various fd's we're listening to */
79
GcrGnupgProcess *process; /* Pointer back to the process object */
81
GByteArray *input_buf;
88
GCancellable *cancellable;
92
struct _GcrGnupgProcessPrivate {
97
GOutputStream *output;
98
GOutputStream *attributes;
105
GAsyncReadyCallback async_callback;
109
/* Forward declarations */
110
static void _gcr_gnupg_process_init_async (GAsyncResultIface *iface);
112
G_DEFINE_TYPE_WITH_CODE (GcrGnupgProcess, _gcr_gnupg_process, G_TYPE_OBJECT,
113
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, _gcr_gnupg_process_init_async));
116
_gcr_gnupg_process_init (GcrGnupgProcess *self)
118
self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_GNUPG_PROCESS,
119
GcrGnupgProcessPrivate);
123
_gcr_gnupg_process_constructed (GObject *obj)
125
GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
127
if (G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->constructed)
128
G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->constructed (obj);
130
if (!self->pv->executable)
131
self->pv->executable = g_strdup (GPG_EXECUTABLE);
135
_gcr_gnupg_process_get_property (GObject *obj, guint prop_id, GValue *value,
138
GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
142
g_value_set_string (value, self->pv->directory);
144
case PROP_EXECUTABLE:
145
g_value_set_string (value, self->pv->executable);
147
case PROP_INPUT_STREAM:
148
g_value_set_object (value, _gcr_gnupg_process_get_input_stream (self));
150
case PROP_OUTPUT_STREAM:
151
g_value_set_object (value, _gcr_gnupg_process_get_output_stream (self));
153
case PROP_ATTRIBUTE_STREAM:
154
g_value_set_object (value, _gcr_gnupg_process_get_attribute_stream (self));
157
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
163
_gcr_gnupg_process_set_property (GObject *obj, guint prop_id, const GValue *value,
166
GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
170
g_return_if_fail (!self->pv->directory);
171
self->pv->directory = g_value_dup_string (value);
173
case PROP_EXECUTABLE:
174
g_return_if_fail (!self->pv->executable);
175
self->pv->executable = g_value_dup_string (value);
177
case PROP_INPUT_STREAM:
178
_gcr_gnupg_process_set_input_stream (self, g_value_get_object (value));
180
case PROP_OUTPUT_STREAM:
181
_gcr_gnupg_process_set_output_stream (self, g_value_get_object (value));
183
case PROP_ATTRIBUTE_STREAM:
184
_gcr_gnupg_process_set_attribute_stream (self, g_value_get_object (value));
187
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
193
_gcr_gnupg_process_dispose (GObject *obj)
195
GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
197
g_clear_object (&self->pv->input);
198
g_clear_object (&self->pv->output);
199
g_clear_object (&self->pv->attributes);
201
G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->dispose (obj);
205
_gcr_gnupg_process_finalize (GObject *obj)
207
GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
209
g_assert (self->pv->source_sig == 0);
210
g_assert (!self->pv->running);
211
g_free (self->pv->directory);
212
g_free (self->pv->executable);
213
g_clear_error (&self->pv->error);
215
G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->finalize (obj);
219
_gcr_gnupg_process_class_init (GcrGnupgProcessClass *klass)
221
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
223
gobject_class->constructed = _gcr_gnupg_process_constructed;
224
gobject_class->get_property = _gcr_gnupg_process_get_property;
225
gobject_class->set_property = _gcr_gnupg_process_set_property;
226
gobject_class->dispose = _gcr_gnupg_process_dispose;
227
gobject_class->finalize = _gcr_gnupg_process_finalize;
230
* GcrGnupgProcess:directory:
232
* Directory to run as gnupg home directory, or %NULL for default
233
* ~/.gnupg/ directory.
235
g_object_class_install_property (gobject_class, PROP_DIRECTORY,
236
g_param_spec_string ("directory", "Directory", "Gnupg Directory",
237
NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
240
* GcrGnupgProcess:executable:
242
* Path to the gnupg executable, or %NULL for default.
244
g_object_class_install_property (gobject_class, PROP_EXECUTABLE,
245
g_param_spec_string ("executable", "Executable", "Gnupg Executable",
246
GPG_EXECUTABLE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
249
* GcrGnupgProcess:input-stream:
251
* Input for gnupg, or %NULL for no input.
253
g_object_class_install_property (gobject_class, PROP_INPUT_STREAM,
254
g_param_spec_object ("input-stream", "Input Stream", "Input Stream",
255
G_TYPE_INPUT_STREAM, G_PARAM_READWRITE));
258
* GcrGnupgProcess:output-stream:
260
* Output from gnupg, or %NULL for ignored output.
262
g_object_class_install_property (gobject_class, PROP_OUTPUT_STREAM,
263
g_param_spec_object ("output-stream", "Output Stream", "Output Stream",
264
G_TYPE_OUTPUT_STREAM, G_PARAM_READWRITE));
267
* GcrGnupgProcess:attribute-stream:
269
* Output of attribute data from gnupg, or %NULL for ignored attributes.
271
g_object_class_install_property (gobject_class, PROP_ATTRIBUTE_STREAM,
272
g_param_spec_object ("attribute-stream", "Attribute Stream", "Attribute Stream",
273
G_TYPE_OUTPUT_STREAM, G_PARAM_READWRITE));
276
* GcrGnupgProcess::error-line:
277
* @line: a line of error output.
279
* Signal emitted when a line of error output is available from the
282
signals[ERROR_LINE] = g_signal_new ("error-line", GCR_TYPE_GNUPG_PROCESS,
283
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrGnupgProcessClass, error_line),
284
NULL, NULL, _gcr_marshal_VOID__STRING,
285
G_TYPE_NONE, 1, G_TYPE_STRING);
288
* GcrGnupgProcess::status-record:
289
* @record: a status record.
291
* Signal emitted when a status record is available from the gnupg process.
293
signals[STATUS_RECORD] = g_signal_new ("status-record", GCR_TYPE_GNUPG_PROCESS,
294
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrGnupgProcessClass, status_record),
295
NULL, NULL, _gcr_marshal_VOID__BOXED,
296
G_TYPE_NONE, 1, GCR_TYPE_RECORD);
298
g_type_class_add_private (gobject_class, sizeof (GcrGnupgProcessPrivate));
302
_gcr_gnupg_process_get_user_data (GAsyncResult *result)
304
g_return_val_if_fail (GCR_IS_GNUPG_PROCESS (result), NULL);
305
return GCR_GNUPG_PROCESS (result)->pv->user_data;
309
_gcr_gnupg_process_get_source_object (GAsyncResult *result)
311
g_return_val_if_fail (GCR_IS_GNUPG_PROCESS (result), NULL);
312
return g_object_ref (result);
316
_gcr_gnupg_process_init_async (GAsyncResultIface *iface)
318
iface->get_source_object = _gcr_gnupg_process_get_source_object;
319
iface->get_user_data = _gcr_gnupg_process_get_user_data;
323
* _gcr_gnupg_process_new:
324
* @directory: (allow-none): The gnupg home directory
325
* @executable: (allow-none): The gpg executable
327
* Create a new GcrGnupgProcess.
329
* The gnupg home directory is where the keyring files live. If directory is
330
* %NULL then the default gnupg home directory is used.
332
* The executable will default to the compiled in path if a %NULL executable
335
* Returns: (transfer full): A newly allocated process.
338
_gcr_gnupg_process_new (const gchar *directory, const gchar *executable)
340
return g_object_new (GCR_TYPE_GNUPG_PROCESS,
341
"directory", directory,
342
"executable", executable,
347
_gcr_gnupg_process_get_directory (GcrGnupgProcess *self)
349
g_return_val_if_fail (GCR_GNUPG_PROCESS (self), NULL);
350
return self->pv->directory;
354
_gcr_gnupg_process_get_input_stream (GcrGnupgProcess *self)
356
g_return_val_if_fail (GCR_GNUPG_PROCESS (self), NULL);
357
return self->pv->input;
361
_gcr_gnupg_process_set_input_stream (GcrGnupgProcess *self,
364
g_return_if_fail (GCR_GNUPG_PROCESS (self));
365
g_return_if_fail (input == NULL || G_INPUT_STREAM (input));
368
g_object_ref (input);
370
g_object_unref (self->pv->input);
371
self->pv->input = input;
372
g_object_notify (G_OBJECT (self), "input-stream");
376
_gcr_gnupg_process_get_output_stream (GcrGnupgProcess *self)
378
g_return_val_if_fail (GCR_GNUPG_PROCESS (self), NULL);
379
return self->pv->output;
383
_gcr_gnupg_process_set_output_stream (GcrGnupgProcess *self,
384
GOutputStream *output)
386
g_return_if_fail (GCR_GNUPG_PROCESS (self));
387
g_return_if_fail (output == NULL || G_OUTPUT_STREAM (output));
390
g_object_ref (output);
391
if (self->pv->output)
392
g_object_unref (self->pv->output);
393
self->pv->output = output;
394
g_object_notify (G_OBJECT (self), "output-stream");
398
_gcr_gnupg_process_get_attribute_stream (GcrGnupgProcess *self)
400
g_return_val_if_fail (GCR_GNUPG_PROCESS (self), NULL);
401
return self->pv->attributes;
405
_gcr_gnupg_process_set_attribute_stream (GcrGnupgProcess *self,
406
GOutputStream *output)
408
g_return_if_fail (GCR_GNUPG_PROCESS (self));
409
g_return_if_fail (output == NULL || G_OUTPUT_STREAM (output));
412
g_object_ref (output);
413
if (self->pv->attributes)
414
g_object_unref (self->pv->attributes);
415
self->pv->attributes = output;
416
g_object_notify (G_OBJECT (self), "attribute-stream");
420
run_async_ready_callback (GcrGnupgProcess *self)
422
GAsyncReadyCallback callback;
425
_gcr_debug ("running async callback");
427
/* Remove these before completing */
428
callback = self->pv->async_callback;
429
user_data = self->pv->user_data;
430
self->pv->async_callback = NULL;
431
self->pv->user_data = NULL;
433
if (callback != NULL)
434
(callback) (G_OBJECT (self), G_ASYNC_RESULT (self), user_data);
438
on_run_async_ready_callback_later (gpointer user_data)
440
run_async_ready_callback (GCR_GNUPG_PROCESS (user_data));
441
return FALSE; /* Don't run this callback again */
445
run_async_ready_callback_later (GcrGnupgProcess *self)
447
_gcr_debug ("running async callback later");
448
g_idle_add_full (G_PRIORITY_DEFAULT, on_run_async_ready_callback_later,
449
g_object_ref (self), g_object_unref);
453
complete_run_process (GcrGnupgProcess *self)
455
g_return_if_fail (self->pv->running);
456
g_return_if_fail (!self->pv->complete);
458
self->pv->running = FALSE;
459
self->pv->complete = TRUE;
461
if (self->pv->error == NULL) {
462
_gcr_debug ("completed process");
464
_gcr_debug ("completed process with error: %s",
465
self->pv->error->message);
470
complete_source_is_done (GnupgSource *gnupg_source)
472
GcrGnupgProcess *self = gnupg_source->process;
474
_gcr_debug ("all fds closed and process exited, completing");
476
g_assert (gnupg_source->child_sig == 0);
478
if (gnupg_source->cancel_sig) {
479
g_signal_handler_disconnect (gnupg_source->cancellable, gnupg_source->cancel_sig);
480
gnupg_source->cancel_sig = 0;
483
g_clear_object (&gnupg_source->cancellable);
485
complete_run_process (self);
486
run_async_ready_callback (self);
488
/* All done, the source can go away now */
489
g_source_unref ((GSource*)gnupg_source);
497
_gcr_debug ("closing fd: %d", *fd);
504
close_poll (GSource *source, GPollFD *poll)
506
g_source_remove_poll (source, poll);
507
close_fd (&poll->fd);
512
unused_callback (gpointer data)
515
g_assert_not_reached ();
520
on_gnupg_source_prepare (GSource *source, gint *timeout_)
522
GnupgSource *gnupg_source = (GnupgSource*)source;
525
for (i = 0; i < NUM_FDS; ++i) {
526
if (gnupg_source->polls[i].fd >= 0)
530
/* If none of the FDs are valid, then process immediately */
535
on_gnupg_source_check (GSource *source)
537
GnupgSource *gnupg_source = (GnupgSource*)source;
540
for (i = 0; i < NUM_FDS; ++i) {
541
if (gnupg_source->polls[i].fd >= 0 && gnupg_source->polls[i].revents != 0)
548
on_gnupg_source_finalize (GSource *source)
550
GnupgSource *gnupg_source = (GnupgSource*)source;
553
g_assert (gnupg_source->cancellable == NULL);
554
g_assert (gnupg_source->cancel_sig == 0);
556
for (i = 0; i < NUM_FDS; ++i)
557
close_fd (&gnupg_source->polls[i].fd);
559
g_object_unref (gnupg_source->process);
560
if (gnupg_source->input_buf)
561
g_byte_array_free (gnupg_source->input_buf, TRUE);
562
g_string_free (gnupg_source->error_buf, TRUE);
563
g_string_free (gnupg_source->status_buf, TRUE);
565
g_assert (!gnupg_source->child_pid);
566
g_assert (!gnupg_source->child_sig);
570
read_output (int fd, GByteArray *buffer)
575
g_return_val_if_fail (fd >= 0, FALSE);
578
result = read (fd, block, sizeof (block));
580
if (errno == EINTR || errno == EAGAIN)
584
g_byte_array_append (buffer, block, result);
586
} while (result == sizeof (block));
592
write_input (int fd, GByteArray *buffer)
596
g_return_val_if_fail (fd >= 0, FALSE);
599
result = write (fd, buffer->data, buffer->len);
601
if (errno == EINTR || errno == EAGAIN)
605
g_byte_array_remove_range (buffer, 0, result);
612
emit_status_for_each_line (const gchar *line, gpointer user_data)
616
if (g_str_has_prefix (line, "[GNUPG:] ")) {
617
_gcr_debug ("received status line: %s", line);
620
g_message ("gnupg status record was not prefixed appropriately: %s", line);
624
record = _gcr_record_parse_spaces (line, -1);
626
g_message ("couldn't parse status record: %s", line);
630
g_signal_emit (GCR_GNUPG_PROCESS (user_data), signals[STATUS_RECORD], 0, record);
631
_gcr_record_free (record);
635
emit_error_for_each_line (const gchar *line, gpointer user_data)
637
_gcr_debug ("received error line: %s", line);
638
g_signal_emit (GCR_GNUPG_PROCESS (user_data), signals[ERROR_LINE], 0, line);
642
on_gnupg_source_input (GcrGnupgProcess *self,
643
GnupgSource *gnupg_source,
648
if (gnupg_source->input_buf == NULL ||
649
gnupg_source->input_buf->len == 0) {
650
if (self->pv->input == NULL)
652
if (!gnupg_source->input_buf)
653
gnupg_source->input_buf = g_byte_array_new ();
654
g_byte_array_set_size (gnupg_source->input_buf, 4096);
655
read = g_input_stream_read (self->pv->input,
656
gnupg_source->input_buf->data,
657
gnupg_source->input_buf->len,
658
gnupg_source->cancellable, NULL);
659
g_byte_array_set_size (gnupg_source->input_buf, read < 0 ? 0 : read);
666
if (!write_input (fd, gnupg_source->input_buf)) {
667
g_warning ("couldn't write output data to gnupg process");
675
on_gnupg_source_status (GcrGnupgProcess *self,
676
GnupgSource *gnupg_source,
679
GByteArray *buffer = g_byte_array_new ();
680
gboolean result = TRUE;
682
if (!read_output (fd, buffer)) {
683
g_warning ("couldn't read status data from gnupg process");
686
g_string_append_len (gnupg_source->status_buf, (gchar*)buffer->data, buffer->len);
687
_gcr_util_parse_lines (gnupg_source->status_buf, buffer->len == 0,
688
emit_status_for_each_line, self);
691
g_byte_array_unref (buffer);
696
on_gnupg_source_attribute (GcrGnupgProcess *self,
697
GnupgSource *gnupg_source,
700
GByteArray *buffer = g_byte_array_new ();
701
gboolean result = TRUE;
703
if (!read_output (fd, buffer)) {
704
g_warning ("couldn't read attribute data from gnupg process");
706
} else if (buffer->len > 0) {
707
_gcr_debug ("received %d bytes of attribute data", (gint)buffer->len);
708
if (self->pv->attributes != NULL)
709
g_output_stream_write_all (self->pv->attributes, buffer->data,
711
gnupg_source->cancellable, NULL);
714
g_byte_array_unref (buffer);
719
on_gnupg_source_output (GcrGnupgProcess *self,
720
GnupgSource *gnupg_source,
723
GByteArray *buffer = g_byte_array_new ();
724
gboolean result = TRUE;
726
if (!read_output (fd, buffer)) {
727
g_warning ("couldn't read output data from gnupg process");
729
} else if (buffer->len > 0) {
730
_gcr_debug ("received %d bytes of output data", (gint)buffer->len);
731
if (self->pv->output != NULL)
732
g_output_stream_write_all (self->pv->output, buffer->data, buffer->len,
733
NULL, gnupg_source->cancellable, NULL);
736
g_byte_array_unref (buffer);
741
on_gnupg_source_error (GcrGnupgProcess *self,
742
GnupgSource *gnupg_source,
746
GByteArray *buffer = g_byte_array_new ();
747
gboolean result = TRUE;
749
if (!read_output (fd, buffer)) {
750
g_warning ("couldn't read error data from gnupg process");
753
g_string_append_len (gnupg_source->error_buf, (gchar*)buffer->data, buffer->len);
754
_gcr_util_parse_lines (gnupg_source->error_buf, last,
755
emit_error_for_each_line, gnupg_source->process);
758
g_byte_array_unref (buffer);
763
on_gnupg_source_dispatch (GSource *source, GSourceFunc unused, gpointer user_data)
765
GnupgSource *gnupg_source = (GnupgSource*)source;
766
GcrGnupgProcess *self = gnupg_source->process;
770
/* Standard input, no support yet */
771
poll = &gnupg_source->polls[FD_INPUT];
773
if (poll->revents & G_IO_OUT)
774
if (!on_gnupg_source_input (self, gnupg_source, poll->fd))
775
poll->revents |= G_IO_HUP;
776
if (poll->revents & G_IO_HUP)
777
close_poll (source, poll);
782
poll = &gnupg_source->polls[FD_STATUS];
784
if (poll->revents & G_IO_IN)
785
if (!on_gnupg_source_status (self, gnupg_source, poll->fd))
786
poll->revents |= G_IO_HUP;
787
if (poll->revents & G_IO_HUP)
788
close_poll (source, poll);
792
/* Attribute output */
793
poll = &gnupg_source->polls[FD_ATTRIBUTE];
795
if (poll->revents & G_IO_IN)
796
if (!on_gnupg_source_attribute (self, gnupg_source, poll->fd))
797
poll->revents |= G_IO_HUP;
798
if (poll->revents & G_IO_HUP)
799
close_poll (source, poll);
803
/* Standard output */
804
poll = &gnupg_source->polls[FD_OUTPUT];
806
if (poll->revents & G_IO_IN)
807
if (!on_gnupg_source_output (self, gnupg_source, poll->fd))
808
poll->revents |= G_IO_HUP;
809
if (poll->revents & G_IO_HUP)
810
close_poll (source, poll);
815
poll = &gnupg_source->polls[FD_ERROR];
817
if (poll->revents & G_IO_IN)
818
if (!on_gnupg_source_error (self, gnupg_source, poll->fd,
819
(poll->revents & G_IO_HUP) ? TRUE : FALSE))
820
poll->revents |= G_IO_HUP;
821
if (poll->revents & G_IO_HUP)
822
close_poll (source, poll);
826
for (i = 0; i < NUM_FDS; ++i) {
827
if (gnupg_source->polls[i].fd >= 0)
831
/* Because we return below */
832
self->pv->source_sig = 0;
834
if (!gnupg_source->child_pid)
835
complete_source_is_done (gnupg_source);
837
return FALSE; /* Disconnect this source */
840
static GSourceFuncs gnupg_source_funcs = {
841
on_gnupg_source_prepare,
842
on_gnupg_source_check,
843
on_gnupg_source_dispatch,
844
on_gnupg_source_finalize,
848
on_gnupg_process_child_exited (GPid pid, gint status, gpointer user_data)
850
GnupgSource *gnupg_source = user_data;
851
GcrGnupgProcess *self = gnupg_source->process;
852
GError *error = NULL;
856
_gcr_debug ("process exited: %d", (int)pid);
858
g_spawn_close_pid (gnupg_source->child_pid);
859
gnupg_source->child_pid = 0;
860
gnupg_source->child_sig = 0;
862
if (WIFEXITED (status)) {
863
code = WEXITSTATUS (status);
865
error = g_error_new (G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
866
_("Gnupg process exited with code: %d"), code);
868
} else if (WIFSIGNALED (status)) {
869
code = WTERMSIG (status);
870
/* Ignore cases where we've signaled the process because we were cancelled */
871
if (!g_error_matches (self->pv->error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
872
error = g_error_new (G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
873
_("Gnupg process was terminated with signal: %d"), code);
876
/* Take this as the async result error */
877
if (error && !self->pv->error) {
878
_gcr_debug ("%s", error->message);
879
self->pv->error = error;
881
/* Already have an error, just print out message */
883
g_warning ("%s", error->message);
884
g_error_free (error);
887
for (i = 0; i < NUM_FDS; ++i) {
888
if (gnupg_source->polls[i].fd >= 0)
892
complete_source_is_done (gnupg_source);
896
on_gnupg_process_child_setup (gpointer user_data)
898
int *child_fds = user_data;
903
* Clear close-on-exec flag for these file descriptors, so that
904
* gnupg can write to them
907
for (i = 0; i < NUM_FDS; i++) {
908
if (child_fds[i] >= 0) {
909
val = fcntl (child_fds[i], F_GETFD);
910
fcntl (child_fds[i], F_SETFD, val & ~FD_CLOEXEC);
916
on_cancellable_cancelled (GCancellable *cancellable, gpointer user_data)
918
GnupgSource *gnupg_source = user_data;
920
g_assert (gnupg_source->process);
922
_gcr_debug ("process cancelled");
924
/* Set an error, which is respected when this actually completes. */
925
if (gnupg_source->process->pv->error == NULL)
926
gnupg_source->process->pv->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED,
927
_("The operation was cancelled"));
929
/* Try and kill the child process */
930
if (gnupg_source->child_pid) {
931
_gcr_debug ("sending term signal to process: %d",
932
(int)gnupg_source->child_pid);
933
kill (gnupg_source->child_pid, SIGTERM);
938
* _gcr_gnupg_process_run_async:
940
* @argv: (array zero-terminated=1): The arguments for the process, not including executable, terminated with %NULL.
941
* @envp: (allow-none) (array zero-terminated=1): The environment for new process, terminated with %NULL.
942
* @flags: Flags for starting the process.
943
* @cancellable: (allow-none): Cancellation object
944
* @callback: Will be called when operation completes.
945
* @user_data: (closure): Data passed to callback.
947
* Run the gpg process. Only one 'run' operation can run per GcrGnupgProcess
948
* object. The GcrGnupgProcess:output_data and GcrGnupgProcess:error_line
949
* signals will be emitted when data is received from the gpg process.
951
* Unless the %GCR_GNUPG_PROCESS_RESPECT_LOCALE flag is specified, the process
952
* will be run in the 'C' locale. If the %GCR_GNUPG_PROCESS_WITH_STATUS or
953
* %GCR_GNUPG_PROCESS_WITH_ATTRIBUTES flags are set, then the gpg process
954
* will be status and attribute output respectively. The
955
* GcrGnupgProcess:status_record and GcrGnupgProcess:attribute_data signals
956
* will provide this data.
959
_gcr_gnupg_process_run_async (GcrGnupgProcess *self, const gchar **argv, const gchar **envp,
960
GcrGnupgProcessFlags flags, GCancellable *cancellable,
961
GAsyncReadyCallback callback, gpointer user_data)
963
GError *error = NULL;
966
int child_fds[NUM_FDS];
967
int status_fds[2] = { -1, -1 };
968
int attribute_fds[2] = { -1, -1 };
972
GnupgSource *gnupg_source;
977
g_return_if_fail (GCR_IS_GNUPG_PROCESS (self));
978
g_return_if_fail (argv);
979
g_return_if_fail (callback);
980
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
982
g_return_if_fail (self->pv->running == FALSE);
983
g_return_if_fail (self->pv->complete == FALSE);
984
g_return_if_fail (self->pv->executable);
986
self->pv->async_callback = callback;
987
self->pv->user_data = user_data;
989
for (i = 0; i < NUM_FDS; i++)
992
/* The command needs to be updated with these status and attribute fds */
993
args = g_ptr_array_new_with_free_func (g_free);
994
g_ptr_array_add (args, g_strdup (self->pv->executable));
996
/* Spawn/child will close all other attributes, besides thesthose in child_fds */
997
child_fds[FD_INPUT] = 0;
998
child_fds[FD_OUTPUT] = 1;
999
child_fds[FD_ERROR] = 2;
1001
if (flags & GCR_GNUPG_PROCESS_WITH_STATUS) {
1002
if (pipe (status_fds) < 0)
1003
g_return_if_reached ();
1004
child_fds[FD_STATUS] = status_fds[1];
1005
g_ptr_array_add (args, g_strdup ("--status-fd"));
1006
g_ptr_array_add (args, g_strdup_printf ("%d", child_fds[FD_STATUS]));
1008
if (flags & GCR_GNUPG_PROCESS_WITH_ATTRIBUTES) {
1009
if (pipe (attribute_fds) < 0)
1010
g_return_if_reached ();
1011
child_fds[FD_ATTRIBUTE] = attribute_fds[1];
1012
g_ptr_array_add (args, g_strdup ("--attribute-fd"));
1013
g_ptr_array_add (args, g_strdup_printf ("%d", child_fds[FD_ATTRIBUTE]));
1016
if (self->pv->directory) {
1017
g_ptr_array_add (args, g_strdup ("--homedir"));
1018
g_ptr_array_add (args, g_strdup (self->pv->directory));
1021
/* All the remaining arguments */
1022
for (i = 0; argv[i] != NULL; i++)
1023
g_ptr_array_add (args, g_strdup (argv[i]));
1024
g_ptr_array_add (args, NULL);
1026
envs = g_ptr_array_new ();
1027
for (i = 0; envp && envp[i] != NULL; i++) {
1028
if (flags & GCR_GNUPG_PROCESS_RESPECT_LOCALE ||
1029
!g_str_has_prefix (envp[i], "LOCALE="))
1030
g_ptr_array_add (envs, (gpointer)envp[i]);
1032
if (!(flags & GCR_GNUPG_PROCESS_RESPECT_LOCALE))
1033
g_ptr_array_add (envs, (gpointer)"LOCALE=C");
1034
g_ptr_array_add (envs, NULL);
1036
if (_gcr_debugging) {
1037
gchar *command = g_strjoinv (" ", (gchar**)args->pdata);
1038
gchar *environ = g_strjoinv (", ", (gchar**)envs->pdata);
1039
_gcr_debug ("running command: %s", command);
1040
_gcr_debug ("process environment: %s", environ);
1045
g_spawn_async_with_pipes (self->pv->directory, (gchar**)args->pdata,
1046
(gchar**)envs->pdata, G_SPAWN_DO_NOT_REAP_CHILD,
1047
on_gnupg_process_child_setup, child_fds,
1048
&pid, &input_fd, &output_fd, &error_fd, &error);
1050
g_ptr_array_free (args, TRUE);
1051
g_ptr_array_free (envs, TRUE);
1053
/* Close 'wrong' ends of extra file descriptors */
1054
close_fd (&(status_fds[1]));
1055
close_fd (&(attribute_fds[1]));
1057
self->pv->complete = FALSE;
1058
self->pv->running = TRUE;
1061
close_fd (&(status_fds[0]));
1062
close_fd (&(attribute_fds[0]));
1063
g_assert (!self->pv->error);
1064
self->pv->error = error;
1065
complete_run_process (self);
1066
run_async_ready_callback_later (self);
1070
_gcr_debug ("process started: %d", (int)pid);
1072
source = g_source_new (&gnupg_source_funcs, sizeof (GnupgSource));
1074
/* Initialize the source */
1075
gnupg_source = (GnupgSource*)source;
1076
for (i = 0; i < NUM_FDS; i++)
1077
gnupg_source->polls[i].fd = -1;
1078
gnupg_source->error_buf = g_string_sized_new (128);
1079
gnupg_source->status_buf = g_string_sized_new (128);
1080
gnupg_source->process = g_object_ref (self);
1081
gnupg_source->child_pid = pid;
1083
gnupg_source->polls[FD_INPUT].fd = input_fd;
1084
if (input_fd >= 0) {
1085
gnupg_source->polls[FD_INPUT].events = G_IO_HUP | G_IO_OUT;
1086
g_source_add_poll (source, &gnupg_source->polls[FD_INPUT]);
1088
gnupg_source->polls[FD_OUTPUT].fd = output_fd;
1089
if (output_fd >= 0) {
1090
gnupg_source->polls[FD_OUTPUT].events = G_IO_HUP | G_IO_IN;
1091
g_source_add_poll (source, &gnupg_source->polls[FD_OUTPUT]);
1093
gnupg_source->polls[FD_ERROR].fd = error_fd;
1094
if (error_fd >= 0) {
1095
gnupg_source->polls[FD_ERROR].events = G_IO_HUP | G_IO_IN;
1096
g_source_add_poll (source, &gnupg_source->polls[FD_ERROR]);
1098
gnupg_source->polls[FD_STATUS].fd = status_fds[0];
1099
if (status_fds[0] >= 0) {
1100
gnupg_source->polls[FD_STATUS].events = G_IO_HUP | G_IO_IN;
1101
g_source_add_poll (source, &gnupg_source->polls[FD_STATUS]);
1103
gnupg_source->polls[FD_ATTRIBUTE].fd = attribute_fds[0];
1104
if (attribute_fds[0] >= 0) {
1105
gnupg_source->polls[FD_ATTRIBUTE].events = G_IO_HUP | G_IO_IN;
1106
g_source_add_poll (source, &gnupg_source->polls[FD_ATTRIBUTE]);
1110
gnupg_source->cancellable = g_object_ref (cancellable);
1111
gnupg_source->cancel_sig = g_cancellable_connect (cancellable,
1112
G_CALLBACK (on_cancellable_cancelled),
1113
g_source_ref (source),
1114
(GDestroyNotify)g_source_unref);
1117
g_assert (self->pv->source_sig == 0);
1118
g_source_set_callback (source, unused_callback, NULL, NULL);
1119
self->pv->source_sig = g_source_attach (source, g_main_context_default ());
1121
/* This assumes the outstanding reference to source */
1122
g_assert (gnupg_source->child_sig == 0);
1123
gnupg_source->child_sig = g_child_watch_add_full (G_PRIORITY_DEFAULT, pid,
1124
on_gnupg_process_child_exited,
1125
g_source_ref (source),
1126
(GDestroyNotify)g_source_unref);
1128
/* source is unreffed in complete_if_source_is_done() */
1132
* _gcr_gnupg_process_run_finish:
1133
* @self: The process
1134
* @result: The result passed to the callback
1135
* @error: Location to raise an error on failure.
1137
* Get the result of running a gnupg process.
1139
* Return value: Whether the Gnupg process was run or not.
1142
_gcr_gnupg_process_run_finish (GcrGnupgProcess *self, GAsyncResult *result,
1145
g_return_val_if_fail (GCR_IS_GNUPG_PROCESS (self), FALSE);
1146
g_return_val_if_fail (!error || !*error, FALSE);
1147
g_return_val_if_fail (G_ASYNC_RESULT (self) == result, FALSE);
1148
g_return_val_if_fail (self->pv->complete, FALSE);
1150
/* This allows the process to run again... */
1151
self->pv->complete = FALSE;
1153
g_assert (!self->pv->running);
1154
g_assert (!self->pv->async_callback);
1155
g_assert (!self->pv->user_data);
1157
if (self->pv->error) {
1158
g_propagate_error (error, self->pv->error);
1159
self->pv->error = NULL;