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.
72 static gint signals[NUM_SIGNALS] = { 0, };
74 typedef struct _GnupgSource {
76 GPollFD polls[NUM_FDS]; /* The various fd's we're listening to */
78 GcrGnupgProcess *process; /* Pointer back to the process object */
86 GCancellable *cancellable;
90 struct _GcrGnupgProcessPrivate {
100 GAsyncReadyCallback async_callback;
104 /* Forward declarations */
105 static void _gcr_gnupg_process_init_async (GAsyncResultIface *iface);
107 G_DEFINE_TYPE_WITH_CODE (GcrGnupgProcess, _gcr_gnupg_process, G_TYPE_OBJECT,
108 G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, _gcr_gnupg_process_init_async));
111 _gcr_gnupg_process_init (GcrGnupgProcess *self)
113 self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_GNUPG_PROCESS,
114 GcrGnupgProcessPrivate);
118 _gcr_gnupg_process_constructed (GObject *obj)
120 GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
122 if (G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->constructed)
123 G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->constructed (obj);
125 if (!self->pv->executable)
126 self->pv->executable = g_strdup (GPG_EXECUTABLE);
130 _gcr_gnupg_process_get_property (GObject *obj, guint prop_id, GValue *value,
133 GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
137 g_value_set_string (value, self->pv->directory);
139 case PROP_EXECUTABLE:
140 g_value_set_string (value, self->pv->executable);
143 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
149 _gcr_gnupg_process_set_property (GObject *obj, guint prop_id, const GValue *value,
152 GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
156 g_return_if_fail (!self->pv->directory);
157 self->pv->directory = g_value_dup_string (value);
159 case PROP_EXECUTABLE:
160 g_return_if_fail (!self->pv->executable);
161 self->pv->executable = g_value_dup_string (value);
164 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
170 _gcr_gnupg_process_finalize (GObject *obj)
172 GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
174 g_assert (!self->pv->running);
175 g_free (self->pv->directory);
176 g_free (self->pv->executable);
177 g_clear_error (&self->pv->error);
179 G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->finalize (obj);
183 _gcr_gnupg_process_class_init (GcrGnupgProcessClass *klass)
185 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
187 gobject_class->constructed = _gcr_gnupg_process_constructed;
188 gobject_class->get_property = _gcr_gnupg_process_get_property;
189 gobject_class->set_property = _gcr_gnupg_process_set_property;
190 gobject_class->finalize = _gcr_gnupg_process_finalize;
193 * GcrGnupgProcess:directory:
195 * Directory to run as gnupg home directory, or %NULL for default
196 * ~/.gnupg/ directory.
198 g_object_class_install_property (gobject_class, PROP_DIRECTORY,
199 g_param_spec_string ("directory", "Directory", "Gnupg Directory",
200 NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
203 * GcrGnupgProcess:executable:
205 * Path to the gnupg executable, or %NULL for default.
207 g_object_class_install_property (gobject_class, PROP_EXECUTABLE,
208 g_param_spec_string ("executable", "Executable", "Gnupg Executable",
209 GPG_EXECUTABLE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
212 * GcrGnupgProcess::output-data:
213 * @data: a #GByteArray of output data.
215 * Signal emitted when normal output data is available from the gnupg
216 * process. The data does not necessarily come on line boundaries, and
217 * won't be null-terminated.
219 signals[OUTPUT_DATA] = g_signal_new ("output-data", GCR_TYPE_GNUPG_PROCESS,
220 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrGnupgProcessClass, output_data),
221 NULL, NULL, _gcr_marshal_VOID__BOXED,
222 G_TYPE_NONE, 1, G_TYPE_BYTE_ARRAY);
225 * GcrGnupgProcess::error-line:
226 * @line: a line of error output.
228 * Signal emitted when a line of error output is available from the
231 signals[ERROR_LINE] = g_signal_new ("error-line", GCR_TYPE_GNUPG_PROCESS,
232 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrGnupgProcessClass, error_line),
233 NULL, NULL, _gcr_marshal_VOID__STRING,
234 G_TYPE_NONE, 1, G_TYPE_STRING);
237 * GcrGnupgProcess::status-record:
238 * @record: a status record.
240 * Signal emitted when a status record is available from the gnupg process.
242 signals[STATUS_RECORD] = g_signal_new ("status-record", GCR_TYPE_GNUPG_PROCESS,
243 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrGnupgProcessClass, status_record),
244 NULL, NULL, _gcr_marshal_VOID__BOXED,
245 G_TYPE_NONE, 1, GCR_TYPE_RECORD);
248 * GcrGnupgProcess::attribute-data:
249 * @data: a #GByteArray of attribute data.
251 * Signal emitted when attribute data is available from the gnupg
254 signals[ATTRIBUTE_DATA] = g_signal_new ("attribute-data", GCR_TYPE_GNUPG_PROCESS,
255 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrGnupgProcessClass, attribute_data),
256 NULL, NULL, _gcr_marshal_VOID__BOXED,
257 G_TYPE_NONE, 1, G_TYPE_BYTE_ARRAY);
259 g_type_class_add_private (gobject_class, sizeof (GcrGnupgProcessPrivate));
263 _gcr_gnupg_process_get_user_data (GAsyncResult *result)
265 g_return_val_if_fail (GCR_IS_GNUPG_PROCESS (result), NULL);
266 return GCR_GNUPG_PROCESS (result)->pv->user_data;
270 _gcr_gnupg_process_get_source_object (GAsyncResult *result)
272 g_return_val_if_fail (GCR_IS_GNUPG_PROCESS (result), NULL);
273 return G_OBJECT (result);
277 _gcr_gnupg_process_init_async (GAsyncResultIface *iface)
279 iface->get_source_object = _gcr_gnupg_process_get_source_object;
280 iface->get_user_data = _gcr_gnupg_process_get_user_data;
284 * _gcr_gnupg_process_new:
285 * @directory: (allow-none): The gnupg home directory
286 * @executable: (allow-none): The gpg executable
288 * Create a new GcrGnupgProcess.
290 * The gnupg home directory is where the keyring files live. If directory is
291 * %NULL then the default gnupg home directory is used.
293 * The executable will default to the compiled in path if a %NULL executable
296 * Returns: (transfer full): A newly allocated process.
299 _gcr_gnupg_process_new (const gchar *directory, const gchar *executable)
301 return g_object_new (GCR_TYPE_GNUPG_PROCESS,
302 "directory", directory,
303 "executable", executable,
308 run_async_ready_callback (GcrGnupgProcess *self)
310 GAsyncReadyCallback callback;
313 _gcr_debug ("running async callback");
315 /* Remove these before completing */
316 callback = self->pv->async_callback;
317 user_data = self->pv->user_data;
318 self->pv->async_callback = NULL;
319 self->pv->user_data = NULL;
321 if (callback != NULL)
322 (callback) (G_OBJECT (self), G_ASYNC_RESULT (self), user_data);
326 on_run_async_ready_callback_later (gpointer user_data)
328 run_async_ready_callback (GCR_GNUPG_PROCESS (user_data));
329 return FALSE; /* Don't run this callback again */
333 run_async_ready_callback_later (GcrGnupgProcess *self)
335 _gcr_debug ("running async callback later");
336 g_idle_add_full (G_PRIORITY_DEFAULT, on_run_async_ready_callback_later,
337 g_object_ref (self), g_object_unref);
341 complete_run_process (GcrGnupgProcess *self)
343 g_return_if_fail (self->pv->running);
344 g_return_if_fail (!self->pv->complete);
346 self->pv->running = FALSE;
347 self->pv->complete = TRUE;
349 if (self->pv->source_sig) {
350 g_source_remove (self->pv->source_sig);
351 self->pv->source_sig = 0;
354 if (self->pv->error == NULL) {
355 _gcr_debug ("completed process");
357 _gcr_debug ("completed process with error: %s",
358 self->pv->error->message);
363 complete_if_source_is_done (GnupgSource *gnupg_source)
367 for (i = 0; i < NUM_FDS; ++i) {
368 if (gnupg_source->polls[i].fd >= 0)
372 if (gnupg_source->child_pid)
375 _gcr_debug ("all fds closed and process exited, completing");
377 complete_run_process (gnupg_source->process);
378 run_async_ready_callback (gnupg_source->process);
380 /* All done, the source can go away now */
381 g_source_unref ((GSource*)gnupg_source);
390 _gcr_debug ("closing fd: %d", *fd);
397 close_poll (GSource *source, GPollFD *poll)
399 g_source_remove_poll (source, poll);
400 close_fd (&poll->fd);
405 unused_callback (gpointer data)
408 g_assert_not_reached ();
413 on_gnupg_source_prepare (GSource *source, gint *timeout_)
415 GnupgSource *gnupg_source = (GnupgSource*)source;
418 for (i = 0; i < NUM_FDS; ++i) {
419 if (gnupg_source->polls[i].fd >= 0)
423 /* If none of the FDs are valid, then process immediately */
428 on_gnupg_source_check (GSource *source)
430 GnupgSource *gnupg_source = (GnupgSource*)source;
433 for (i = 0; i < NUM_FDS; ++i) {
434 if (gnupg_source->polls[i].fd >= 0 && gnupg_source->polls[i].revents != 0)
441 on_gnupg_source_finalize (GSource *source)
443 GnupgSource *gnupg_source = (GnupgSource*)source;
446 if (gnupg_source->cancel_sig)
447 g_signal_handler_disconnect (gnupg_source->cancellable, gnupg_source->cancel_sig);
448 if (gnupg_source->cancellable)
449 g_object_unref (gnupg_source->cancellable);
451 for (i = 0; i < NUM_FDS; ++i)
452 close_fd (&gnupg_source->polls[i].fd);
454 g_object_unref (gnupg_source->process);
455 g_string_free (gnupg_source->error_buf, TRUE);
456 g_string_free (gnupg_source->status_buf, TRUE);
458 g_assert (!gnupg_source->child_pid);
459 g_assert (!gnupg_source->child_sig);
463 read_output (int fd, GByteArray *buffer)
468 g_return_val_if_fail (fd >= 0, FALSE);
471 result = read (fd, block, sizeof (block));
473 if (errno == EINTR || errno == EAGAIN)
477 g_byte_array_append (buffer, block, result);
479 } while (result == sizeof (block));
485 emit_status_for_each_line (const gchar *line, gpointer user_data)
489 if (g_str_has_prefix (line, "[GNUPG:] ")) {
490 _gcr_debug ("received status line: %s", line);
493 g_message ("gnupg status record was not prefixed appropriately: %s", line);
497 record = _gcr_record_parse_spaces (line, -1);
499 g_message ("couldn't parse status record: %s", line);
503 g_signal_emit (GCR_GNUPG_PROCESS (user_data), signals[STATUS_RECORD], 0, record);
504 _gcr_record_free (record);
508 emit_error_for_each_line (const gchar *line, gpointer user_data)
510 _gcr_debug ("received error line: %s", line);
511 g_signal_emit (GCR_GNUPG_PROCESS (user_data), signals[ERROR_LINE], 0, line);
515 on_gnupg_source_dispatch (GSource *source, GSourceFunc unused, gpointer user_data)
517 GnupgSource *gnupg_source = (GnupgSource*)source;
521 /* Standard input, no support yet */
522 poll = &gnupg_source->polls[FD_INPUT];
523 if (poll->fd >= 0 && poll->revents != 0) {
524 close_poll (source, poll);
528 poll = &gnupg_source->polls[FD_STATUS];
530 if (poll->revents & G_IO_IN) {
531 buffer = g_byte_array_new ();
532 if (!read_output (poll->fd, buffer)) {
533 g_warning ("couldn't read status data from gnupg process");
535 g_string_append_len (gnupg_source->status_buf, (gchar*)buffer->data, buffer->len);
536 _gcr_util_parse_lines (gnupg_source->status_buf, buffer->len == 0,
537 emit_status_for_each_line, gnupg_source->process);
539 g_byte_array_unref (buffer);
541 if (poll->revents & G_IO_HUP)
542 close_poll (source, poll);
546 /* Attribute output */
547 poll = &gnupg_source->polls[FD_ATTRIBUTE];
549 if (poll->revents & G_IO_IN) {
550 buffer = g_byte_array_new ();
551 if (!read_output (poll->fd, buffer)) {
552 g_warning ("couldn't read attribute data from gnupg process");
553 } else if (buffer->len > 0) {
554 _gcr_debug ("received %d bytes of attribute data", (gint)buffer->len);
555 g_signal_emit (gnupg_source->process, signals[ATTRIBUTE_DATA], 0, buffer);
557 g_byte_array_unref (buffer);
559 if (poll->revents & G_IO_HUP)
560 close_poll (source, poll);
564 /* Standard output */
565 poll = &gnupg_source->polls[FD_OUTPUT];
567 if (poll->revents & G_IO_IN) {
568 buffer = g_byte_array_new ();
569 if (!read_output (poll->fd, buffer)) {
570 g_warning ("couldn't read output data from gnupg process");
571 } else if (buffer->len > 0) {
572 _gcr_debug ("received %d bytes of output data", (gint)buffer->len);
573 g_signal_emit (gnupg_source->process, signals[OUTPUT_DATA], 0, buffer);
575 g_byte_array_unref (buffer);
577 if (poll->revents & G_IO_HUP)
578 close_poll (source, poll);
583 poll = &gnupg_source->polls[FD_ERROR];
585 if (poll->revents & G_IO_IN) {
586 buffer = g_byte_array_new ();
587 if (!read_output (poll->fd, buffer)) {
588 g_warning ("couldn't read error data from gnupg process");
590 g_string_append_len (gnupg_source->error_buf, (gchar*)buffer->data, buffer->len);
591 _gcr_util_parse_lines (gnupg_source->error_buf, (poll->revents & G_IO_HUP) ? TRUE : FALSE,
592 emit_error_for_each_line, gnupg_source->process);
594 g_byte_array_unref (buffer);
596 if (poll->revents & G_IO_HUP)
597 close_poll (source, poll);
601 if (complete_if_source_is_done (gnupg_source))
602 return FALSE; /* Disconnect this source */
607 static GSourceFuncs gnupg_source_funcs = {
608 on_gnupg_source_prepare,
609 on_gnupg_source_check,
610 on_gnupg_source_dispatch,
611 on_gnupg_source_finalize,
615 on_gnupg_process_child_exited (GPid pid, gint status, gpointer user_data)
617 GnupgSource *gnupg_source = user_data;
618 GcrGnupgProcess *self = gnupg_source->process;
619 GError *error = NULL;
622 _gcr_debug ("process exited: %d", (int)pid);
624 g_spawn_close_pid (gnupg_source->child_pid);
625 gnupg_source->child_pid = 0;
626 gnupg_source->child_sig = 0;
628 if (WIFEXITED (status)) {
629 code = WEXITSTATUS (status);
631 error = g_error_new (G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
632 _("Gnupg process exited with code: %d"), code);
634 } else if (WIFSIGNALED (status)) {
635 code = WTERMSIG (status);
636 /* Ignore cases where we've signaled the process because we were cancelled */
637 if (!g_error_matches (self->pv->error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
638 error = g_error_new (G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
639 _("Gnupg process was terminated with signal: %d"), code);
642 /* Take this as the async result error */
643 if (error && !self->pv->error) {
644 _gcr_debug ("%s", error->message);
645 self->pv->error = error;
647 /* Already have an error, just print out message */
649 g_warning ("%s", error->message);
650 g_error_free (error);
653 complete_if_source_is_done (gnupg_source);
657 on_gnupg_process_child_setup (gpointer user_data)
659 int *child_fds = user_data;
664 * Clear close-on-exec flag for these file descriptors, so that
665 * gnupg can write to them
668 for (i = 0; i < NUM_FDS; i++) {
669 if (child_fds[i] >= 0) {
670 val = fcntl (child_fds[i], F_GETFD);
671 fcntl (child_fds[i], F_SETFD, val & ~FD_CLOEXEC);
677 on_cancellable_cancelled (GCancellable *cancellable, gpointer user_data)
679 GnupgSource *gnupg_source = user_data;
681 g_assert (gnupg_source->process);
683 _gcr_debug ("process cancelled");
685 /* Try and kill the child process */
686 if (gnupg_source->child_pid) {
687 _gcr_debug ("sending term signal to process: %d",
688 (int)gnupg_source->child_pid);
689 kill (gnupg_source->child_pid, SIGTERM);
692 /* Set an error, which is respected when this actually completes. */
693 if (gnupg_source->process->pv->error == NULL)
694 gnupg_source->process->pv->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED,
695 _("The operation was cancelled"));
697 complete_if_source_is_done (gnupg_source);
701 * _gcr_gnupg_process_run_async:
703 * @argv: (array zero-terminated=1): The arguments for the process, not including executable, terminated with %NULL.
704 * @envp: (allow-none) (array zero-terminated=1): The environment for new process, terminated with %NULL.
705 * @flags: Flags for starting the process.
706 * @cancellable: (allow-none): Cancellation object
707 * @callback: Will be called when operation completes.
708 * @user_data: (closure): Data passed to callback.
710 * Run the gpg process. Only one 'run' operation can run per GcrGnupgProcess
711 * object. The GcrGnupgProcess:output_data and GcrGnupgProcess:error_line
712 * signals will be emitted when data is received from the gpg process.
714 * Unless the %GCR_GNUPG_PROCESS_RESPECT_LOCALE flag is specified, the process
715 * will be run in the 'C' locale. If the %GCR_GNUPG_PROCESS_WITH_STATUS or
716 * %GCR_GNUPG_PROCESS_WITH_ATTRIBUTES flags are set, then the gpg process
717 * will be status and attribute output respectively. The
718 * GcrGnupgProcess:status_record and GcrGnupgProcess:attribute_data signals
719 * will provide this data.
722 _gcr_gnupg_process_run_async (GcrGnupgProcess *self, const gchar **argv, const gchar **envp,
723 GcrGnupgProcessFlags flags, GCancellable *cancellable,
724 GAsyncReadyCallback callback, gpointer user_data)
726 GError *error = NULL;
729 int child_fds[NUM_FDS];
730 int status_fds[2] = { -1, -1 };
731 int attribute_fds[2] = { -1, -1 };
734 GnupgSource *gnupg_source;
739 g_return_if_fail (GCR_IS_GNUPG_PROCESS (self));
740 g_return_if_fail (argv);
741 g_return_if_fail (callback);
742 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
744 g_return_if_fail (self->pv->running == FALSE);
745 g_return_if_fail (self->pv->complete == FALSE);
746 g_return_if_fail (self->pv->executable);
748 self->pv->async_callback = callback;
749 self->pv->user_data = user_data;
751 for (i = 0; i < NUM_FDS; i++)
754 /* The command needs to be updated with these status and attribute fds */
755 args = g_ptr_array_new_with_free_func (g_free);
756 g_ptr_array_add (args, g_strdup (self->pv->executable));
758 /* Spawn/child will close all other attributes, besides thesthose in child_fds */
759 child_fds[FD_OUTPUT] = 1;
760 child_fds[FD_ERROR] = 2;
762 if (flags & GCR_GNUPG_PROCESS_WITH_STATUS) {
763 if (pipe (status_fds) < 0)
764 g_return_if_reached ();
765 child_fds[FD_STATUS] = status_fds[1];
766 g_ptr_array_add (args, g_strdup ("--status-fd"));
767 g_ptr_array_add (args, g_strdup_printf ("%d", child_fds[FD_STATUS]));
769 if (flags & GCR_GNUPG_PROCESS_WITH_ATTRIBUTES) {
770 if (pipe (attribute_fds) < 0)
771 g_return_if_reached ();
772 child_fds[FD_ATTRIBUTE] = attribute_fds[1];
773 g_ptr_array_add (args, g_strdup ("--attribute-fd"));
774 g_ptr_array_add (args, g_strdup_printf ("%d", child_fds[FD_ATTRIBUTE]));
777 if (self->pv->directory) {
778 g_ptr_array_add (args, g_strdup ("--homedir"));
779 g_ptr_array_add (args, g_strdup (self->pv->directory));
782 /* All the remaining arguments */
783 for (i = 0; argv[i] != NULL; i++)
784 g_ptr_array_add (args, g_strdup (argv[i]));
785 g_ptr_array_add (args, NULL);
787 envs = g_ptr_array_new ();
788 for (i = 0; envp && envp[i] != NULL; i++) {
789 if (flags & GCR_GNUPG_PROCESS_RESPECT_LOCALE ||
790 !g_str_has_prefix (envp[i], "LOCALE="))
791 g_ptr_array_add (envs, (gpointer)envp[i]);
793 if (!(flags & GCR_GNUPG_PROCESS_RESPECT_LOCALE))
794 g_ptr_array_add (envs, (gpointer)"LOCALE=C");
795 g_ptr_array_add (envs, NULL);
797 if (_gcr_debugging) {
798 gchar *command = g_strjoinv (" ", (gchar**)args->pdata);
799 gchar *environ = g_strjoinv (", ", (gchar**)envs->pdata);
800 _gcr_debug ("running command: %s", command);
801 _gcr_debug ("process environment: %s", environ);
806 g_spawn_async_with_pipes (self->pv->directory, (gchar**)args->pdata,
807 (gchar**)envs->pdata, G_SPAWN_DO_NOT_REAP_CHILD,
808 on_gnupg_process_child_setup,
809 child_fds, &pid, NULL, &output_fd, &error_fd, &error);
811 g_ptr_array_free (args, TRUE);
812 g_ptr_array_free (envs, TRUE);
814 /* Close 'wrong' ends of extra file descriptors */
815 close_fd (&(status_fds[1]));
816 close_fd (&(attribute_fds[1]));
818 self->pv->complete = FALSE;
819 self->pv->running = TRUE;
822 close_fd (&(status_fds[0]));
823 close_fd (&(attribute_fds[0]));
824 g_assert (!self->pv->error);
825 self->pv->error = error;
826 complete_run_process (self);
827 run_async_ready_callback_later (self);
831 _gcr_debug ("process started: %d", (int)pid);
833 source = g_source_new (&gnupg_source_funcs, sizeof (GnupgSource));
835 /* Initialize the source */
836 gnupg_source = (GnupgSource*)source;
837 for (i = 0; i < NUM_FDS; i++)
838 gnupg_source->polls[i].fd = -1;
839 gnupg_source->error_buf = g_string_sized_new (128);
840 gnupg_source->status_buf = g_string_sized_new (128);
841 gnupg_source->process = g_object_ref (self);
842 gnupg_source->child_pid = pid;
844 gnupg_source->polls[FD_OUTPUT].fd = output_fd;
845 if (output_fd >= 0) {
846 gnupg_source->polls[FD_OUTPUT].events = G_IO_HUP | G_IO_IN;
847 g_source_add_poll (source, &gnupg_source->polls[FD_OUTPUT]);
849 gnupg_source->polls[FD_ERROR].fd = error_fd;
851 gnupg_source->polls[FD_ERROR].events = G_IO_HUP | G_IO_IN;
852 g_source_add_poll (source, &gnupg_source->polls[FD_ERROR]);
854 gnupg_source->polls[FD_STATUS].fd = status_fds[0];
855 if (status_fds[0] >= 0) {
856 gnupg_source->polls[FD_STATUS].events = G_IO_HUP | G_IO_IN;
857 g_source_add_poll (source, &gnupg_source->polls[FD_STATUS]);
859 gnupg_source->polls[FD_ATTRIBUTE].fd = attribute_fds[0];
860 if (attribute_fds[0] >= 0) {
861 gnupg_source->polls[FD_ATTRIBUTE].events = G_IO_HUP | G_IO_IN;
862 g_source_add_poll (source, &gnupg_source->polls[FD_ATTRIBUTE]);
866 gnupg_source->cancellable = g_object_ref (cancellable);
867 gnupg_source->cancel_sig = g_cancellable_connect (cancellable,
868 G_CALLBACK (on_cancellable_cancelled),
869 g_source_ref (source),
870 (GDestroyNotify)g_source_unref);
873 g_assert (!self->pv->source_sig);
874 g_source_set_callback (source, unused_callback, NULL, NULL);
875 self->pv->source_sig = g_source_attach (source, g_main_context_default ());
877 /* This assumes the outstanding reference to source */
878 g_assert (!gnupg_source->child_sig);
879 gnupg_source->child_sig = g_child_watch_add_full (G_PRIORITY_DEFAULT, pid,
880 on_gnupg_process_child_exited,
881 g_source_ref (source),
882 (GDestroyNotify)g_source_unref);
884 /* source is unreffed in complete_if_source_is_done() */
888 * _gcr_gnupg_process_run_finish:
890 * @result: The result passed to the callback
891 * @error: Location to raise an error on failure.
893 * Get the result of running a gnupg process.
895 * Return value: Whether the Gnupg process was run or not.
898 _gcr_gnupg_process_run_finish (GcrGnupgProcess *self, GAsyncResult *result,
901 g_return_val_if_fail (GCR_IS_GNUPG_PROCESS (self), FALSE);
902 g_return_val_if_fail (!error || !*error, FALSE);
903 g_return_val_if_fail (G_ASYNC_RESULT (self) == result, FALSE);
904 g_return_val_if_fail (self->pv->complete, FALSE);
906 /* This allows the process to run again... */
907 self->pv->complete = FALSE;
909 g_assert (!self->pv->running);
910 g_assert (!self->pv->async_callback);
911 g_assert (!self->pv->user_data);
912 g_assert (!self->pv->source_sig);
914 if (self->pv->error) {
915 g_propagate_error (error, self->pv->error);
916 self->pv->error = NULL;