diff options
Diffstat (limited to 'gpgme/rungpg.c')
-rw-r--r-- | gpgme/rungpg.c | 1080 |
1 files changed, 607 insertions, 473 deletions
diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c index 1d6aa2b1..318e99d8 100644 --- a/gpgme/rungpg.c +++ b/gpgme/rungpg.c @@ -54,113 +54,166 @@ struct arg_and_data_s { char arg[1]; /* .. this is used */ }; -struct fd_data_map_s { - GpgmeData data; - int inbound; /* true if this is used for reading from gpg */ - int dup_to; - int fd; /* the fd to use */ - int peer_fd; /* the outher side of the pipe */ +struct fd_data_map_s +{ + GpgmeData data; + int inbound; /* true if this is used for reading from gpg */ + int dup_to; + int fd; /* the fd to use */ + int peer_fd; /* the outher side of the pipe */ + void *tag; }; -struct gpg_object_s { - struct arg_and_data_s *arglist; - struct arg_and_data_s **argtail; - int arg_error; - - struct { - int fd[2]; - size_t bufsize; - char *buffer; - size_t readpos; - int eof; - GpgStatusHandler fnc; - void *fnc_value; - } status; - - /* This is a kludge - see the comment at gpg_colon_line_handler */ - struct { - int fd[2]; - size_t bufsize; - char *buffer; - size_t readpos; - int eof; - GpgColonLineHandler fnc; /* this indicate use of this structrue */ - void *fnc_value; - int simple; - } colon; - - char **argv; - struct fd_data_map_s *fd_data_map; - - int pid; /* we can't use pid_t because we don't use it in Windoze */ - - int running; - - /* stuff needed for pipemode */ - struct { - int used; - int active; - GpgmeData sig; - GpgmeData text; - int stream_started; - } pm; - - /* stuff needed for interactive (command) mode */ - struct { - int used; - int fd; - GpgmeData cb_data; /* hack to get init the above fd later */ - GpgStatusCode code; /* last code */ - char *keyword; /* what has been requested (malloced) */ - GpgCommandHandler fnc; - void *fnc_value; - } cmd; +struct gpg_object_s +{ + struct arg_and_data_s *arglist; + struct arg_and_data_s **argtail; + int arg_error; + + struct + { + int fd[2]; + size_t bufsize; + char *buffer; + size_t readpos; + int eof; + GpgStatusHandler fnc; + void *fnc_value; + void *tag; + } status; + + /* This is a kludge - see the comment at gpg_colon_line_handler */ + struct + { + int fd[2]; + size_t bufsize; + char *buffer; + size_t readpos; + int eof; + GpgColonLineHandler fnc; /* this indicate use of this structrue */ + void *fnc_value; + void *tag; + int simple; + } colon; + + char **argv; + struct fd_data_map_s *fd_data_map; + + int pid; /* we can't use pid_t because we don't use it in Windoze */ + + /* stuff needed for pipemode */ + struct + { + int used; + int active; + GpgmeData sig; + GpgmeData text; + int stream_started; + } pm; + + /* stuff needed for interactive (command) mode */ + struct + { + int used; + int fd; + int idx; /* Index in fd_data_map */ + GpgmeData cb_data; /* hack to get init the above idx later */ + GpgStatusCode code; /* last code */ + char *keyword; /* what has been requested (malloced) */ + GpgCommandHandler fnc; + void *fnc_value; + } cmd; + + struct GpgmeIOCbs io_cbs; }; -static void free_argv ( char **argv ); -static void free_fd_data_map ( struct fd_data_map_s *fd_data_map ); - -static int gpg_status_handler ( void *opaque, int pid, int fd ); -static GpgmeError read_status ( GpgObject gpg ); +static void free_argv (char **argv); +static void free_fd_data_map (struct fd_data_map_s *fd_data_map); -static int gpg_colon_line_handler ( void *opaque, int pid, int fd ); -static GpgmeError read_colon_line ( GpgObject gpg ); +static void gpg_status_handler (void *opaque, int fd); +static GpgmeError read_status (GpgObject gpg); -static int pipemode_cb ( void *opaque, - char *buffer, size_t length, size_t *nread ); -static int command_cb ( void *opaque, - char *buffer, size_t length, size_t *nread ); +static void gpg_colon_line_handler (void *opaque, int fd); +static GpgmeError read_colon_line (GpgObject gpg); +static int pipemode_cb (void *opaque, char *buffer, size_t length, + size_t *nread); +static int command_cb (void *opaque, char *buffer, size_t length, + size_t *nread); static void -close_notify_handler ( int fd, void *opaque ) +close_notify_handler (int fd, void *opaque) { - GpgObject gpg = opaque; + GpgObject gpg = opaque; + int possibly_done = 0; + int not_done = 0; + assert (fd != -1); - assert (fd != -1); - if (gpg->status.fd[0] == fd ) - gpg->status.fd[0] = -1; - else if (gpg->status.fd[1] == fd ) - gpg->status.fd[1] = -1; - else if (gpg->colon.fd[0] == fd ) - gpg->colon.fd[0] = -1; - else if (gpg->colon.fd[1] == fd ) - gpg->colon.fd[1] = -1; - else if (gpg->fd_data_map) { - int i; - - for (i=0; gpg->fd_data_map[i].data; i++ ) { - if ( gpg->fd_data_map[i].fd == fd ) { - gpg->fd_data_map[i].fd = -1; - break; + if (gpg->status.fd[0] == fd) + { + if (gpg->status.tag) + { + (*gpg->io_cbs.remove) (gpg->status.tag); + possibly_done = 1; + } + gpg->status.fd[0] = -1; + } + else if (gpg->status.fd[1] == fd) + gpg->status.fd[1] = -1; + else if (gpg->colon.fd[0] == fd) + { + if (gpg->colon.tag) + { + (*gpg->io_cbs.remove) (gpg->colon.tag); + possibly_done = 1; + } + gpg->colon.fd[0] = -1; + } + else if (gpg->colon.fd[1] == fd) + gpg->colon.fd[1] = -1; + else if (gpg->fd_data_map) + { + int i; + + for (i = 0; gpg->fd_data_map[i].data; i++) + { + if (gpg->fd_data_map[i].fd == fd) + { + if (gpg->fd_data_map[i].tag) + { + (*gpg->io_cbs.remove) (gpg->fd_data_map[i].tag); + possibly_done = 1; + } + gpg->fd_data_map[i].fd = -1; + break; } - if ( gpg->fd_data_map[i].peer_fd == fd ) { - gpg->fd_data_map[i].peer_fd = -1; - break; + if (gpg->fd_data_map[i].peer_fd == fd) + { + gpg->fd_data_map[i].peer_fd = -1; + break; } } } + if (!possibly_done) + not_done = 1; + else if (gpg->status.fd[0] != -1) + not_done = 1; + else if (gpg->colon.fd[0] != -1) + not_done = 1; + else if (gpg->fd_data_map) + { + int i; + + for (i = 0; gpg->fd_data_map[i].data; i++) + if (gpg->fd_data_map[i].fd != -1) + { + not_done = 1; + break; + } + } + if (!not_done && gpg->io_cbs.event) + (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, GPGME_EVENT_DONE, NULL); } const char * @@ -185,65 +238,70 @@ _gpgme_gpg_check_version (void) } GpgmeError -_gpgme_gpg_new ( GpgObject *r_gpg ) +_gpgme_gpg_new (GpgObject *r_gpg) { - GpgObject gpg; - int rc = 0; - - gpg = xtrycalloc ( 1, sizeof *gpg ); - if ( !gpg ) { - rc = mk_error (Out_Of_Core); - goto leave; - } - gpg->argtail = &gpg->arglist; + GpgObject gpg; + int rc = 0; - gpg->status.fd[0] = -1; - gpg->status.fd[1] = -1; - gpg->colon.fd[0] = -1; - gpg->colon.fd[1] = -1; - gpg->cmd.fd = -1; - - gpg->pid = -1; - - /* allocate the read buffer for the status pipe */ - gpg->status.bufsize = 1024; - gpg->status.readpos = 0; - gpg->status.buffer = xtrymalloc (gpg->status.bufsize); - if (!gpg->status.buffer) { - rc = mk_error (Out_Of_Core); - goto leave; + gpg = xtrycalloc (1, sizeof *gpg); + if (!gpg) + { + rc = mk_error (Out_Of_Core); + goto leave; } - /* In any case we need a status pipe - create it right here and - * don't handle it with our generic GpgmeData mechanism */ - if (_gpgme_io_pipe (gpg->status.fd, 1) == -1) { - rc = mk_error (Pipe_Error); - goto leave; + gpg->argtail = &gpg->arglist; + + gpg->status.fd[0] = -1; + gpg->status.fd[1] = -1; + gpg->colon.fd[0] = -1; + gpg->colon.fd[1] = -1; + gpg->cmd.fd = -1; + gpg->cmd.idx = -1; + + gpg->pid = -1; + + /* Allocate the read buffer for the status pipe. */ + gpg->status.bufsize = 1024; + gpg->status.readpos = 0; + gpg->status.buffer = xtrymalloc (gpg->status.bufsize); + if (!gpg->status.buffer) + { + rc = mk_error (Out_Of_Core); + goto leave; } - if ( _gpgme_io_set_close_notify (gpg->status.fd[0], - close_notify_handler, gpg) - || _gpgme_io_set_close_notify (gpg->status.fd[1], - close_notify_handler, gpg) ) { - rc = mk_error (General_Error); - goto leave; + /* In any case we need a status pipe - create it right here and + don't handle it with our generic GpgmeData mechanism. */ + if (_gpgme_io_pipe (gpg->status.fd, 1) == -1) + { + rc = mk_error (Pipe_Error); + goto leave; } - gpg->status.eof = 0; - _gpgme_gpg_add_arg ( gpg, "--status-fd" ); + if (_gpgme_io_set_close_notify (gpg->status.fd[0], + close_notify_handler, gpg) + || _gpgme_io_set_close_notify (gpg->status.fd[1], + close_notify_handler, gpg)) { - char buf[25]; - sprintf ( buf, "%d", gpg->status.fd[1]); - _gpgme_gpg_add_arg ( gpg, buf ); + rc = mk_error (General_Error); + goto leave; } - _gpgme_gpg_add_arg ( gpg, "--no-tty" ); - + gpg->status.eof = 0; + _gpgme_gpg_add_arg (gpg, "--status-fd"); + { + char buf[25]; + sprintf (buf, "%d", gpg->status.fd[1]); + _gpgme_gpg_add_arg (gpg, buf); + } + _gpgme_gpg_add_arg (gpg, "--no-tty"); leave: - if (rc) { - _gpgme_gpg_release (gpg); - *r_gpg = NULL; + if (rc) + { + _gpgme_gpg_release (gpg); + *r_gpg = NULL; } - else - *r_gpg = gpg; - return rc; + else + *r_gpg = gpg; + return rc; } @@ -268,8 +326,6 @@ _gpgme_gpg_release (GpgObject gpg) gpgme_data_release (gpg->cmd.cb_data); xfree (gpg->cmd.keyword); - if (gpg->pid != -1) - _gpgme_remove_proc_from_wait_queue (gpg->pid); if (gpg->status.fd[0] != -1) _gpgme_io_close (gpg->status.fd[0]); if (gpg->status.fd[1] != -1) @@ -279,7 +335,9 @@ _gpgme_gpg_release (GpgObject gpg) if (gpg->colon.fd[1] != -1) _gpgme_io_close (gpg->colon.fd[1]); free_fd_data_map (gpg->fd_data_map); - if (gpg->running) + if (gpg->cmd.fd != -1) + _gpgme_io_close (gpg->cmd.fd); + if (gpg->pid != -1) _gpgme_engine_add_child_to_reap_list (gpg, sizeof *gpg, gpg->pid); else xfree (gpg); @@ -512,341 +570,387 @@ free_fd_data_map ( struct fd_data_map_s *fd_data_map ) static GpgmeError -build_argv ( GpgObject gpg ) +build_argv (GpgObject gpg) { - struct arg_and_data_s *a; - struct fd_data_map_s *fd_data_map; - size_t datac=0, argc=0; - char **argv; - int need_special = 0; - int use_agent = !!getenv ("GPG_AGENT_INFO"); + struct arg_and_data_s *a; + struct fd_data_map_s *fd_data_map; + size_t datac=0, argc=0; + char **argv; + int need_special = 0; + int use_agent = !!getenv ("GPG_AGENT_INFO"); - if ( gpg->argv ) { - free_argv ( gpg->argv ); - gpg->argv = NULL; + if (gpg->argv) + { + free_argv (gpg->argv); + gpg->argv = NULL; } - if (gpg->fd_data_map) { - free_fd_data_map (gpg->fd_data_map); - gpg->fd_data_map = NULL; + if (gpg->fd_data_map) + { + free_fd_data_map (gpg->fd_data_map); + gpg->fd_data_map = NULL; } - argc++; /* for argv[0] */ - for ( a=gpg->arglist; a; a = a->next ) { - argc++; - if (a->data) { - /*fprintf (stderr, "build_argv: data\n" );*/ - datac++; - if ( a->dup_to == -1 && !a->print_fd ) - need_special = 1; + argc++; /* For argv[0]. */ + for (a = gpg->arglist; a; a = a->next) + { + argc++; + if (a->data) + { + /*fprintf (stderr, "build_argv: data\n" );*/ + datac++; + if (a->dup_to == -1 && !a->print_fd) + need_special = 1; } - else { - /* fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/ + else + { + /* fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/ } } - if ( need_special ) - argc++; - if (use_agent) - argc++; - if (!gpg->cmd.used) - argc++; - argc += 2; /* --comment */ - - argv = xtrycalloc ( argc+1, sizeof *argv ); - if (!argv) - return mk_error (Out_Of_Core); - fd_data_map = xtrycalloc ( datac+1, sizeof *fd_data_map ); - if (!fd_data_map) { - free_argv (argv); - return mk_error (Out_Of_Core); + if (need_special) + argc++; + if (use_agent) + argc++; + if (!gpg->cmd.used) + argc++; + argc += 2; /* --comment */ + + argv = xtrycalloc (argc + 1, sizeof *argv); + if (!argv) + return mk_error (Out_Of_Core); + fd_data_map = xtrycalloc (datac + 1, sizeof *fd_data_map); + if (!fd_data_map) + { + free_argv (argv); + return mk_error (Out_Of_Core); } - argc = datac = 0; - argv[argc] = xtrystrdup ( "gpg" ); /* argv[0] */ - if (!argv[argc]) { - xfree (fd_data_map); - free_argv (argv); - return mk_error (Out_Of_Core); + argc = datac = 0; + argv[argc] = xtrystrdup ("gpg"); /* argv[0] */ + if (!argv[argc]) + { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); } - argc++; - if ( need_special ) { - argv[argc] = xtrystrdup ( "--enable-special-filenames" ); - if (!argv[argc]) { - xfree (fd_data_map); - free_argv (argv); - return mk_error (Out_Of_Core); + argc++; + if (need_special) + { + argv[argc] = xtrystrdup ("--enable-special-filenames"); + if (!argv[argc]) + { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); } - argc++; + argc++; } - if ( use_agent ) { - argv[argc] = xtrystrdup ( "--use-agent" ); - if (!argv[argc]) { - xfree (fd_data_map); - free_argv (argv); - return mk_error (Out_Of_Core); + if (use_agent) + { + argv[argc] = xtrystrdup ("--use-agent"); + if (!argv[argc]) + { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); } - argc++; + argc++; } - if ( !gpg->cmd.used ) { - argv[argc] = xtrystrdup ( "--batch" ); - if (!argv[argc]) { - xfree (fd_data_map); - free_argv (argv); - return mk_error (Out_Of_Core); + if (!gpg->cmd.used) + { + argv[argc] = xtrystrdup ("--batch"); + if (!argv[argc]) + { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); } - argc++; + argc++; } - argv[argc] = xtrystrdup ( "--comment" ); - if (!argv[argc]) { - xfree (fd_data_map); - free_argv (argv); - return mk_error (Out_Of_Core); + argv[argc] = xtrystrdup ("--comment"); + if (!argv[argc]) + { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); } - argc++; - argv[argc] = xtrystrdup ( "" ); - if (!argv[argc]) { - xfree (fd_data_map); - free_argv (argv); - return mk_error (Out_Of_Core); + argc++; + argv[argc] = xtrystrdup (""); + if (!argv[argc]) + { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); } - argc++; - for ( a=gpg->arglist; a; a = a->next ) { - if ( a->data ) { - switch ( _gpgme_data_get_mode (a->data) ) { - case GPGME_DATA_MODE_NONE: - case GPGME_DATA_MODE_INOUT: - xfree (fd_data_map); - free_argv (argv); - return mk_error (Invalid_Mode); - case GPGME_DATA_MODE_IN: - /* create a pipe to read from gpg */ - fd_data_map[datac].inbound = 1; - break; - case GPGME_DATA_MODE_OUT: - /* create a pipe to pass it down to gpg */ - fd_data_map[datac].inbound = 0; - break; + argc++; + for (a = gpg->arglist; a; a = a->next) + { + if (a->data) + { + switch (_gpgme_data_get_mode (a->data)) + { + case GPGME_DATA_MODE_NONE: + case GPGME_DATA_MODE_INOUT: + xfree (fd_data_map); + free_argv (argv); + return mk_error (Invalid_Mode); + case GPGME_DATA_MODE_IN: + /* Create a pipe to read from gpg. */ + fd_data_map[datac].inbound = 1; + break; + case GPGME_DATA_MODE_OUT: + /* Create a pipe to pass it down to gpg. */ + fd_data_map[datac].inbound = 0; + break; } - switch ( gpgme_data_get_type (a->data) ) { - case GPGME_DATA_TYPE_NONE: - if ( fd_data_map[datac].inbound ) - break; /* allowed */ - xfree (fd_data_map); - free_argv (argv); - return mk_error (Invalid_Type); - case GPGME_DATA_TYPE_MEM: - case GPGME_DATA_TYPE_CB: - break; - case GPGME_DATA_TYPE_FD: - case GPGME_DATA_TYPE_FILE: - xfree (fd_data_map); - free_argv (argv); - return mk_error (Not_Implemented); + switch (gpgme_data_get_type (a->data)) + { + case GPGME_DATA_TYPE_NONE: + if (fd_data_map[datac].inbound) + break; /* Allowed. */ + xfree (fd_data_map); + free_argv (argv); + return mk_error (Invalid_Type); + case GPGME_DATA_TYPE_MEM: + case GPGME_DATA_TYPE_CB: + break; + case GPGME_DATA_TYPE_FD: + case GPGME_DATA_TYPE_FILE: + xfree (fd_data_map); + free_argv (argv); + return mk_error (Not_Implemented); } - /* create a pipe */ - { - int fds[2]; - - if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound?1:0 ) - == -1) { - xfree (fd_data_map); - free_argv (argv); - return mk_error (Pipe_Error); - } - if ( _gpgme_io_set_close_notify (fds[0], - close_notify_handler, gpg) - || _gpgme_io_set_close_notify (fds[1], - close_notify_handler, - gpg)) { - return mk_error (General_Error); - } - /* if the data_type is FD, we have to do a dup2 here */ - if (fd_data_map[datac].inbound) { - fd_data_map[datac].fd = fds[0]; - fd_data_map[datac].peer_fd = fds[1]; - } - else { - fd_data_map[datac].fd = fds[1]; - fd_data_map[datac].peer_fd = fds[0]; - } - } - - /* Hack to get hands on the fd later */ - if ( gpg->cmd.used && gpg->cmd.cb_data == a->data ) { - assert (gpg->cmd.fd == -1); - gpg->cmd.fd = fd_data_map[datac].fd; - } + /* Create a pipe. */ + { + int fds[2]; + + if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0) + == -1) + { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Pipe_Error); + } + if (_gpgme_io_set_close_notify (fds[0], + close_notify_handler, gpg) + || _gpgme_io_set_close_notify (fds[1], + close_notify_handler, + gpg)) + { + return mk_error (General_Error); + } + /* If the data_type is FD, we have to do a dup2 here. */ + if (fd_data_map[datac].inbound) + { + fd_data_map[datac].fd = fds[0]; + fd_data_map[datac].peer_fd = fds[1]; + } + else + { + fd_data_map[datac].fd = fds[1]; + fd_data_map[datac].peer_fd = fds[0]; + } + } + + /* Hack to get hands on the fd later. */ + if (gpg->cmd.used && gpg->cmd.cb_data == a->data) + { + assert (gpg->cmd.idx == -1); + gpg->cmd.idx = datac; + } - fd_data_map[datac].data = a->data; - fd_data_map[datac].dup_to = a->dup_to; - if ( a->dup_to == -1 ) { - argv[argc] = xtrymalloc ( 25 ); - if (!argv[argc]) { - xfree (fd_data_map); - free_argv (argv); - return mk_error (Out_Of_Core); + fd_data_map[datac].data = a->data; + fd_data_map[datac].dup_to = a->dup_to; + if (a->dup_to == -1) + { + argv[argc] = xtrymalloc (25); + if (!argv[argc]) + { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); } - sprintf ( argv[argc], - a->print_fd? "%d" : "-&%d", - fd_data_map[datac].peer_fd ); - argc++; + sprintf (argv[argc], + a->print_fd ? "%d" : "-&%d", + fd_data_map[datac].peer_fd); + argc++; } - datac++; + datac++; } - else { - argv[argc] = xtrystrdup ( a->arg ); - if (!argv[argc]) { - xfree (fd_data_map); - free_argv (argv); - return mk_error (Out_Of_Core); + else + { + argv[argc] = xtrystrdup (a->arg); + if (!argv[argc]) + { + xfree (fd_data_map); + free_argv (argv); + return mk_error (Out_Of_Core); } argc++; } } - gpg->argv = argv; - gpg->fd_data_map = fd_data_map; - return 0; + gpg->argv = argv; + gpg->fd_data_map = fd_data_map; + return 0; +} + +static GpgmeError +_gpgme_gpg_add_io_cb (GpgObject gpg, int fd, int dir, + GpgmeIOCb handler, void *data, void **tag) +{ + GpgmeError err = 0; + + *tag = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data); + if (!tag) + err = mk_error (General_Error); + if (!err && !dir) + /* FIXME Kludge around poll() problem. */ + err = _gpgme_io_set_nonblocking (fd); + return err; } GpgmeError -_gpgme_gpg_spawn( GpgObject gpg, void *opaque ) +_gpgme_gpg_spawn (GpgObject gpg, void *opaque) { - int rc; - int i, n; - int pid; - struct spawn_fd_item_s *fd_child_list, *fd_parent_list; + GpgmeError rc; + int i, n; + int pid; + struct spawn_fd_item_s *fd_child_list, *fd_parent_list; - if (!gpg) - return mk_error (Invalid_Value); + if (!gpg) + return mk_error (Invalid_Value); - if (! _gpgme_get_gpg_path ()) - return mk_error (Invalid_Engine); + if (! _gpgme_get_gpg_path ()) + return mk_error (Invalid_Engine); - /* Kludge, so that we don't need to check the return code of - * all the gpgme_gpg_add_arg(). we bail out here instead */ - if ( gpg->arg_error ) - return mk_error (Out_Of_Core); + /* Kludge, so that we don't need to check the return code of all the + gpgme_gpg_add_arg(). we bail out here instead */ + if (gpg->arg_error) + return mk_error (Out_Of_Core); - if (gpg->pm.active) - return 0; + if (gpg->pm.active) + return 0; - rc = build_argv ( gpg ); - if ( rc ) - return rc; + rc = build_argv (gpg); + if (rc) + return rc; - n = 3; /* status_fd, colon_fd and end of list */ - for (i=0; gpg->fd_data_map[i].data; i++ ) - n++; - fd_child_list = xtrycalloc ( n+n, sizeof *fd_child_list ); - if (!fd_child_list) - return mk_error (Out_Of_Core); - fd_parent_list = fd_child_list + n; - - /* build the fd list for the child */ - n=0; - if ( gpg->colon.fnc ) { - fd_child_list[n].fd = gpg->colon.fd[1]; - fd_child_list[n].dup_to = 1; /* dup to stdout */ - n++; + n = 3; /* status_fd, colon_fd and end of list */ + for (i = 0; gpg->fd_data_map[i].data; i++) + n++; + fd_child_list = xtrycalloc (n + n, sizeof *fd_child_list); + if (!fd_child_list) + return mk_error (Out_Of_Core); + fd_parent_list = fd_child_list + n; + + /* build the fd list for the child */ + n = 0; + if (gpg->colon.fnc) + { + fd_child_list[n].fd = gpg->colon.fd[1]; + fd_child_list[n].dup_to = 1; /* dup to stdout */ + n++; } - for (i=0; gpg->fd_data_map[i].data; i++ ) { - if (gpg->fd_data_map[i].dup_to != -1) { - fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd; - fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to; - n++; + for (i = 0; gpg->fd_data_map[i].data; i++) + { + if (gpg->fd_data_map[i].dup_to != -1) + { + fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd; + fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to; + n++; } } - fd_child_list[n].fd = -1; - fd_child_list[n].dup_to = -1; - - /* build the fd list for the parent */ - n=0; - if ( gpg->status.fd[1] != -1 ) { - fd_parent_list[n].fd = gpg->status.fd[1]; - fd_parent_list[n].dup_to = -1; - n++; - gpg->status.fd[1] = -1; + fd_child_list[n].fd = -1; + fd_child_list[n].dup_to = -1; + + /* Build the fd list for the parent. */ + n = 0; + if (gpg->status.fd[1] != -1) + { + fd_parent_list[n].fd = gpg->status.fd[1]; + fd_parent_list[n].dup_to = -1; + n++; + gpg->status.fd[1] = -1; } - if ( gpg->colon.fd[1] != -1 ) { - fd_parent_list[n].fd = gpg->colon.fd[1]; - fd_parent_list[n].dup_to = -1; - n++; - gpg->colon.fd[1] = -1; + if (gpg->colon.fd[1] != -1) + { + fd_parent_list[n].fd = gpg->colon.fd[1]; + fd_parent_list[n].dup_to = -1; + n++; + gpg->colon.fd[1] = -1; } - for (i=0; gpg->fd_data_map[i].data; i++ ) { - fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd; - fd_parent_list[n].dup_to = -1; - n++; - gpg->fd_data_map[i].peer_fd = -1; + for (i = 0; gpg->fd_data_map[i].data; i++) + { + fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd; + fd_parent_list[n].dup_to = -1; + n++; + gpg->fd_data_map[i].peer_fd = -1; } - fd_parent_list[n].fd = -1; - fd_parent_list[n].dup_to = -1; - + fd_parent_list[n].fd = -1; + fd_parent_list[n].dup_to = -1; - pid = _gpgme_io_spawn (_gpgme_get_gpg_path (), - gpg->argv, fd_child_list, fd_parent_list); - xfree (fd_child_list); - if (pid == -1) { - return mk_error (Exec_Error); - } + pid = _gpgme_io_spawn (_gpgme_get_gpg_path (), + gpg->argv, fd_child_list, fd_parent_list); + xfree (fd_child_list); + if (pid == -1) + return mk_error (Exec_Error); - gpg->pid = pid; - if (gpg->pm.used) - gpg->pm.active = 1; + gpg->pid = pid; + if (gpg->pm.used) + gpg->pm.active = 1; - /*_gpgme_register_term_handler ( closure, closure_value, pid );*/ - - if ( _gpgme_register_pipe_handler ( opaque, gpg_status_handler, - gpg, pid, gpg->status.fd[0], 1 ) ) { - /* FIXME: kill the child */ - return mk_error (General_Error); + /*_gpgme_register_term_handler ( closure, closure_value, pid );*/ - } + rc = _gpgme_gpg_add_io_cb (gpg, gpg->status.fd[0], 1, + gpg_status_handler, gpg, &gpg->status.tag); + if (rc) + /* FIXME: kill the child */ + return rc; - if ( gpg->colon.fnc ) { - assert ( gpg->colon.fd[0] != -1 ); - if ( _gpgme_register_pipe_handler ( opaque, gpg_colon_line_handler, - gpg, pid, gpg->colon.fd[0], 1 ) ) { - /* FIXME: kill the child */ - return mk_error (General_Error); - - } + if (gpg->colon.fnc) + { + assert (gpg->colon.fd[0] != -1); + rc = _gpgme_gpg_add_io_cb (gpg, gpg->colon.fd[0], 1, + gpg_colon_line_handler, gpg, + &gpg->colon.tag); + if (rc) + /* FIXME: kill the child */ + return rc; } - for (i=0; gpg->fd_data_map[i].data; i++ ) { - /* Due to problems with select and write we set outbound pipes - * to non-blocking */ - if (!gpg->fd_data_map[i].inbound) { - _gpgme_io_set_nonblocking (gpg->fd_data_map[i].fd); - } - - if ( _gpgme_register_pipe_handler ( - opaque, - gpg->fd_data_map[i].inbound? - _gpgme_data_inbound_handler:_gpgme_data_outbound_handler, - gpg->fd_data_map[i].data, - pid, gpg->fd_data_map[i].fd, - gpg->fd_data_map[i].inbound ) - ) { - /* FIXME: kill the child */ - return mk_error (General_Error); - } + for (i = 0; gpg->fd_data_map[i].data; i++) + { + if (gpg->cmd.used && i == gpg->cmd.idx) + { + /* Park the cmd fd. */ + gpg->cmd.fd = gpg->fd_data_map[i].fd; + gpg->fd_data_map[i].fd = -1; + } + else + { + rc = _gpgme_gpg_add_io_cb (gpg, gpg->fd_data_map[i].fd, + gpg->fd_data_map[i].inbound, + gpg->fd_data_map[i].inbound + ? _gpgme_data_inbound_handler + : _gpgme_data_outbound_handler, + gpg->fd_data_map[i].data, + &gpg->fd_data_map[i].tag); + + if (rc) + /* FIXME: kill the child */ + return rc; + } } - - if ( gpg->cmd.used ) - _gpgme_freeze_fd ( gpg->cmd.fd ); - - /* fixme: check what data we can release here */ - - gpg->running = 1; - return 0; + + /* fixme: check what data we can release here */ + return 0; } -static int -gpg_status_handler (void *opaque, int pid, int fd) +static void +gpg_status_handler (void *opaque, int fd) { GpgObject gpg = opaque; int err; @@ -860,9 +964,11 @@ gpg_status_handler (void *opaque, int pid, int fd) GpgmeCtx ctx = (GpgmeCtx) gpg->status.fnc_value; ctx->error = err; DEBUG1 ("gpg_handler: read_status problem %d\n - stop", err); - return 1; + _gpgme_io_close (fd); + return; } - return gpg->status.eof; + if (gpg->status.eof) + _gpgme_io_close (fd); } @@ -951,7 +1057,14 @@ read_status ( GpgObject gpg ) * handler does its action */ if ( nread > 1 ) DEBUG0 ("ERROR, unexpected data in read_status"); - _gpgme_thaw_fd (gpg->cmd.fd); + + _gpgme_gpg_add_io_cb + (gpg, gpg->cmd.fd, + 0, _gpgme_data_outbound_handler, + gpg->fd_data_map[gpg->cmd.idx].data, + &gpg->fd_data_map[gpg->cmd.idx].tag); + gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd; + gpg->cmd.fd = -1; } else if ( gpg->status.fnc ) { gpg->status.fnc ( gpg->status.fnc_value, @@ -959,8 +1072,13 @@ read_status ( GpgObject gpg ) } if ( r->code == STATUS_END_STREAM ) { - if ( gpg->cmd.used ) - _gpgme_freeze_fd ( gpg->cmd.fd ); + if (gpg->cmd.used) + { + (*gpg->io_cbs.remove) + (gpg->fd_data_map[gpg->cmd.idx].tag); + gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd; + gpg->fd_data_map[gpg->cmd.idx].fd = -1; + } } } } @@ -995,21 +1113,23 @@ read_status ( GpgObject gpg ) * a wrapper for a callback. Same goes for the status thing. * For now we use this thing here becuase it is easier to implement. */ -static int -gpg_colon_line_handler ( void *opaque, int pid, int fd ) +static void +gpg_colon_line_handler (void *opaque, int fd) { - GpgObject gpg = opaque; - GpgmeError rc = 0; - - assert ( fd == gpg->colon.fd[0] ); - rc = read_colon_line ( gpg ); - if ( rc ) { - DEBUG1 ("gpg_colon_line_handler: " - "read problem %d\n - stop", rc); - return 1; - } + GpgObject gpg = opaque; + GpgmeError rc = 0; - return gpg->colon.eof; + assert (fd == gpg->colon.fd[0]); + rc = read_colon_line (gpg); + if (rc) + { + DEBUG1 ("gpg_colon_line_handler: " + "read problem %d\n - stop", rc); + _gpgme_io_close (fd); + return; + } + if (gpg->colon.eof) + _gpgme_io_close (fd); } static GpgmeError @@ -1167,52 +1287,59 @@ pipemode_cb ( void *opaque, char *buffer, size_t length, size_t *nread ) */ static int -command_cb ( void *opaque, char *buffer, size_t length, size_t *nread ) +command_cb (void *opaque, char *buffer, size_t length, size_t *nread) { - GpgObject gpg = opaque; - const char *value; - int value_len; - - DEBUG0 ("command_cb: enter\n"); - assert (gpg->cmd.used); - if ( !buffer || !length || !nread ) - return 0; /* those values are reserved for extensions */ - *nread =0; - if ( !gpg->cmd.code ) { - DEBUG0 ("command_cb: no code\n"); - return -1; + GpgObject gpg = opaque; + const char *value; + int value_len; + + DEBUG0 ("command_cb: enter\n"); + assert (gpg->cmd.used); + if (!buffer || !length || !nread) + return 0; /* These values are reserved for extensions. */ + *nread = 0; + if (!gpg->cmd.code) + { + DEBUG0 ("command_cb: no code\n"); + return -1; } - if ( !gpg->cmd.fnc ) { - DEBUG0 ("command_cb: no user cb\n"); - return -1; + if (!gpg->cmd.fnc) + { + DEBUG0 ("command_cb: no user cb\n"); + return -1; } - value = gpg->cmd.fnc ( gpg->cmd.fnc_value, - gpg->cmd.code, gpg->cmd.keyword ); - if ( !value ) { - DEBUG0 ("command_cb: no data from user cb\n"); - gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); - return -1; + value = gpg->cmd.fnc (gpg->cmd.fnc_value, + gpg->cmd.code, gpg->cmd.keyword); + if (!value) + { + DEBUG0 ("command_cb: no data from user cb\n"); + gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value); + return -1; } - value_len = strlen (value); - if ( value_len+1 > length ) { - DEBUG0 ("command_cb: too much data from user cb\n"); - gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); - return -1; + value_len = strlen (value); + if (value_len + 1 > length) + { + DEBUG0 ("command_cb: too much data from user cb\n"); + gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value); + return -1; } - memcpy ( buffer, value, value_len ); - if ( !value_len || (value_len && value[value_len-1] != '\n') ) - buffer[value_len++] = '\n'; - *nread = value_len; + memcpy (buffer, value, value_len); + if (!value_len || (value_len && value[value_len-1] != '\n')) + buffer[value_len++] = '\n'; + *nread = value_len; - gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); - gpg->cmd.code = 0; - /* and sleep again until read_status will wake us up again */ - _gpgme_freeze_fd ( gpg->cmd.fd ); - return 0; + gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value); + gpg->cmd.code = 0; + /* And sleep again until read_status will wake us up again. */ + (*gpg->io_cbs.remove) (gpg->fd_data_map[gpg->cmd.idx].tag); + gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd; + gpg->fd_data_map[gpg->cmd.idx].fd = -1; + + return 0; } GpgmeError @@ -1603,3 +1730,10 @@ _gpgme_gpg_op_verify (GpgObject gpg, GpgmeData sig, GpgmeData text) } return err; } + + +void +_gpgme_gpg_set_io_cbs (GpgObject gpg, struct GpgmeIOCbs *io_cbs) +{ + gpg->io_cbs = *io_cbs; +} |