Changeset View
Changeset View
Standalone View
Standalone View
b/common/exechelp.c
Context not available. | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#ifdef HAVE_STDINT_H | |||||
# include <stdint.h> | |||||
#endif | |||||
#include <string.h> | #include <string.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <assert.h> | #include <assert.h> | ||||
#include <signal.h> | #include <signal.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */ | #ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */ | ||||
Context not available. | |||||
#undef USE_GNU_PTH | #undef USE_GNU_PTH | ||||
#endif | #endif | ||||
#ifdef USE_GNU_PTH | #ifdef USE_GNU_PTH | ||||
#include <pth.h> | #include <pth.h> | ||||
#endif | #endif | ||||
#ifndef HAVE_W32_SYSTEM | #ifndef HAVE_W32_SYSTEM | ||||
Context not available. | |||||
and some are not. However we want to use pth_fork and pth_waitpid | and some are not. However we want to use pth_fork and pth_waitpid | ||||
here. Using a weak symbol works but is not portable - we should | here. Using a weak symbol works but is not portable - we should | ||||
provide a an explicit dummy pth module instead of using the | provide a an explicit dummy pth module instead of using the | ||||
pragma. */ | pragma. */ | ||||
#ifndef _WIN32 | #ifndef _WIN32 | ||||
#pragma weak pth_fork | #pragma weak pth_fork | ||||
#pragma weak pth_waitpid | #pragma weak pth_waitpid | ||||
Context not available. | |||||
if (max_fds == -1) | if (max_fds == -1) | ||||
max_fds = 256; /* Arbitrary limit. */ | max_fds = 256; /* Arbitrary limit. */ | ||||
/* AIX returns INT32_MAX instead of a proper value. We assume that | |||||
this is always an error and use an arbitrary limit. */ | |||||
#ifdef INT32_MAX | |||||
if (max_fds == INT32_MAX) | |||||
max_fds = 256; | |||||
#endif | |||||
return max_fds; | return max_fds; | ||||
} | } | ||||
Context not available. | |||||
array = calloc (narray, sizeof *array); | array = calloc (narray, sizeof *array); | ||||
if (!array) | if (!array) | ||||
return NULL; | return NULL; | ||||
/* Note: The list we return is ordered. */ | /* Note: The list we return is ordered. */ | ||||
for (idx=0, fd=0; fd < max_fd; fd++) | for (idx=0, fd=0; fd < max_fd; fd++) | ||||
if (!(fstat (fd, &statbuf) == -1 && errno == EBADF)) | if (!(fstat (fd, &statbuf) == -1 && errno == EBADF)) | ||||
Context not available. | |||||
/* Build a command line for use with W32's CreateProcess. On success | /* Build a command line for use with W32's CreateProcess. On success | ||||
CMDLINE gets the address of a newly allocated string. */ | CMDLINE gets the address of a newly allocated string. */ | ||||
static gpg_error_t | static gpg_error_t | ||||
build_w32_commandline (const char *pgmname, const char * const *argv, | build_w32_commandline (const char *pgmname, const char * const *argv, | ||||
char **cmdline) | char **cmdline) | ||||
{ | { | ||||
int i, n; | int i, n; | ||||
Context not available. | |||||
return gpg_error_from_syserror (); | return gpg_error_from_syserror (); | ||||
p = build_w32_commandline_copy (p, pgmname); | p = build_w32_commandline_copy (p, pgmname); | ||||
for (i=0; argv[i]; i++) | for (i=0; argv[i]; i++) | ||||
{ | { | ||||
*p++ = ' '; | *p++ = ' '; | ||||
p = build_w32_commandline_copy (p, argv[i]); | p = build_w32_commandline_copy (p, argv[i]); | ||||
Context not available. | |||||
memset (&sec_attr, 0, sizeof sec_attr ); | memset (&sec_attr, 0, sizeof sec_attr ); | ||||
sec_attr.nLength = sizeof sec_attr; | sec_attr.nLength = sizeof sec_attr; | ||||
sec_attr.bInheritHandle = FALSE; | sec_attr.bInheritHandle = FALSE; | ||||
if (!CreatePipe (&r, &w, &sec_attr, 0)) | if (!CreatePipe (&r, &w, &sec_attr, 0)) | ||||
return -1; | return -1; | ||||
Context not available. | |||||
/* Close all other files. */ | /* Close all other files. */ | ||||
close_all_fds (3, NULL); | close_all_fds (3, NULL); | ||||
if (preexec) | if (preexec) | ||||
preexec (); | preexec (); | ||||
execv (pgmname, arg_list); | execv (pgmname, arg_list); | ||||
Context not available. | |||||
log_error ("failed to translate osfhandle %p\n", (void*)fds[0]); | log_error ("failed to translate osfhandle %p\n", (void*)fds[0]); | ||||
CloseHandle (fd_to_handle (fds[1])); | CloseHandle (fd_to_handle (fds[1])); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
filedes[1] = _open_osfhandle (fds[1], 1); | filedes[1] = _open_osfhandle (fds[1], 1); | ||||
if (filedes[1] == -1) | if (filedes[1] == -1) | ||||
Context not available. | |||||
This flag is only useful under W32 systems, so that no new | This flag is only useful under W32 systems, so that no new | ||||
console is created and pops up a console window when | console is created and pops up a console window when | ||||
starting the server | starting the server | ||||
Bit 6: On W32 run AllowSetForegroundWindow for the child. Due to | Bit 6: On W32 run AllowSetForegroundWindow for the child. Due to | ||||
error problems this actually allows SetForegroundWindow for | error problems this actually allows SetForegroundWindow for | ||||
childs of this process. | childs of this process. | ||||
Context not available. | |||||
#ifdef HAVE_W32_SYSTEM | #ifdef HAVE_W32_SYSTEM | ||||
gpg_error_t err; | gpg_error_t err; | ||||
SECURITY_ATTRIBUTES sec_attr; | SECURITY_ATTRIBUTES sec_attr; | ||||
PROCESS_INFORMATION pi = | PROCESS_INFORMATION pi = | ||||
{ | { | ||||
NULL, /* Returns process handle. */ | NULL, /* Returns process handle. */ | ||||
0, /* Returns primary thread handle. */ | 0, /* Returns primary thread handle. */ | ||||
Context not available. | |||||
memset (&sec_attr, 0, sizeof sec_attr ); | memset (&sec_attr, 0, sizeof sec_attr ); | ||||
sec_attr.nLength = sizeof sec_attr; | sec_attr.nLength = sizeof sec_attr; | ||||
sec_attr.bInheritHandle = FALSE; | sec_attr.bInheritHandle = FALSE; | ||||
/* Build the command line. */ | /* Build the command line. */ | ||||
err = build_w32_commandline (pgmname, argv, &cmdline); | err = build_w32_commandline (pgmname, argv, &cmdline); | ||||
if (err) | if (err) | ||||
return err; | return err; | ||||
/* Create a pipe. */ | /* Create a pipe. */ | ||||
if (create_inheritable_pipe (rp)) | if (create_inheritable_pipe (rp)) | ||||
Context not available. | |||||
xfree (cmdline); | xfree (cmdline); | ||||
return err; | return err; | ||||
} | } | ||||
/* Start the process. Note that we can't run the PREEXEC function | /* Start the process. Note that we can't run the PREEXEC function | ||||
because this would change our own environment. */ | because this would change our own environment. */ | ||||
memset (&si, 0, sizeof si); | memset (&si, 0, sizeof si); | ||||
Context not available. | |||||
cr_flags = (CREATE_DEFAULT_ERROR_MODE | cr_flags = (CREATE_DEFAULT_ERROR_MODE | ||||
| ((flags & 128)? DETACHED_PROCESS : 0) | | ((flags & 128)? DETACHED_PROCESS : 0) | ||||
| GetPriorityClass (GetCurrentProcess ()) | | GetPriorityClass (GetCurrentProcess ()) | ||||
| CREATE_SUSPENDED); | | CREATE_SUSPENDED); | ||||
/* log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline); */ | /* log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline); */ | ||||
if (!CreateProcess (pgmname, /* Program to start. */ | if (!CreateProcess (pgmname, /* Program to start. */ | ||||
cmdline, /* Command line arguments. */ | cmdline, /* Command line arguments. */ | ||||
Context not available. | |||||
/* Close the other end of the pipe. */ | /* Close the other end of the pipe. */ | ||||
CloseHandle (fd_to_handle (rp[1])); | CloseHandle (fd_to_handle (rp[1])); | ||||
/* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */ | /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */ | ||||
/* " dwProcessID=%d dwThreadId=%d\n", */ | /* " dwProcessID=%d dwThreadId=%d\n", */ | ||||
/* pi.hProcess, pi.hThread, */ | /* pi.hProcess, pi.hThread, */ | ||||
/* (int) pi.dwProcessId, (int) pi.dwThreadId); */ | /* (int) pi.dwProcessId, (int) pi.dwThreadId); */ | ||||
/* Fixme: For unknown reasons AllowSetForegroundWindow returns an | /* Fixme: For unknown reasons AllowSetForegroundWindow returns an | ||||
invalid argument error if we pass the correct processID to | invalid argument error if we pass the correct processID to | ||||
it. As a workaround we use -1 (ASFW_ANY). */ | it. As a workaround we use -1 (ASFW_ANY). */ | ||||
Context not available. | |||||
/* Process has been created suspended; resume it now. */ | /* Process has been created suspended; resume it now. */ | ||||
ResumeThread (pi.hThread); | ResumeThread (pi.hThread); | ||||
CloseHandle (pi.hThread); | CloseHandle (pi.hThread); | ||||
{ | { | ||||
int x; | int x; | ||||
Context not available. | |||||
x = _open_osfhandle (rp[0], 0); | x = _open_osfhandle (rp[0], 0); | ||||
if (x == -1) | if (x == -1) | ||||
log_error ("failed to translate osfhandle %p\n", (void*)rp[0] ); | log_error ("failed to translate osfhandle %p\n", (void*)rp[0] ); | ||||
else | else | ||||
*statusfile = fdopen (x, "r"); | *statusfile = fdopen (x, "r"); | ||||
} | } | ||||
if (!*statusfile) | if (!*statusfile) | ||||
Context not available. | |||||
return err; | return err; | ||||
} | } | ||||
#ifdef USE_GNU_PTH | #ifdef USE_GNU_PTH | ||||
*pid = pth_fork? pth_fork () : fork (); | *pid = pth_fork? pth_fork () : fork (); | ||||
#else | #else | ||||
*pid = fork (); | *pid = fork (); | ||||
Context not available. | |||||
} | } | ||||
if (!*pid) | if (!*pid) | ||||
{ | { | ||||
gcry_control (GCRYCTL_TERM_SECMEM); | gcry_control (GCRYCTL_TERM_SECMEM); | ||||
/* Run child. */ | /* Run child. */ | ||||
do_exec (pgmname, argv, fd, fdout, rp[1], preexec); | do_exec (pgmname, argv, fd, fdout, rp[1], preexec); | ||||
Context not available. | |||||
memset (&sec_attr, 0, sizeof sec_attr ); | memset (&sec_attr, 0, sizeof sec_attr ); | ||||
sec_attr.nLength = sizeof sec_attr; | sec_attr.nLength = sizeof sec_attr; | ||||
sec_attr.bInheritHandle = FALSE; | sec_attr.bInheritHandle = FALSE; | ||||
/* Build the command line. */ | /* Build the command line. */ | ||||
err = build_w32_commandline (pgmname, argv, &cmdline); | err = build_w32_commandline (pgmname, argv, &cmdline); | ||||
if (err) | if (err) | ||||
return err; | return err; | ||||
memset (&si, 0, sizeof si); | memset (&si, 0, sizeof si); | ||||
si.cb = sizeof (si); | si.cb = sizeof (si); | ||||
Context not available. | |||||
/* Process has been created suspended; resume it now. */ | /* Process has been created suspended; resume it now. */ | ||||
ResumeThread (pi.hThread); | ResumeThread (pi.hThread); | ||||
CloseHandle (pi.hThread); | CloseHandle (pi.hThread); | ||||
*pid = handle_to_pid (pi.hProcess); | *pid = handle_to_pid (pi.hProcess); | ||||
return 0; | return 0; | ||||
Context not available. | |||||
#else /* !HAVE_W32_SYSTEM */ | #else /* !HAVE_W32_SYSTEM */ | ||||
gpg_error_t err; | gpg_error_t err; | ||||
#ifdef USE_GNU_PTH | #ifdef USE_GNU_PTH | ||||
*pid = pth_fork? pth_fork () : fork (); | *pid = pth_fork? pth_fork () : fork (); | ||||
#else | #else | ||||
*pid = fork (); | *pid = fork (); | ||||
Context not available. | |||||
} | } | ||||
if (!*pid) | if (!*pid) | ||||
{ | { | ||||
gcry_control (GCRYCTL_TERM_SECMEM); | gcry_control (GCRYCTL_TERM_SECMEM); | ||||
/* Run child. */ | /* Run child. */ | ||||
do_exec (pgmname, argv, infd, outfd, errfd, NULL); | do_exec (pgmname, argv, infd, outfd, errfd, NULL); | ||||
Context not available. | |||||
been implemented. A special W32 pth system call would even be | been implemented. A special W32 pth system call would even be | ||||
better. */ | better. */ | ||||
code = WaitForSingleObject (proc, INFINITE); | code = WaitForSingleObject (proc, INFINITE); | ||||
switch (code) | switch (code) | ||||
{ | { | ||||
case WAIT_FAILED: | case WAIT_FAILED: | ||||
log_error (_("waiting for process %d to terminate failed: %s\n"), | log_error (_("waiting for process %d to terminate failed: %s\n"), | ||||
Context not available. | |||||
} | } | ||||
else if (WIFEXITED (status) && WEXITSTATUS (status)) | else if (WIFEXITED (status) && WEXITSTATUS (status)) | ||||
{ | { | ||||
if (!exitcode) | if (!exitcode) | ||||
log_error (_("error running `%s': exit status %d\n"), pgmname, | log_error (_("error running `%s': exit status %d\n"), pgmname, | ||||
WEXITSTATUS (status)); | WEXITSTATUS (status)); | ||||
Context not available. | |||||
log_error (_("error running `%s': terminated\n"), pgmname); | log_error (_("error running `%s': terminated\n"), pgmname); | ||||
ec = GPG_ERR_GENERAL; | ec = GPG_ERR_GENERAL; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
if (exitcode) | if (exitcode) | ||||
*exitcode = 0; | *exitcode = 0; | ||||
Context not available. | |||||
#ifdef HAVE_W32_SYSTEM | #ifdef HAVE_W32_SYSTEM | ||||
gpg_error_t err; | gpg_error_t err; | ||||
SECURITY_ATTRIBUTES sec_attr; | SECURITY_ATTRIBUTES sec_attr; | ||||
PROCESS_INFORMATION pi = | PROCESS_INFORMATION pi = | ||||
{ | { | ||||
NULL, /* Returns process handle. */ | NULL, /* Returns process handle. */ | ||||
0, /* Returns primary thread handle. */ | 0, /* Returns primary thread handle. */ | ||||
Context not available. | |||||
memset (&sec_attr, 0, sizeof sec_attr ); | memset (&sec_attr, 0, sizeof sec_attr ); | ||||
sec_attr.nLength = sizeof sec_attr; | sec_attr.nLength = sizeof sec_attr; | ||||
sec_attr.bInheritHandle = FALSE; | sec_attr.bInheritHandle = FALSE; | ||||
/* Build the command line. */ | /* Build the command line. */ | ||||
err = build_w32_commandline (pgmname, argv, &cmdline); | err = build_w32_commandline (pgmname, argv, &cmdline); | ||||
if (err) | if (err) | ||||
return err; | return err; | ||||
/* Start the process. */ | /* Start the process. */ | ||||
memset (&si, 0, sizeof si); | memset (&si, 0, sizeof si); | ||||
Context not available. | |||||
cr_flags = (CREATE_DEFAULT_ERROR_MODE | cr_flags = (CREATE_DEFAULT_ERROR_MODE | ||||
| GetPriorityClass (GetCurrentProcess ()) | | GetPriorityClass (GetCurrentProcess ()) | ||||
| CREATE_NEW_PROCESS_GROUP | | CREATE_NEW_PROCESS_GROUP | ||||
| DETACHED_PROCESS); | | DETACHED_PROCESS); | ||||
/* log_debug ("CreateProcess(detached), path=`%s' cmdline=`%s'\n", */ | /* log_debug ("CreateProcess(detached), path=`%s' cmdline=`%s'\n", */ | ||||
/* pgmname, cmdline); */ | /* pgmname, cmdline); */ | ||||
if (!CreateProcess (pgmname, /* Program to start. */ | if (!CreateProcess (pgmname, /* Program to start. */ | ||||
Context not available. | |||||
/* pi.hProcess, pi.hThread, */ | /* pi.hProcess, pi.hThread, */ | ||||
/* (int) pi.dwProcessId, (int) pi.dwThreadId); */ | /* (int) pi.dwProcessId, (int) pi.dwThreadId); */ | ||||
CloseHandle (pi.hThread); | CloseHandle (pi.hThread); | ||||
return 0; | return 0; | ||||
Context not available. | |||||
if (access (pgmname, X_OK)) | if (access (pgmname, X_OK)) | ||||
return gpg_error_from_syserror (); | return gpg_error_from_syserror (); | ||||
#ifdef USE_GNU_PTH | #ifdef USE_GNU_PTH | ||||
pid = pth_fork? pth_fork () : fork (); | pid = pth_fork? pth_fork () : fork (); | ||||
#else | #else | ||||
pid = fork (); | pid = fork (); | ||||
Context not available. | |||||
} | } | ||||
if (!pid) | if (!pid) | ||||
{ | { | ||||
pid_t pid2; | pid_t pid2; | ||||
gcry_control (GCRYCTL_TERM_SECMEM); | gcry_control (GCRYCTL_TERM_SECMEM); | ||||
if (setsid() == -1 || chdir ("/")) | if (setsid() == -1 || chdir ("/")) | ||||
Context not available. | |||||
if (envp) | if (envp) | ||||
for (i=0; envp[i]; i++) | for (i=0; envp[i]; i++) | ||||
putenv (xstrdup (envp[i])); | putenv (xstrdup (envp[i])); | ||||
do_exec (pgmname, argv, -1, -1, -1, NULL); | do_exec (pgmname, argv, -1, -1, -1, NULL); | ||||
/*NOTREACHED*/ | /*NOTREACHED*/ | ||||
} | } | ||||
if (waitpid (pid, NULL, 0) == -1) | if (waitpid (pid, NULL, 0) == -1) | ||||
log_error ("waitpid failed in gnupg_spawn_process_detached: %s", | log_error ("waitpid failed in gnupg_spawn_process_detached: %s", | ||||
strerror (errno)); | strerror (errno)); | ||||
Context not available. |