diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2024-07-09 02:39:15 +0200 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2024-07-09 03:04:16 +0200 |
commit | 953dd67368ceaeb8b42cfb8f9b5f3c4de8afdbe0 (patch) | |
tree | 34861697c585e95c970fd6955ea749867efcb6ec /common | |
parent | speedo: Set PREFIX for bzip2 build also for Unix. (diff) | |
download | gnupg2-953dd67368ceaeb8b42cfb8f9b5f3c4de8afdbe0.tar.xz gnupg2-953dd67368ceaeb8b42cfb8f9b5f3c4de8afdbe0.zip |
Use gpgrt_process_spawn API from libgpg-error.
* agent/genkey.c (do_check_passphrase_pattern): Use the gpgrt API.
* common/asshelp.c (start_new_service): Ditto.
* common/exechelp.h: Remove gnupg_process_spawn API.
* common/exechelp-posix.c: Remove gnupg_process_spawn implementation.
* common/exechelp-w32.c: Likewise.
* common/exectool.c (gnupg_exec_tool_stream): Use the gpgrt API.
* common/t-exechelp.c (test_pipe_stream): Remove.
* dirmngr/ldap-wrapper.c (destroy_wrapper, ldap_reaper_thread): Use
the gpgrt API.
(ldap_wrapper_connection_cleanup, ldap_wrapper): Ditto.
* dirmngr/ldap.c, g10/call-keyboxd.c: No need to include exechelp.h.
* g10/photoid.c (run_with_pipe, show_photo): Use the gpgrt API.
* g13/be-encfs.c (run_umount_helper, run_encfs_tool): Ditto.
* g13/g13.c, g13/mount.c, g13/runner.c: No need to include exechelp.h.
* scd/apdu.c: No need to include exechelp.h.
* scd/app.c (report_change): Use the gpgrt API.
* sm/export.c, sm/import.c: No need to include exechelp.h.
* tests/gpgscm/ffi.c (proc_object_finalize, proc_wrap)
(do_process_spawn_io, do_process_spawn_fd, do_process_wait): Use the
gpgrt API.
* tools/gpg-auth.c: No need to include exechelp.h.
* tools/gpg-card.c (cmd_gpg): Use the gpgrt API.
* tools/gpg-connect-agent.c: No need to include exechelp.h.
* tools/gpg-mail-tube.c (mail_tube_encrypt, prepare_for_appimage)
(start_gpg_encrypt): Use the gpgrt API.
* tools/gpgconf-comp.c (gpg_agent_runtime_change)
(scdaemon_runtime_change, tpm2daemon_runtime_change)
(dirmngr_runtime_change, keyboxd_runtime_change)
(gc_component_launch, gc_component_check_options)
(retrieve_options_from_program): Ditto.
* tools/gpgconf.c (show_versions_via_dirmngr): Ditto.
* tools/gpgtar-create.c (gpgtar_create): Ditto.
* tools/gpgtar-extract.c (gpgtar_extract): Ditto.
* tools/gpgtar-list.c (gpgtar_list): Ditto.
--
GnuPG-bug-id: 7192
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
Diffstat (limited to 'common')
-rw-r--r-- | common/asshelp.c | 7 | ||||
-rw-r--r-- | common/exechelp-posix.c | 725 | ||||
-rw-r--r-- | common/exechelp-w32.c | 974 | ||||
-rw-r--r-- | common/exechelp.h | 95 | ||||
-rw-r--r-- | common/exectool.c | 35 | ||||
-rw-r--r-- | common/t-exechelp.c | 66 |
6 files changed, 20 insertions, 1882 deletions
diff --git a/common/asshelp.c b/common/asshelp.c index f17a32e52..a31fa83bc 100644 --- a/common/asshelp.c +++ b/common/asshelp.c @@ -39,7 +39,6 @@ #include "i18n.h" #include "util.h" -#include "exechelp.h" #include "sysutils.h" #include "status.h" #include "membuf.h" @@ -524,10 +523,10 @@ start_new_service (assuan_context_t *r_ctx, && assuan_socket_connect (ctx, sockname, 0, connect_flags)) { #ifdef HAVE_W32_SYSTEM - err = gnupg_process_spawn (program? program : program_name, argv, - GNUPG_PROCESS_DETACHED, NULL, NULL); + err = gpgrt_process_spawn (program? program : program_name, argv, + GPGRT_PROCESS_DETACHED, NULL, NULL); #else /*!W32*/ - err = gnupg_process_spawn (program? program : program_name, argv, + err = gpgrt_process_spawn (program? program : program_name, argv, 0, NULL, NULL); #endif /*!W32*/ if (err) diff --git a/common/exechelp-posix.c b/common/exechelp-posix.c index 97d8fa4ad..b78439dca 100644 --- a/common/exechelp-posix.c +++ b/common/exechelp-posix.c @@ -357,728 +357,3 @@ gnupg_close_pipe (int fd) if (fd != -1) close (fd); } - -#include <sys/socket.h> - -struct gnupg_process { - const char *pgmname; - unsigned int terminated :1; /* or detached */ - unsigned int flags; - pid_t pid; - int fd_in; - int fd_out; - int fd_err; - int wstatus; -}; - -static int gnupg_process_syscall_func_initialized; - -/* Functions called before and after blocking syscalls. */ -static void (*pre_syscall_func) (void); -static void (*post_syscall_func) (void); - -static void -check_syscall_func (void) -{ - if (!gnupg_process_syscall_func_initialized) - { - gpgrt_get_syscall_clamp (&pre_syscall_func, &post_syscall_func); - gnupg_process_syscall_func_initialized = 1; - } -} - -static void -pre_syscall (void) -{ - if (pre_syscall_func) - pre_syscall_func (); -} - -static void -post_syscall (void) -{ - if (post_syscall_func) - post_syscall_func (); -} - - -static gpg_err_code_t -do_create_socketpair (int filedes[2]) -{ - gpg_error_t err = 0; - - pre_syscall (); - if (socketpair (AF_LOCAL, SOCK_STREAM, 0, filedes) == -1) - { - err = gpg_err_code_from_syserror (); - filedes[0] = filedes[1] = -1; - } - post_syscall (); - - return err; -} - -static int -posix_open_null (int for_write) -{ - int fd; - - fd = open ("/dev/null", for_write? O_WRONLY : O_RDONLY); - if (fd == -1) - log_fatal ("failed to open '/dev/null': %s\n", strerror (errno)); - return fd; -} - -struct gnupg_spawn_actions { - int fd[3]; - const int *except_fds; - char **environ; - void (*atfork) (void *); - void *atfork_arg; -}; - -gpg_err_code_t -gnupg_spawn_actions_new (gnupg_spawn_actions_t *r_act) -{ - gnupg_spawn_actions_t act; - int i; - - *r_act = NULL; - - act = xtrycalloc (1, sizeof (struct gnupg_spawn_actions)); - if (act == NULL) - return gpg_err_code_from_syserror (); - - for (i = 0; i <= 2; i++) - act->fd[i] = -1; - - *r_act = act; - return 0; -} - -void -gnupg_spawn_actions_release (gnupg_spawn_actions_t act) -{ - if (!act) - return; - - xfree (act); -} - -void -gnupg_spawn_actions_set_environ (gnupg_spawn_actions_t act, - char **environ_for_child) -{ - act->environ = environ_for_child; -} - -void -gnupg_spawn_actions_set_atfork (gnupg_spawn_actions_t act, - void (*atfork)(void *), void *arg) -{ - act->atfork = atfork; - act->atfork_arg = arg; -} - -void -gnupg_spawn_actions_set_redirect (gnupg_spawn_actions_t act, - int in, int out, int err) -{ - act->fd[0] = in; - act->fd[1] = out; - act->fd[2] = err; -} - -void -gnupg_spawn_actions_set_inherit_fds (gnupg_spawn_actions_t act, - const int *fds) -{ - act->except_fds = fds; -} - -static void -my_exec (const char *pgmname, const char *argv[], gnupg_spawn_actions_t act) -{ - int i; - - /* Assign /dev/null to unused FDs. */ - for (i = 0; i <= 2; i++) - if (act->fd[i] == -1) - act->fd[i] = posix_open_null (i); - - /* Connect the standard files. */ - for (i = 0; i <= 2; i++) - if (act->fd[i] != i) - { - if (dup2 (act->fd[i], i) == -1) - log_fatal ("dup2 std%s failed: %s\n", - i==0?"in":i==1?"out":"err", strerror (errno)); - /* - * We don't close act->fd[i] here, but close them by - * close_all_fds. Note that there may be same one in three of - * act->fd[i]. - */ - } - - /* Close all other files. */ - close_all_fds (3, act->except_fds); - - if (act->environ) - environ = act->environ; - - if (act->atfork) - act->atfork (act->atfork_arg); - - execv (pgmname, (char *const *)argv); - /* No way to print anything, as we have may have closed all streams. */ - _exit (127); -} - -static gpg_err_code_t -spawn_detached (const char *pgmname, const char *argv[], - gnupg_spawn_actions_t act) -{ - gpg_err_code_t ec; - pid_t pid; - - /* FIXME: Is this GnuPG specific or should we keep it. */ - if (getuid() != geteuid()) - { - xfree (argv); - return GPG_ERR_BUG; - } - - if (access (pgmname, X_OK)) - { - ec = gpg_err_code_from_syserror (); - xfree (argv); - return ec; - } - - pre_syscall (); - pid = fork (); - post_syscall (); - if (pid == (pid_t)(-1)) - { - ec = gpg_err_code_from_syserror (); - log_error (_("error forking process: %s\n"), gpg_strerror (ec)); - xfree (argv); - return ec; - } - - if (!pid) - { - pid_t pid2; - - if (setsid() == -1 || chdir ("/")) - _exit (1); - - pid2 = fork (); /* Double fork to let init take over the new child. */ - if (pid2 == (pid_t)(-1)) - _exit (1); - if (pid2) - _exit (0); /* Let the parent exit immediately. */ - - my_exec (pgmname, argv, act); - /*NOTREACHED*/ - } - - pre_syscall (); - if (waitpid (pid, NULL, 0) == -1) - { - post_syscall (); - ec = gpg_err_code_from_syserror (); - log_error ("waitpid failed in spawn_detached: %s", - gpg_strerror (ec)); - return ec; - } - else - post_syscall (); - - return 0; -} - -gpg_err_code_t -gnupg_process_spawn (const char *pgmname, const char *argv1[], - unsigned int flags, gnupg_spawn_actions_t act, - gnupg_process_t *r_process) -{ - gpg_err_code_t ec; - gnupg_process_t process; - int fd_in[2]; - int fd_out[2]; - int fd_err[2]; - pid_t pid; - const char **argv; - int i, j; - struct gnupg_spawn_actions act_default; - - if (!act) - { - memset (&act_default, 0, sizeof (act_default)); - for (i = 0; i <= 2; i++) - act_default.fd[i] = -1; - act = &act_default; - } - - check_syscall_func (); - - if (r_process) - *r_process = NULL; - - /* Create the command line argument array. */ - i = 0; - if (argv1) - while (argv1[i]) - i++; - argv = xtrycalloc (i+2, sizeof *argv); - if (!argv) - return gpg_err_code_from_syserror (); - argv[0] = strrchr (pgmname, '/'); - if (argv[0]) - argv[0]++; - else - argv[0] = pgmname; - - if (argv1) - for (i=0, j=1; argv1[i]; i++, j++) - argv[j] = argv1[i]; - - if ((flags & GNUPG_PROCESS_DETACHED)) - { - if ((flags & GNUPG_PROCESS_STDFDS_SETTING)) - { - xfree (argv); - return GPG_ERR_INV_FLAG; - } - - /* In detached case, it must be no R_PROCESS. */ - if (r_process) - { - xfree (argv); - return GPG_ERR_INV_ARG; - } - - return spawn_detached (pgmname, argv, act); - } - - process = xtrycalloc (1, sizeof (struct gnupg_process)); - if (process == NULL) - { - xfree (argv); - return gpg_err_code_from_syserror (); - } - - process->pgmname = pgmname; - process->flags = flags; - - if ((flags & GNUPG_PROCESS_STDINOUT_SOCKETPAIR)) - { - ec = do_create_socketpair (fd_in); - if (ec) - { - xfree (process); - xfree (argv); - return ec; - } - fd_out[0] = dup (fd_in[0]); - fd_out[1] = dup (fd_in[1]); - } - else - { - if ((flags & GNUPG_PROCESS_STDIN_PIPE)) - { - ec = do_create_pipe (fd_in); - if (ec) - { - xfree (process); - xfree (argv); - return ec; - } - } - else if ((flags & GNUPG_PROCESS_STDIN_KEEP)) - { - fd_in[0] = 0; - fd_in[1] = -1; - } - else - { - fd_in[0] = -1; - fd_in[1] = -1; - } - - if ((flags & GNUPG_PROCESS_STDOUT_PIPE)) - { - ec = do_create_pipe (fd_out); - if (ec) - { - if (fd_in[0] >= 0 && fd_in[0] != 0) - close (fd_in[0]); - if (fd_in[1] >= 0) - close (fd_in[1]); - xfree (process); - xfree (argv); - return ec; - } - } - else if ((flags & GNUPG_PROCESS_STDOUT_KEEP)) - { - fd_out[0] = -1; - fd_out[1] = 1; - } - else - { - fd_out[0] = -1; - fd_out[1] = -1; - } - } - - if ((flags & GNUPG_PROCESS_STDERR_PIPE)) - { - ec = do_create_pipe (fd_err); - if (ec) - { - if (fd_in[0] >= 0 && fd_in[0] != 0) - close (fd_in[0]); - if (fd_in[1] >= 0) - close (fd_in[1]); - if (fd_out[0] >= 0) - close (fd_out[0]); - if (fd_out[1] >= 0 && fd_out[1] != 1) - close (fd_out[1]); - xfree (process); - xfree (argv); - return ec; - } - } - else if ((flags & GNUPG_PROCESS_STDERR_KEEP)) - { - fd_err[0] = -1; - fd_err[1] = 2; - } - else - { - fd_err[0] = -1; - fd_err[1] = -1; - } - - pre_syscall (); - pid = fork (); - post_syscall (); - if (pid == (pid_t)(-1)) - { - ec = gpg_err_code_from_syserror (); - log_error (_("error forking process: %s\n"), gpg_strerror (ec)); - if (fd_in[0] >= 0 && fd_in[0] != 0) - close (fd_in[0]); - if (fd_in[1] >= 0) - close (fd_in[1]); - if (fd_out[0] >= 0) - close (fd_out[0]); - if (fd_out[1] >= 0 && fd_out[1] != 1) - close (fd_out[1]); - if (fd_err[0] >= 0) - close (fd_err[0]); - if (fd_err[1] >= 0 && fd_err[1] != 2) - close (fd_err[1]); - xfree (process); - xfree (argv); - return ec; - } - - if (!pid) - { - if (fd_in[1] >= 0) - close (fd_in[1]); - if (fd_out[0] >= 0) - close (fd_out[0]); - if (fd_err[0] >= 0) - close (fd_err[0]); - - if (act->fd[0] < 0) - act->fd[0] = fd_in[0]; - if (act->fd[1] < 0) - act->fd[1] = fd_out[1]; - if (act->fd[2] < 0) - act->fd[2] = fd_err[1]; - - /* Run child. */ - my_exec (pgmname, argv, act); - /*NOTREACHED*/ - } - - xfree (argv); - process->pid = pid; - - if (fd_in[0] >= 0 && fd_in[0] != 0) - close (fd_in[0]); - if (fd_out[1] >= 0 && fd_out[1] != 1) - close (fd_out[1]); - if (fd_err[1] >= 0 && fd_err[1] != 2) - close (fd_err[1]); - process->fd_in = fd_in[1]; - process->fd_out = fd_out[0]; - process->fd_err = fd_err[0]; - process->wstatus = -1; - process->terminated = 0; - - if (r_process == NULL) - { - ec = gnupg_process_wait (process, 1); - gnupg_process_release (process); - return ec; - } - - *r_process = process; - return 0; -} - -static gpg_err_code_t -process_kill (gnupg_process_t process, int sig) -{ - gpg_err_code_t ec = 0; - pid_t pid = process->pid; - - pre_syscall (); - if (kill (pid, sig) < 0) - ec = gpg_err_code_from_syserror (); - post_syscall (); - return ec; -} - -gpg_err_code_t -gnupg_process_terminate (gnupg_process_t process) -{ - return process_kill (process, SIGTERM); -} - -gpg_err_code_t -gnupg_process_get_fds (gnupg_process_t process, unsigned int flags, - int *r_fd_in, int *r_fd_out, int *r_fd_err) -{ - (void)flags; - if (r_fd_in) - { - *r_fd_in = process->fd_in; - process->fd_in = -1; - } - if (r_fd_out) - { - *r_fd_out = process->fd_out; - process->fd_out = -1; - } - if (r_fd_err) - { - *r_fd_err = process->fd_err; - process->fd_err = -1; - } - - return 0; -} - -gpg_err_code_t -gnupg_process_get_streams (gnupg_process_t process, unsigned int flags, - gpgrt_stream_t *r_fp_in, gpgrt_stream_t *r_fp_out, - gpgrt_stream_t *r_fp_err) -{ - int nonblock = (flags & GNUPG_PROCESS_STREAM_NONBLOCK)? 1: 0; - - if (r_fp_in) - { - *r_fp_in = es_fdopen (process->fd_in, nonblock? "w,nonblock" : "w"); - process->fd_in = -1; - } - if (r_fp_out) - { - *r_fp_out = es_fdopen (process->fd_out, nonblock? "r,nonblock" : "r"); - process->fd_out = -1; - } - if (r_fp_err) - { - *r_fp_err = es_fdopen (process->fd_err, nonblock? "r,nonblock" : "r"); - process->fd_err = -1; - } - return 0; -} - -static gpg_err_code_t -process_vctl (gnupg_process_t process, unsigned int request, va_list arg_ptr) -{ - switch (request) - { - case GNUPG_PROCESS_NOP: - return 0; - - case GNUPG_PROCESS_GET_PROC_ID: - { - int *r_id = va_arg (arg_ptr, int *); - - if (r_id == NULL) - return GPG_ERR_INV_VALUE; - - *r_id = (int)process->pid; - return 0; - } - - case GNUPG_PROCESS_GET_EXIT_ID: - { - int status = process->wstatus; - int *r_exit_status = va_arg (arg_ptr, int *); - - if (!process->terminated) - return GPG_ERR_UNFINISHED; - - if (WIFEXITED (status)) - { - if (r_exit_status) - *r_exit_status = WEXITSTATUS (status); - } - else - *r_exit_status = -1; - - return 0; - } - - case GNUPG_PROCESS_GET_PID: - { - pid_t *r_pid = va_arg (arg_ptr, pid_t *); - - if (r_pid == NULL) - return GPG_ERR_INV_VALUE; - - *r_pid = process->pid; - return 0; - } - - case GNUPG_PROCESS_GET_WSTATUS: - { - int status = process->wstatus; - int *r_if_exited = va_arg (arg_ptr, int *); - int *r_if_signaled = va_arg (arg_ptr, int *); - int *r_exit_status = va_arg (arg_ptr, int *); - int *r_termsig = va_arg (arg_ptr, int *); - - if (!process->terminated) - return GPG_ERR_UNFINISHED; - - if (WIFEXITED (status)) - { - if (r_if_exited) - *r_if_exited = 1; - if (r_if_signaled) - *r_if_signaled = 0; - if (r_exit_status) - *r_exit_status = WEXITSTATUS (status); - if (r_termsig) - *r_termsig = 0; - } - else if (WIFSIGNALED (status)) - { - if (r_if_exited) - *r_if_exited = 0; - if (r_if_signaled) - *r_if_signaled = 1; - if (r_exit_status) - *r_exit_status = 0; - if (r_termsig) - *r_termsig = WTERMSIG (status); - } - - return 0; - } - - case GNUPG_PROCESS_KILL: - { - int sig = va_arg (arg_ptr, int); - - return process_kill (process, sig); - } - - default: - break; - } - - return GPG_ERR_UNKNOWN_COMMAND; -} - -gpg_err_code_t -gnupg_process_ctl (gnupg_process_t process, unsigned int request, ...) -{ - va_list arg_ptr; - gpg_err_code_t ec; - - va_start (arg_ptr, request); - ec = process_vctl (process, request, arg_ptr); - va_end (arg_ptr); - return ec; -} - -gpg_err_code_t -gnupg_process_wait (gnupg_process_t process, int hang) -{ - gpg_err_code_t ec; - int status; - pid_t pid; - - if (process->terminated) - /* Already terminated. */ - return 0; - - pre_syscall (); - while ((pid = waitpid (process->pid, &status, hang? 0: WNOHANG)) - == (pid_t)(-1) && errno == EINTR); - post_syscall (); - - if (pid == (pid_t)(-1)) - { - ec = gpg_err_code_from_syserror (); - log_error (_("waiting for process %d to terminate failed: %s\n"), - (int)pid, gpg_strerror (ec)); - } - else if (!pid) - { - ec = GPG_ERR_TIMEOUT; /* Still running. */ - } - else - { - process->terminated = 1; - process->wstatus = status; - ec = 0; - } - - return ec; -} - -void -gnupg_process_release (gnupg_process_t process) -{ - if (!process) - return; - - if (!process->terminated) - { - gnupg_process_terminate (process); - gnupg_process_wait (process, 1); - } - - xfree (process); -} - -gpg_err_code_t -gnupg_process_wait_list (gnupg_process_t *process_list, int count, int hang) -{ - gpg_err_code_t ec = 0; - int i; - - for (i = 0; i < count; i++) - { - if (process_list[i]->terminated) - continue; - - ec = gnupg_process_wait (process_list[i], hang); - if (ec) - break; - } - - return ec; -} diff --git a/common/exechelp-w32.c b/common/exechelp-w32.c index 46fb9ae92..51d6920bd 100644 --- a/common/exechelp-w32.c +++ b/common/exechelp-w32.c @@ -184,77 +184,6 @@ get_all_open_fds (void) return array; } - -/* Helper function to build_w32_commandline. */ -static char * -build_w32_commandline_copy (char *buffer, const char *string) -{ - char *p = buffer; - const char *s; - - if (!*string) /* Empty string. */ - p = stpcpy (p, "\"\""); - else if (strpbrk (string, " \t\n\v\f\"")) - { - /* Need to do some kind of quoting. */ - p = stpcpy (p, "\""); - for (s=string; *s; s++) - { - *p++ = *s; - if (*s == '\"') - *p++ = *s; - } - *p++ = '\"'; - *p = 0; - } - else - p = stpcpy (p, string); - - return p; -} - -/* Build a command line for use with W32's CreateProcess. On success - CMDLINE gets the address of a newly allocated string. */ -static gpg_error_t -build_w32_commandline (const char *pgmname, const char * const *argv, - char **cmdline) -{ - int i, n; - const char *s; - char *buf, *p; - - *cmdline = NULL; - n = 0; - s = pgmname; - n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */ - for (; *s; s++) - if (*s == '\"') - n++; /* Need to double inner quotes. */ - for (i=0; (s=argv[i]); i++) - { - n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */ - for (; *s; s++) - if (*s == '\"') - n++; /* Need to double inner quotes. */ - } - n++; - - buf = p = xtrymalloc (n); - if (!buf) - return my_error_from_syserror (); - - p = build_w32_commandline_copy (p, pgmname); - for (i=0; argv[i]; i++) - { - *p++ = ' '; - p = build_w32_commandline_copy (p, argv[i]); - } - - *cmdline= buf; - return 0; -} - - #define INHERIT_READ 1 #define INHERIT_WRITE 2 #define INHERIT_BOTH (INHERIT_READ|INHERIT_WRITE) @@ -293,21 +222,6 @@ create_inheritable_pipe (HANDLE filedes[2], int flags) } -static HANDLE -w32_open_null (int for_write) -{ - HANDLE hfile; - - hfile = CreateFileW (L"nul", - for_write? GENERIC_WRITE : GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, 0, NULL); - if (hfile == INVALID_HANDLE_VALUE) - log_debug ("can't open 'nul': %s\n", w32_strerror (-1)); - return hfile; -} - - static gpg_error_t create_pipe_and_estream (int filedes[2], int flags, estream_t *r_fp, int outbound, int nonblock) @@ -408,891 +322,3 @@ gnupg_close_pipe (int fd) if (fd != -1) close (fd); } - -struct gnupg_spawn_actions { - void *hd[3]; - void **inherit_hds; - char *env; -}; - -struct gnupg_process { - const char *pgmname; - unsigned int terminated :1; /* or detached */ - unsigned int flags; - HANDLE hProcess; - HANDLE hd_in; - HANDLE hd_out; - HANDLE hd_err; - int exitcode; -}; - -static int gnupg_process_syscall_func_initialized; - -/* Functions called before and after blocking syscalls. */ -static void (*pre_syscall_func) (void); -static void (*post_syscall_func) (void); - -static void -check_syscall_func (void) -{ - if (!gnupg_process_syscall_func_initialized) - { - gpgrt_get_syscall_clamp (&pre_syscall_func, &post_syscall_func); - gnupg_process_syscall_func_initialized = 1; - } -} - - -static void -pre_syscall (void) -{ - if (pre_syscall_func) - pre_syscall_func (); -} - - -static void -post_syscall (void) -{ - if (post_syscall_func) - post_syscall_func (); -} - - -/* - * Check if STARTUPINFOEXW supports PROC_THREAD_ATTRIBUTE_HANDLE_LIST. - */ -static int -check_windows_version (void) -{ - static int is_vista_or_later = -1; - - OSVERSIONINFO osvi; - - if (is_vista_or_later == -1) - { - memset (&osvi,0,sizeof(osvi)); - osvi.dwOSVersionInfoSize = sizeof(osvi); - GetVersionEx (&osvi); - - /* The feature is available on Vista or later. */ - is_vista_or_later = (osvi.dwMajorVersion >= 6); - } - - return is_vista_or_later; -} - - -static gpg_err_code_t -spawn_detached (const char *pgmname, char *cmdline, gnupg_spawn_actions_t act) -{ - SECURITY_ATTRIBUTES sec_attr; - PROCESS_INFORMATION pi = { NULL, 0, 0, 0 }; - STARTUPINFOEXW si; - int cr_flags; - wchar_t *wcmdline = NULL; - wchar_t *wpgmname = NULL; - gpg_err_code_t ec; - int ret; - BOOL ask_inherit = FALSE; - int i; - - ec = gnupg_access (pgmname, X_OK); - if (ec) - { - xfree (cmdline); - return ec; - } - - memset (&si, 0, sizeof si); - - i = 0; - if (act->hd[0] != INVALID_HANDLE_VALUE) - i++; - if (act->hd[1] != INVALID_HANDLE_VALUE) - i++; - if (act->hd[2] != INVALID_HANDLE_VALUE) - i++; - - if (i != 0 || act->inherit_hds) - { - SIZE_T attr_list_size = 0; - HANDLE hd[16]; - HANDLE *hd_p = act->inherit_hds; - int j = 0; - - if (act->hd[0] != INVALID_HANDLE_VALUE) - hd[j++] = act->hd[0]; - if (act->hd[1] != INVALID_HANDLE_VALUE) - hd[j++] = act->hd[1]; - if (act->hd[1] != INVALID_HANDLE_VALUE) - hd[j++] = act->hd[2]; - if (hd_p) - { - while (*hd_p != INVALID_HANDLE_VALUE) - if (j < DIM (hd)) - hd[j++] = *hd_p++; - else - { - log_error ("Too much handles\n"); - break; - } - } - - if (j) - { - if (check_windows_version ()) - { - InitializeProcThreadAttributeList (NULL, 1, 0, &attr_list_size); - si.lpAttributeList = xtrymalloc (attr_list_size); - if (si.lpAttributeList == NULL) - { - xfree (cmdline); - return gpg_err_code_from_syserror (); - } - InitializeProcThreadAttributeList (si.lpAttributeList, 1, 0, - &attr_list_size); - UpdateProcThreadAttribute (si.lpAttributeList, 0, - PROC_THREAD_ATTRIBUTE_HANDLE_LIST, - hd, sizeof (HANDLE) * j, NULL, NULL); - } - - ask_inherit = TRUE; - } - } - - /* Prepare security attributes. */ - memset (&sec_attr, 0, sizeof sec_attr ); - sec_attr.nLength = sizeof sec_attr; - sec_attr.bInheritHandle = FALSE; - - /* Start the process. */ - si.StartupInfo.cb = sizeof (si); - si.StartupInfo.dwFlags = ((i > 0 ? STARTF_USESTDHANDLES : 0) - | STARTF_USESHOWWINDOW); - si.StartupInfo.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE; - - cr_flags = (CREATE_DEFAULT_ERROR_MODE - | GetPriorityClass (GetCurrentProcess ()) - | CREATE_NEW_PROCESS_GROUP - | DETACHED_PROCESS); - - /* Take care: CreateProcessW may modify wpgmname */ - if (!(wpgmname = utf8_to_wchar (pgmname))) - ret = 0; - else if (!(wcmdline = utf8_to_wchar (cmdline))) - ret = 0; - else - ret = CreateProcessW (wpgmname, /* Program to start. */ - wcmdline, /* Command line arguments. */ - &sec_attr, /* Process security attributes. */ - &sec_attr, /* Thread security attributes. */ - ask_inherit, /* Inherit handles. */ - cr_flags, /* Creation flags. */ - act->env, /* Environment. */ - NULL, /* Use current drive/directory. */ - (STARTUPINFOW *)&si, /* Startup information. */ - &pi /* Returns process information. */ - ); - if (!ret) - { - if (!wpgmname || !wcmdline) - log_error ("CreateProcess failed (utf8_to_wchar): %s\n", - strerror (errno)); - else - log_error ("CreateProcess(detached) failed: %d\n", - (int)GetLastError ()); - xfree (wpgmname); - xfree (wcmdline); - xfree (cmdline); - return GPG_ERR_GENERAL; - } - if (si.lpAttributeList) - DeleteProcThreadAttributeList (si.lpAttributeList); - xfree (wpgmname); - xfree (wcmdline); - xfree (cmdline); - - /* log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */ - /* " dwProcessID=%d dwThreadId=%d\n", */ - /* pi.hProcess, pi.hThread, */ - /* (int) pi.dwProcessId, (int) pi.dwThreadId); */ - - /* Note: AllowSetForegroundWindow doesn't make sense for background - process. */ - - CloseHandle (pi.hThread); - CloseHandle (pi.hProcess); - return 0; -} - - -gpg_err_code_t -gnupg_spawn_actions_new (gnupg_spawn_actions_t *r_act) -{ - gnupg_spawn_actions_t act; - int i; - - *r_act = NULL; - - act = xtrycalloc (1, sizeof (struct gnupg_spawn_actions)); - if (act == NULL) - return gpg_err_code_from_syserror (); - - for (i = 0; i <= 2; i++) - act->hd[i] = INVALID_HANDLE_VALUE; - - *r_act = act; - return 0; -} - -void -gnupg_spawn_actions_release (gnupg_spawn_actions_t act) -{ - if (!act) - return; - - xfree (act); -} - -void -gnupg_spawn_actions_set_envvars (gnupg_spawn_actions_t act, char *env) -{ - act->env = env; -} - -void -gnupg_spawn_actions_set_redirect (gnupg_spawn_actions_t act, - void *in, void *out, void *err) -{ - act->hd[0] = in; - act->hd[1] = out; - act->hd[2] = err; -} - -void -gnupg_spawn_actions_set_inherit_handles (gnupg_spawn_actions_t act, - void **handles) -{ - act->inherit_hds = handles; -} - - -gpg_err_code_t -gnupg_process_spawn (const char *pgmname, const char *argv[], - unsigned int flags, gnupg_spawn_actions_t act, - gnupg_process_t *r_process) -{ - gpg_err_code_t ec; - gnupg_process_t process; - SECURITY_ATTRIBUTES sec_attr; - PROCESS_INFORMATION pi = { NULL, 0, 0, 0 }; - STARTUPINFOEXW si; - int cr_flags; - char *cmdline; - wchar_t *wcmdline = NULL; - wchar_t *wpgmname = NULL; - int ret; - HANDLE hd_in[2]; - HANDLE hd_out[2]; - HANDLE hd_err[2]; - int i; - BOOL ask_inherit = FALSE; - BOOL allow_foreground_window = FALSE; - struct gnupg_spawn_actions act_default; - - if (!act) - { - memset (&act_default, 0, sizeof (act_default)); - for (i = 0; i <= 2; i++) - act_default.hd[i] = INVALID_HANDLE_VALUE; - act = &act_default; - } - - check_syscall_func (); - - /* Build the command line. */ - ec = build_w32_commandline (pgmname, argv, &cmdline); - if (ec) - return ec; - - if ((flags & GNUPG_PROCESS_DETACHED)) - { - if ((flags & GNUPG_PROCESS_STDFDS_SETTING)) - { - xfree (cmdline); - return GPG_ERR_INV_FLAG; - } - - /* In detached case, it must be no R_PROCESS. */ - if (r_process) - { - xfree (cmdline); - return GPG_ERR_INV_ARG; - } - - return spawn_detached (pgmname, cmdline, act); - } - - if (r_process) - *r_process = NULL; - - process = xtrymalloc (sizeof (struct gnupg_process)); - if (process == NULL) - { - xfree (cmdline); - return gpg_err_code_from_syserror (); - } - - process->pgmname = pgmname; - process->flags = flags; - - if ((flags & GNUPG_PROCESS_STDINOUT_SOCKETPAIR)) - { - xfree (process); - xfree (cmdline); - return GPG_ERR_NOT_SUPPORTED; - } - - if ((flags & GNUPG_PROCESS_STDIN_PIPE)) - { - ec = create_inheritable_pipe (hd_in, INHERIT_READ); - if (ec) - { - xfree (process); - xfree (cmdline); - return ec; - } - } - else if ((flags & GNUPG_PROCESS_STDIN_KEEP)) - { - hd_in[0] = GetStdHandle (STD_INPUT_HANDLE); - hd_in[1] = INVALID_HANDLE_VALUE; - } - else - { - hd_in[0] = w32_open_null (0); - hd_in[1] = INVALID_HANDLE_VALUE; - } - - if ((flags & GNUPG_PROCESS_STDOUT_PIPE)) - { - ec = create_inheritable_pipe (hd_out, INHERIT_WRITE); - if (ec) - { - if (hd_in[0] != INVALID_HANDLE_VALUE) - CloseHandle (hd_in[0]); - if (hd_in[1] != INVALID_HANDLE_VALUE) - CloseHandle (hd_in[1]); - xfree (process); - xfree (cmdline); - return ec; - } - } - else if ((flags & GNUPG_PROCESS_STDOUT_KEEP)) - { - hd_out[0] = INVALID_HANDLE_VALUE; - hd_out[1] = GetStdHandle (STD_OUTPUT_HANDLE); - } - else - { - hd_out[0] = INVALID_HANDLE_VALUE; - hd_out[1] = w32_open_null (1); - } - - if ((flags & GNUPG_PROCESS_STDERR_PIPE)) - { - ec = create_inheritable_pipe (hd_err, INHERIT_WRITE); - if (ec) - { - if (hd_in[0] != INVALID_HANDLE_VALUE) - CloseHandle (hd_in[0]); - if (hd_in[1] != INVALID_HANDLE_VALUE) - CloseHandle (hd_in[1]); - if (hd_out[0] != INVALID_HANDLE_VALUE) - CloseHandle (hd_out[0]); - if (hd_out[1] != INVALID_HANDLE_VALUE) - CloseHandle (hd_out[1]); - xfree (process); - xfree (cmdline); - return ec; - } - } - else if ((flags & GNUPG_PROCESS_STDERR_KEEP)) - { - hd_err[0] = INVALID_HANDLE_VALUE; - hd_err[1] = GetStdHandle (STD_ERROR_HANDLE); - } - else - { - hd_err[0] = INVALID_HANDLE_VALUE; - hd_err[1] = w32_open_null (1); - } - - memset (&si, 0, sizeof si); - - if (act->hd[0] == INVALID_HANDLE_VALUE) - act->hd[0] = hd_in[0]; - if (act->hd[1] == INVALID_HANDLE_VALUE) - act->hd[1] = hd_out[1]; - if (act->hd[2] == INVALID_HANDLE_VALUE) - act->hd[2] = hd_err[1]; - - i = 0; - if (act->hd[0] != INVALID_HANDLE_VALUE) - i++; - if (act->hd[1] != INVALID_HANDLE_VALUE) - i++; - if (act->hd[2] != INVALID_HANDLE_VALUE) - i++; - - if (i != 0 || act->inherit_hds) - { - SIZE_T attr_list_size = 0; - HANDLE hd[16]; - HANDLE *hd_p = act->inherit_hds; - int j = 0; - - if (act->hd[0] != INVALID_HANDLE_VALUE) - hd[j++] = act->hd[0]; - if (act->hd[1] != INVALID_HANDLE_VALUE) - hd[j++] = act->hd[1]; - if (act->hd[1] != INVALID_HANDLE_VALUE) - hd[j++] = act->hd[2]; - if (hd_p) - { - while (*hd_p != INVALID_HANDLE_VALUE) - if (j < DIM (hd)) - hd[j++] = *hd_p++; - else - { - log_error ("Too much handles\n"); - break; - } - } - - if (j) - { - if (check_windows_version ()) - { - InitializeProcThreadAttributeList (NULL, 1, 0, &attr_list_size); - si.lpAttributeList = xtrymalloc (attr_list_size); - if (si.lpAttributeList == NULL) - { - if ((flags & GNUPG_PROCESS_STDIN_PIPE) - || !(flags & GNUPG_PROCESS_STDIN_KEEP)) - CloseHandle (hd_in[0]); - if ((flags & GNUPG_PROCESS_STDIN_PIPE)) - CloseHandle (hd_in[1]); - if ((flags & GNUPG_PROCESS_STDOUT_PIPE)) - CloseHandle (hd_out[0]); - if ((flags & GNUPG_PROCESS_STDOUT_PIPE) - || !(flags & GNUPG_PROCESS_STDOUT_KEEP)) - CloseHandle (hd_out[1]); - if ((flags & GNUPG_PROCESS_STDERR_PIPE)) - CloseHandle (hd_err[0]); - if ((flags & GNUPG_PROCESS_STDERR_PIPE) - || !(flags & GNUPG_PROCESS_STDERR_KEEP)) - CloseHandle (hd_err[1]); - xfree (process); - xfree (cmdline); - return gpg_err_code_from_syserror (); - } - InitializeProcThreadAttributeList (si.lpAttributeList, 1, 0, - &attr_list_size); - UpdateProcThreadAttribute (si.lpAttributeList, 0, - PROC_THREAD_ATTRIBUTE_HANDLE_LIST, - hd, sizeof (HANDLE) * j, NULL, NULL); - } - ask_inherit = TRUE; - } - } - - /* Prepare security attributes. */ - memset (&sec_attr, 0, sizeof sec_attr ); - sec_attr.nLength = sizeof sec_attr; - sec_attr.bInheritHandle = FALSE; - - /* Start the process. */ - si.StartupInfo.cb = sizeof (si); - si.StartupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - si.StartupInfo.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_HIDE; - si.StartupInfo.hStdInput = act->hd[0]; - si.StartupInfo.hStdOutput = act->hd[1]; - si.StartupInfo.hStdError = act->hd[2]; - - /* log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline); */ - cr_flags = (CREATE_DEFAULT_ERROR_MODE - | GetPriorityClass (GetCurrentProcess ()) - | CREATE_SUSPENDED); - if (!(wpgmname = utf8_to_wchar (pgmname))) - ret = 0; - else if (!(wcmdline = utf8_to_wchar (cmdline))) - ret = 0; - else - ret = CreateProcessW (wpgmname, /* Program to start. */ - wcmdline, /* Command line arguments. */ - &sec_attr, /* Process security attributes. */ - &sec_attr, /* Thread security attributes. */ - ask_inherit, /* Inherit handles. */ - cr_flags, /* Creation flags. */ - act->env, /* Environment. */ - NULL, /* Use current drive/directory. */ - (STARTUPINFOW *)&si, /* Startup information. */ - &pi /* Returns process information. */ - ); - if (!ret) - { - if (!wpgmname || !wcmdline) - log_error ("CreateProcess failed (utf8_to_wchar): %s\n", - strerror (errno)); - else - log_error ("CreateProcess failed: ec=%d\n", - (int)GetLastError ()); - if ((flags & GNUPG_PROCESS_STDIN_PIPE) - || !(flags & GNUPG_PROCESS_STDIN_KEEP)) - CloseHandle (hd_in[0]); - if ((flags & GNUPG_PROCESS_STDIN_PIPE)) - CloseHandle (hd_in[1]); - if ((flags & GNUPG_PROCESS_STDOUT_PIPE)) - CloseHandle (hd_out[0]); - if ((flags & GNUPG_PROCESS_STDOUT_PIPE) - || !(flags & GNUPG_PROCESS_STDOUT_KEEP)) - CloseHandle (hd_out[1]); - if ((flags & GNUPG_PROCESS_STDERR_PIPE)) - CloseHandle (hd_err[0]); - if ((flags & GNUPG_PROCESS_STDERR_PIPE) - || !(flags & GNUPG_PROCESS_STDERR_KEEP)) - CloseHandle (hd_err[1]); - xfree (wpgmname); - xfree (wcmdline); - xfree (process); - xfree (cmdline); - return GPG_ERR_GENERAL; - } - - if (si.lpAttributeList) - DeleteProcThreadAttributeList (si.lpAttributeList); - xfree (wpgmname); - xfree (wcmdline); - xfree (cmdline); - - if ((flags & GNUPG_PROCESS_STDIN_PIPE) - || !(flags & GNUPG_PROCESS_STDIN_KEEP)) - CloseHandle (hd_in[0]); - if ((flags & GNUPG_PROCESS_STDOUT_PIPE) - || !(flags & GNUPG_PROCESS_STDOUT_KEEP)) - CloseHandle (hd_out[1]); - if ((flags & GNUPG_PROCESS_STDERR_PIPE) - || !(flags & GNUPG_PROCESS_STDERR_KEEP)) - CloseHandle (hd_err[1]); - - /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */ - /* " dwProcessID=%d dwThreadId=%d\n", */ - /* pi.hProcess, pi.hThread, */ - /* (int) pi.dwProcessId, (int) pi.dwThreadId); */ - - if (allow_foreground_window) - { - /* Fixme: For unknown reasons AllowSetForegroundWindow returns - * an invalid argument error if we pass it the correct - * processID. As a workaround we use -1 (ASFW_ANY). */ - if (!AllowSetForegroundWindow (ASFW_ANY /*pi.dwProcessId*/)) - log_info ("AllowSetForegroundWindow() failed: ec=%d\n", - (int)GetLastError ()); - } - - /* Process has been created suspended; resume it now. */ - pre_syscall (); - ResumeThread (pi.hThread); - CloseHandle (pi.hThread); - post_syscall (); - - process->hProcess = pi.hProcess; - process->hd_in = hd_in[1]; - process->hd_out = hd_out[0]; - process->hd_err = hd_err[0]; - process->exitcode = -1; - process->terminated = 0; - - if (r_process == NULL) - { - ec = gnupg_process_wait (process, 1); - gnupg_process_release (process); - return ec; - } - - *r_process = process; - return 0; -} - -gpg_err_code_t -gnupg_process_get_fds (gnupg_process_t process, unsigned int flags, - int *r_fd_in, int *r_fd_out, int *r_fd_err) -{ - (void)flags; - if (r_fd_in) - { - *r_fd_in = _open_osfhandle ((intptr_t)process->hd_in, O_APPEND); - process->hd_in = INVALID_HANDLE_VALUE; - } - if (r_fd_out) - { - *r_fd_out = _open_osfhandle ((intptr_t)process->hd_out, O_RDONLY); - process->hd_out = INVALID_HANDLE_VALUE; - } - if (r_fd_err) - { - *r_fd_err = _open_osfhandle ((intptr_t)process->hd_err, O_RDONLY); - process->hd_err = INVALID_HANDLE_VALUE; - } - - return 0; -} - -gpg_err_code_t -gnupg_process_get_streams (gnupg_process_t process, unsigned int flags, - estream_t *r_fp_in, estream_t *r_fp_out, - estream_t *r_fp_err) -{ - int nonblock = (flags & GNUPG_PROCESS_STREAM_NONBLOCK)? 1: 0; - es_syshd_t syshd; - - syshd.type = ES_SYSHD_HANDLE; - if (r_fp_in) - { - syshd.u.handle = process->hd_in; - *r_fp_in = es_sysopen (&syshd, nonblock? "w,nonblock" : "w"); - process->hd_in = INVALID_HANDLE_VALUE; - } - if (r_fp_out) - { - syshd.u.handle = process->hd_out; - *r_fp_out = es_sysopen (&syshd, nonblock? "r,nonblock" : "r"); - process->hd_out = INVALID_HANDLE_VALUE; - } - if (r_fp_err) - { - syshd.u.handle = process->hd_err; - *r_fp_err = es_sysopen (&syshd, nonblock? "r,nonblock" : "r"); - process->hd_err = INVALID_HANDLE_VALUE; - } - return 0; -} - -static gpg_err_code_t -process_kill (gnupg_process_t process, unsigned int exitcode) -{ - gpg_err_code_t ec = 0; - - pre_syscall (); - if (TerminateProcess (process->hProcess, exitcode)) - ec = gpg_err_code_from_syserror (); - post_syscall (); - return ec; -} - -static gpg_err_code_t -process_vctl (gnupg_process_t process, unsigned int request, va_list arg_ptr) -{ - switch (request) - { - case GNUPG_PROCESS_NOP: - return 0; - - case GNUPG_PROCESS_GET_PROC_ID: - { - int *r_id = va_arg (arg_ptr, int *); - - if (r_id == NULL) - return GPG_ERR_INV_VALUE; - - *r_id = (int)GetProcessId (process->hProcess); - return 0; - } - - case GNUPG_PROCESS_GET_EXIT_ID: - { - int *r_exit_status = va_arg (arg_ptr, int *); - unsigned long exit_code; - - *r_exit_status = -1; - - if (!process->terminated) - return GPG_ERR_UNFINISHED; - - if (process->hProcess == INVALID_HANDLE_VALUE) - return 0; - - if (GetExitCodeProcess (process->hProcess, &exit_code) == 0) - return gpg_err_code_from_syserror (); - - *r_exit_status = (int)exit_code; - return 0; - } - - case GNUPG_PROCESS_GET_P_HANDLE: - { - HANDLE *r_hProcess = va_arg (arg_ptr, HANDLE *); - - if (r_hProcess == NULL) - return GPG_ERR_INV_VALUE; - - *r_hProcess = process->hProcess; - process->hProcess = INVALID_HANDLE_VALUE; - return 0; - } - - case GNUPG_PROCESS_GET_HANDLES: - { - HANDLE *r_hd_in = va_arg (arg_ptr, HANDLE *); - HANDLE *r_hd_out = va_arg (arg_ptr, HANDLE *); - HANDLE *r_hd_err = va_arg (arg_ptr, HANDLE *); - - if (r_hd_in) - { - *r_hd_in = process->hd_in; - process->hd_in = INVALID_HANDLE_VALUE; - } - if (r_hd_out) - { - *r_hd_out = process->hd_out; - process->hd_out = INVALID_HANDLE_VALUE; - } - if (r_hd_err) - { - *r_hd_err = process->hd_err; - process->hd_err = INVALID_HANDLE_VALUE; - } - return 0; - } - - case GNUPG_PROCESS_GET_EXIT_CODE: - { - unsigned long *r_exitcode = va_arg (arg_ptr, unsigned long *); - - if (!process->terminated) - return GPG_ERR_UNFINISHED; - - if (process->hProcess == INVALID_HANDLE_VALUE) - { - *r_exitcode = (unsigned long)-1; - return 0; - } - - if (GetExitCodeProcess (process->hProcess, r_exitcode) == 0) - return gpg_err_code_from_syserror (); - return 0; - } - - case GNUPG_PROCESS_KILL_WITH_EC: - { - unsigned int exitcode = va_arg (arg_ptr, unsigned int); - - if (process->terminated) - return 0; - - if (process->hProcess == INVALID_HANDLE_VALUE) - return 0; - - return process_kill (process, exitcode); - } - - default: - break; - } - - return GPG_ERR_UNKNOWN_COMMAND; -} - -gpg_err_code_t -gnupg_process_ctl (gnupg_process_t process, unsigned int request, ...) -{ - va_list arg_ptr; - gpg_err_code_t ec; - - va_start (arg_ptr, request); - ec = process_vctl (process, request, arg_ptr); - va_end (arg_ptr); - return ec; -} - -gpg_err_code_t -gnupg_process_wait (gnupg_process_t process, int hang) -{ - gpg_err_code_t ec; - int code; - - if (process->hProcess == INVALID_HANDLE_VALUE) - return 0; - - pre_syscall (); - code = WaitForSingleObject (process->hProcess, hang? INFINITE : 0); - post_syscall (); - - switch (code) - { - case WAIT_TIMEOUT: - ec = GPG_ERR_TIMEOUT; /* Still running. */ - break; - - case WAIT_FAILED: - log_error (_("waiting for process to terminate failed: ec=%d\n"), - (int)GetLastError ()); - ec = GPG_ERR_GENERAL; - break; - - case WAIT_OBJECT_0: - process->terminated = 1; - ec = 0; - break; - - default: - log_debug ("WaitForSingleObject returned unexpected code %d\n", code); - ec = GPG_ERR_GENERAL; - break; - } - - return ec; -} - -gpg_err_code_t -gnupg_process_terminate (gnupg_process_t process) -{ - return process_kill (process, 1); -} - -void -gnupg_process_release (gnupg_process_t process) -{ - if (!process) - return; - - if (!process->terminated) - { - gnupg_process_terminate (process); - gnupg_process_wait (process, 1); - } - - CloseHandle (process->hProcess); - xfree (process); -} - -gpg_err_code_t -gnupg_process_wait_list (gnupg_process_t *process_list, int count, int hang) -{ - gpg_err_code_t ec = 0; - int i; - - for (i = 0; i < count; i++) - { - if (process_list[i]->terminated) - continue; - - ec = gnupg_process_wait (process_list[i], hang); - if (ec) - break; - } - - return ec; -} diff --git a/common/exechelp.h b/common/exechelp.h index 93ba12eeb..be7119357 100644 --- a/common/exechelp.h +++ b/common/exechelp.h @@ -72,99 +72,4 @@ gpg_error_t gnupg_create_pipe (int filedes[2]); /* Close the end of a pipe. */ void gnupg_close_pipe (int fd); - -/* The opaque type for a subprocess. */ -typedef struct gnupg_process *gnupg_process_t; -typedef struct gnupg_spawn_actions *gnupg_spawn_actions_t; -gpg_err_code_t gnupg_spawn_actions_new (gnupg_spawn_actions_t *r_act); -void gnupg_spawn_actions_release (gnupg_spawn_actions_t act); -#ifdef HAVE_W32_SYSTEM -void gnupg_spawn_actions_set_envvars (gnupg_spawn_actions_t, char *); -void gnupg_spawn_actions_set_redirect (gnupg_spawn_actions_t, - void *, void *, void *); -void gnupg_spawn_actions_set_inherit_handles (gnupg_spawn_actions_t, void **); -#else -void gnupg_spawn_actions_set_environ (gnupg_spawn_actions_t, char **); -void gnupg_spawn_actions_set_redirect (gnupg_spawn_actions_t, int, int, int); -void gnupg_spawn_actions_set_inherit_fds (gnupg_spawn_actions_t, - const int *); -void gnupg_spawn_actions_set_atfork (gnupg_spawn_actions_t, - void (*atfork)(void *), void *arg); -#endif - -#define GNUPG_PROCESS_DETACHED (1 << 1) - -/* Specify how to keep/connect standard fds. */ -#define GNUPG_PROCESS_STDIN_PIPE (1 << 8) -#define GNUPG_PROCESS_STDOUT_PIPE (1 << 9) -#define GNUPG_PROCESS_STDERR_PIPE (1 << 10) -#define GNUPG_PROCESS_STDINOUT_SOCKETPAIR (1 << 11) -#define GNUPG_PROCESS_STDIN_KEEP (1 << 12) -#define GNUPG_PROCESS_STDOUT_KEEP (1 << 13) -#define GNUPG_PROCESS_STDERR_KEEP (1 << 14) -#define GNUPG_PROCESS_STDFDS_SETTING ( GNUPG_PROCESS_STDIN_PIPE \ - | GNUPG_PROCESS_STDOUT_PIPE | GNUPG_PROCESS_STDERR_PIPE \ - | GNUPG_PROCESS_STDINOUT_SOCKETPAIR | GNUPG_PROCESS_STDIN_KEEP \ - | GNUPG_PROCESS_STDOUT_KEEP | GNUPG_PROCESS_STDERR_KEEP) - -#define GNUPG_PROCESS_STREAM_NONBLOCK (1 << 16) - -/* Spawn PGMNAME. */ -gpg_err_code_t gnupg_process_spawn (const char *pgmname, const char *argv1[], - unsigned int flags, - gnupg_spawn_actions_t act, - gnupg_process_t *r_process); - -/* Get FDs for subprocess I/O. It is the caller which should care - FDs (closing FDs). */ -gpg_err_code_t gnupg_process_get_fds (gnupg_process_t process, - unsigned int flags, - int *r_fd_in, int *r_fd_out, - int *r_fd_err); - -/* Get STREAMs for subprocess I/O. It is the caller which should care - STREAMs (closing STREAMs). */ -gpg_err_code_t gnupg_process_get_streams (gnupg_process_t process, - unsigned int flags, - gpgrt_stream_t *r_fp_in, - gpgrt_stream_t *r_fp_out, - gpgrt_stream_t *r_fp_err); - -enum gnupg_process_requests - { - /* Portable requests */ - GNUPG_PROCESS_NOP = 0, - GNUPG_PROCESS_GET_PROC_ID = 1, - GNUPG_PROCESS_GET_EXIT_ID = 2, - - /* POSIX only */ - GNUPG_PROCESS_GET_PID = 16, - GNUPG_PROCESS_GET_WSTATUS = 17, - GNUPG_PROCESS_KILL = 18, - - /* Windows only */ - GNUPG_PROCESS_GET_P_HANDLE = 32, - GNUPG_PROCESS_GET_HANDLES = 33, - GNUPG_PROCESS_GET_EXIT_CODE = 34, - GNUPG_PROCESS_KILL_WITH_EC = 35 - }; - -/* Control of a process. */ -gpg_err_code_t gnupg_process_ctl (gnupg_process_t process, - unsigned int request, ...); - -/* Wait for a single PROCESS. */ -gpg_err_code_t gnupg_process_wait (gnupg_process_t process, int hang); - -/* Terminate a PROCESS. */ -gpg_err_code_t gnupg_process_terminate (gnupg_process_t process); - -/* Release PROCESS resources. */ -void gnupg_process_release (gnupg_process_t process); - -/* Wait for a multiple processes. */ -gpg_err_code_t gnupg_process_wait_list (gnupg_process_t *process_list, - int count, int hang); - - #endif /*GNUPG_COMMON_EXECHELP_H*/ diff --git a/common/exectool.c b/common/exectool.c index ce424fc49..bb867fbc3 100644 --- a/common/exectool.c +++ b/common/exectool.c @@ -43,11 +43,8 @@ #include "logging.h" #include "membuf.h" #include "mischelp.h" -#ifdef HAVE_W32_SYSTEM -#define NEED_STRUCT_SPAWN_CB_ARG 1 -#endif -#include "exechelp.h" #include "sysutils.h" +#include "exechelp.h" #include "util.h" #include "exectool.h" @@ -324,7 +321,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[], void *status_cb_value) { gpg_error_t err; - gnupg_process_t proc = NULL; + gpgrt_process_t proc = NULL; estream_t infp = NULL; estream_t extrafp = NULL; estream_t outfp = NULL, errfp = NULL; @@ -342,7 +339,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[], read_and_log_buffer_t fderrstate; struct copy_buffer *cpbuf_in = NULL, *cpbuf_out = NULL, *cpbuf_extra = NULL; int quiet = 0; - gnupg_spawn_actions_t act = NULL; + gpgrt_spawn_actions_t act = NULL; int i = 0; memset (fds, 0, sizeof fds); @@ -433,22 +430,22 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[], exceptclose[i] = -1; #endif - err = gnupg_spawn_actions_new (&act); + err = gpgrt_spawn_actions_new (&act); if (err) goto leave; #ifdef HAVE_W32_SYSTEM - gnupg_spawn_actions_set_inherit_handles (act, exceptclose); + gpgrt_spawn_actions_set_inherit_handles (act, exceptclose); #else - gnupg_spawn_actions_set_inherit_fds (act, exceptclose); + gpgrt_spawn_actions_set_inherit_fds (act, exceptclose); #endif - err = gnupg_process_spawn (pgmname, argv, + err = gpgrt_process_spawn (pgmname, argv, ((input - ? GNUPG_PROCESS_STDIN_PIPE + ? GPGRT_PROCESS_STDIN_PIPE : 0) - | GNUPG_PROCESS_STDOUT_PIPE - | GNUPG_PROCESS_STDERR_PIPE), act, &proc); - gnupg_process_get_streams (proc, GNUPG_PROCESS_STREAM_NONBLOCK, + | GPGRT_PROCESS_STDOUT_PIPE + | GPGRT_PROCESS_STDERR_PIPE), act, &proc); + gpgrt_process_get_streams (proc, GPGRT_PROCESS_STREAM_NONBLOCK, input? &infp : NULL, &outfp, &errfp); if (extrapipe[0] != -1) close (extrapipe[0]); @@ -581,26 +578,26 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[], es_fclose (outfp); outfp = NULL; es_fclose (errfp); errfp = NULL; - err = gnupg_process_wait (proc, 1); + err = gpgrt_process_wait (proc, 1); if (!err) { /* To be compatible to old wait_process. */ int status; - gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &status); + gpgrt_process_ctl (proc, GPGRT_PROCESS_GET_EXIT_ID, &status); if (status) err = gpg_error (GPG_ERR_GENERAL); } leave: if (err && proc) - gnupg_process_terminate (proc); + gpgrt_process_terminate (proc); es_fclose (infp); es_fclose (extrafp); es_fclose (outfp); es_fclose (errfp); - gnupg_process_release (proc); - gnupg_spawn_actions_release (act); + gpgrt_process_release (proc); + gpgrt_spawn_actions_release (act); copy_buffer_shred (cpbuf_in); xfree (cpbuf_in); diff --git a/common/t-exechelp.c b/common/t-exechelp.c index f25c91d3a..b9a2e1e2c 100644 --- a/common/t-exechelp.c +++ b/common/t-exechelp.c @@ -25,6 +25,7 @@ #include <unistd.h> #include "util.h" +#include "sysutils.h" #include "exechelp.h" static int verbose; @@ -248,75 +249,11 @@ run_server (void) } -static void -test_pipe_stream (const char *pgmname) -{ - gpg_error_t err; - gnupg_process_t proc; - estream_t outfp; - const char *argv[2]; - unsigned int len; - size_t n; - off_t o; - int ret; - - argv[0] = "--server"; - argv[1] = NULL; - - err = gnupg_process_spawn (pgmname, argv, - (GNUPG_PROCESS_STDOUT_PIPE - |GNUPG_PROCESS_STDERR_KEEP), - NULL, &proc); - if (err) - { - fprintf (stderr, "gnupg_process_spawn failed\n"); - exit (1); - } - - gnupg_process_get_streams (proc, 0, NULL, &outfp, NULL); - - ret = es_read (outfp, (void *)&len, sizeof (len), NULL); - if (ret) - { - fprintf (stderr, "es_read (1) failed\n"); - exit (1); - } - - o = 0; - while (1) - { - if (es_feof (outfp)) - break; - - ret = es_read (outfp, buff4k, sizeof (buff4k), &n); - if (ret) - { - fprintf (stderr, "es_read (2) failed\n"); - exit (1); - } - - memcpy (buff12k + o, buff4k, n); - o += n; - } - - if (o != sizeof (buff12k)) - { - fprintf (stderr, "received data with wrong length %d\n", (int)o); - exit (1); - } - es_fclose (outfp); - gnupg_process_release (proc); -} - - int main (int argc, char **argv) { - const char *myname = "no-pgm"; - if (argc) { - myname = argv[0]; argc--; argv++; } if (argc && !strcmp (argv[0], "--verbose")) @@ -330,7 +267,6 @@ main (int argc, char **argv) #ifndef HAVE_W32_SYSTEM test_close_all_fds (); #endif - test_pipe_stream (myname); return 0; } |