os_priority.c | os_priority.c | |||
---|---|---|---|---|
skipping to change at line 31 | skipping to change at line 31 | |||
/** | /** | |||
* @file util/os_priority.c | * @file util/os_priority.c | |||
* @brief Methods to set process priority | * @brief Methods to set process priority | |||
* @author Nils Durner | * @author Nils Durner | |||
*/ | */ | |||
#include "platform.h" | #include "platform.h" | |||
#include "gnunet_common.h" | #include "gnunet_common.h" | |||
#include "gnunet_os_lib.h" | #include "gnunet_os_lib.h" | |||
#include "gnunet_scheduler_lib.h" | #include "gnunet_scheduler_lib.h" | |||
#include "gnunet_strings_lib.h" | ||||
#include "gnunet_crypto_lib.h" | ||||
#include "disk.h" | #include "disk.h" | |||
#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) | #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__) | |||
#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) | #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall) | |||
#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_f ile (kind, "util", syscall, filename) | #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_f ile (kind, "util", syscall, filename) | |||
#define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE" | #define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE" | |||
#define DEBUG_OS GNUNET_EXTRA_LOGGING | ||||
struct GNUNET_OS_Process | struct GNUNET_OS_Process | |||
{ | { | |||
/** | ||||
* PID of the process. | ||||
*/ | ||||
pid_t pid; | pid_t pid; | |||
#if WINDOWS | #if WINDOWS | |||
/** | ||||
* Process handle. | ||||
*/ | ||||
HANDLE handle; | HANDLE handle; | |||
#endif | #endif | |||
int sig; | ||||
/** | ||||
* Pipe we use to signal the process (if used). | ||||
*/ | ||||
struct GNUNET_DISK_FileHandle *control_pipe; | struct GNUNET_DISK_FileHandle *control_pipe; | |||
/** | ||||
* Name of the pipe, NULL for none. | ||||
*/ | ||||
char *childpipename; | ||||
}; | }; | |||
/** | ||||
* Handle for 'this' process. | ||||
*/ | ||||
static struct GNUNET_OS_Process current_process; | static struct GNUNET_OS_Process current_process; | |||
/* MinGW version of named pipe API */ | ||||
#ifdef MINGW | ||||
/** | ||||
* Creates a named pipe/FIFO and opens it | ||||
* | ||||
* @param fn pointer to the name of the named pipe or to NULL | ||||
* @param flags open flags | ||||
* @param perm access permissions | ||||
* @return pipe handle on success, NULL on error | ||||
*/ | ||||
static struct GNUNET_DISK_FileHandle * | ||||
npipe_create (char **fn, enum GNUNET_DISK_OpenFlags flags, | ||||
enum GNUNET_DISK_AccessPermissions perm) | ||||
{ | ||||
struct GNUNET_DISK_FileHandle *ret; | ||||
HANDLE h = NULL; | ||||
DWORD openMode; | ||||
char *name; | ||||
openMode = 0; | ||||
if (flags & GNUNET_DISK_OPEN_READWRITE) | ||||
openMode = PIPE_ACCESS_DUPLEX; | ||||
else if (flags & GNUNET_DISK_OPEN_READ) | ||||
openMode = PIPE_ACCESS_INBOUND; | ||||
else if (flags & GNUNET_DISK_OPEN_WRITE) | ||||
openMode = PIPE_ACCESS_OUTBOUND; | ||||
if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS) | ||||
openMode |= FILE_FLAG_FIRST_PIPE_INSTANCE; | ||||
while (h == NULL) | ||||
{ | ||||
DWORD error_code; | ||||
name = NULL; | ||||
if (*fn != NULL) | ||||
{ | ||||
GNUNET_asprintf (&name, "\\\\.\\pipe\\%.246s", fn); | ||||
LOG (GNUNET_ERROR_TYPE_DEBUG, | ||||
"Trying to create an instance of named pipe `%s'\n", name); | ||||
/* 1) This might work just fine with UTF-8 strings as it is. | ||||
* 2) This is only used by GNUnet itself, and only with latin names. | ||||
*/ | ||||
h = CreateNamedPipe (name, openMode | FILE_FLAG_OVERLAPPED, | ||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0, | ||||
NULL); | ||||
} | ||||
else | ||||
{ | ||||
GNUNET_asprintf (fn, "\\\\.\\pipe\\gnunet-%llu", | ||||
GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK | ||||
, | ||||
UINT64_MAX)); | ||||
LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to create unique named pipe `%s | ||||
'\n", | ||||
*fn); | ||||
h = CreateNamedPipe (*fn, | ||||
openMode | FILE_FLAG_OVERLAPPED | | ||||
FILE_FLAG_FIRST_PIPE_INSTANCE, | ||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 2, 1, 1, 0, | ||||
NULL); | ||||
} | ||||
error_code = GetLastError (); | ||||
if (name) | ||||
GNUNET_free (name); | ||||
/* don't re-set name to NULL yet */ | ||||
if (h == INVALID_HANDLE_VALUE) | ||||
{ | ||||
SetErrnoFromWinError (error_code); | ||||
LOG (GNUNET_ERROR_TYPE_DEBUG, | ||||
"Pipe creation have failed because of %d, errno is %d\n", error_ | ||||
code, | ||||
errno); | ||||
if (name == NULL) | ||||
{ | ||||
LOG (GNUNET_ERROR_TYPE_DEBUG, | ||||
"Pipe was to be unique, considering re-creation\n"); | ||||
GNUNET_free (*fn); | ||||
*fn = NULL; | ||||
if (error_code != ERROR_ACCESS_DENIED && error_code != ERROR_PIPE_B | ||||
USY) | ||||
{ | ||||
return NULL; | ||||
} | ||||
LOG (GNUNET_ERROR_TYPE_DEBUG, | ||||
"Pipe name was not unique, trying again\n"); | ||||
h = NULL; | ||||
} | ||||
else | ||||
return NULL; | ||||
} | ||||
} | ||||
errno = 0; | ||||
ret = GNUNET_malloc (sizeof (*ret)); | ||||
ret->h = h; | ||||
ret->type = GNUNET_PIPE; | ||||
ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); | ||||
ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); | ||||
ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); | ||||
ret->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); | ||||
return ret; | ||||
} | ||||
/** | ||||
* Opens already existing named pipe/FIFO | ||||
* | ||||
* @param fn name of an existing named pipe | ||||
* @param flags open flags | ||||
* @return pipe handle on success, NULL on error | ||||
*/ | ||||
static struct GNUNET_DISK_FileHandle * | ||||
npipe_open (const char *fn, enum GNUNET_DISK_OpenFlags flags) | ||||
{ | ||||
struct GNUNET_DISK_FileHandle *ret; | ||||
HANDLE h; | ||||
DWORD openMode; | ||||
openMode = 0; | ||||
if (flags & GNUNET_DISK_OPEN_READWRITE) | ||||
openMode = GENERIC_WRITE | GENERIC_READ; | ||||
else if (flags & GNUNET_DISK_OPEN_READ) | ||||
openMode = GENERIC_READ; | ||||
else if (flags & GNUNET_DISK_OPEN_WRITE) | ||||
openMode = GENERIC_WRITE; | ||||
h = CreateFile (fn, openMode, 0, NULL, OPEN_EXISTING, | ||||
FILE_FLAG_OVERLAPPED | FILE_READ_ATTRIBUTES, NULL); | ||||
if (h == INVALID_HANDLE_VALUE) | ||||
{ | ||||
SetErrnoFromWinError (GetLastError ()); | ||||
return NULL; | ||||
} | ||||
ret = GNUNET_malloc (sizeof (*ret)); | ||||
ret->h = h; | ||||
ret->type = GNUNET_PIPE; | ||||
ret->oOverlapRead = GNUNET_malloc (sizeof (OVERLAPPED)); | ||||
ret->oOverlapWrite = GNUNET_malloc (sizeof (OVERLAPPED)); | ||||
ret->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); | ||||
ret->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); | ||||
return ret; | ||||
} | ||||
#else | ||||
/* UNIX version of named-pipe API */ | ||||
/** | ||||
* Clean up a named pipe and the directory it was placed in. | ||||
* | ||||
* @param fn name of the pipe | ||||
*/ | ||||
static void | ||||
cleanup_npipe (const char *fn) | ||||
{ | ||||
char *dn; | ||||
char *dp; | ||||
if (0 != unlink (fn)) | ||||
GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn); | ||||
dn = GNUNET_strdup (fn); | ||||
dp = dirname (dn); | ||||
if (0 != rmdir (dp)) | ||||
GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rmdir", dp); | ||||
GNUNET_free (dn); | ||||
} | ||||
/** | ||||
* Setup a named pipe. | ||||
* | ||||
* @param fn where to store the name of the new pipe, | ||||
* if *fn is non-null, the name of the pipe to setup | ||||
* @return GNUNET_OK on success | ||||
*/ | ||||
static int | ||||
npipe_setup (char **fn) | ||||
{ | ||||
if (NULL == *fn) | ||||
{ | ||||
/* FIXME: hardwired '/tmp' path... is bad */ | ||||
char dir[] = "/tmp/gnunet-pipe-XXXXXX"; | ||||
if (NULL == mkdtemp (dir)) | ||||
{ | ||||
LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "mkdtemp"); | ||||
return GNUNET_SYSERR; | ||||
} | ||||
GNUNET_asprintf (fn, "%s/child-control", dir); | ||||
} | ||||
if (-1 == mkfifo (*fn, S_IRUSR | S_IWUSR)) | ||||
return GNUNET_SYSERR; | ||||
return GNUNET_OK; | ||||
} | ||||
/** | ||||
* Open an existing named pipe. | ||||
* | ||||
* @param fn name of the file | ||||
* @param flags flags to use | ||||
* @return NULL on error | ||||
*/ | ||||
static struct GNUNET_DISK_FileHandle * | ||||
npipe_open (const char *fn, | ||||
enum GNUNET_DISK_OpenFlags flags) | ||||
{ | ||||
struct GNUNET_DISK_FileHandle *ret; | ||||
int fd; | ||||
struct timespec req; | ||||
int i; | ||||
/* 200 * 5ms = 1s at most */ | ||||
for (i=0;i<200;i++) | ||||
{ | ||||
fd = open (fn, O_NONBLOCK | ((flags == GNUNET_DISK_OPEN_READ) ? O_RDONL | ||||
Y : O_WRONLY)); | ||||
if ( (-1 != fd) || (9 == i) || (flags == GNUNET_DISK_OPEN_READ)) | ||||
break; | ||||
/* as this is for killing a child process via pipe and it is conceivabl | ||||
e that | ||||
the child process simply didn't finish starting yet, we do some slee | ||||
ping | ||||
(which is obviously usually not allowed). We can't select on the FD | ||||
as | ||||
'open' fails, and we probably shouldn't just "ignore" the error, so | ||||
wait | ||||
and retry a few times is likely the best method; our process API doe | ||||
sn't | ||||
support continuations, so we need to sleep directly... */ | ||||
req.tv_sec = 0; | ||||
req.tv_nsec = 5000000; /* 5ms */ | ||||
(void) nanosleep (&req, NULL); | ||||
} | ||||
if (-1 == fd) | ||||
{ | ||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||||
(flags == GNUNET_DISK_OPEN_READ) | ||||
? _("Failed to open named pipe `%s' for reading: %s\n") | ||||
: _("Failed to open named pipe `%s' for writing: %s\n"), | ||||
fn, | ||||
STRERROR (errno)); | ||||
return NULL; | ||||
} | ||||
ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle)); | ||||
ret->fd = fd; | ||||
return ret; | ||||
} | ||||
#endif | ||||
/** | /** | |||
* This handler is called when there are control data to be read on the pip e | * This handler is called when there are control data to be read on the pip e | |||
* | * | |||
* @param cls the 'struct GNUNET_DISK_FileHandle' of the control pipe | * @param cls the 'struct GNUNET_DISK_FileHandle' of the control pipe | |||
* @param tc scheduler context | * @param tc scheduler context | |||
*/ | */ | |||
static void | static void | |||
parent_control_handler (void *cls, | parent_control_handler (void *cls, | |||
const struct GNUNET_SCHEDULER_TaskContext *tc) | const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
{ | { | |||
struct GNUNET_DISK_FileHandle *control_pipe = | struct GNUNET_DISK_FileHandle *control_pipe = cls; | |||
(struct GNUNET_DISK_FileHandle *) cls; | ||||
int sig; | int sig; | |||
#if DEBUG_OS | ||||
LOG (GNUNET_ERROR_TYPE_DEBUG, "`%s' invoked because of %d\n", __FUNCTION_ _, | LOG (GNUNET_ERROR_TYPE_DEBUG, "`%s' invoked because of %d\n", __FUNCTION_ _, | |||
tc->reason); | tc->reason); | |||
#endif | ||||
if (tc->reason & | if (tc->reason & | |||
(GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT | | (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT | | |||
GNUNET_SCHEDULER_REASON_PREREQ_DONE)) | GNUNET_SCHEDULER_REASON_PREREQ_DONE)) | |||
{ | { | |||
GNUNET_DISK_npipe_close (control_pipe); | GNUNET_DISK_file_close (control_pipe); | |||
return; | ||||
} | } | |||
else | if (GNUNET_DISK_file_read (control_pipe, &sig, sizeof (sig)) != | |||
sizeof (sig)) | ||||
{ | { | |||
if (GNUNET_DISK_file_read (control_pipe, &sig, sizeof (sig)) != | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read"); | |||
sizeof (sig)) | GNUNET_DISK_file_close (control_pipe); | |||
{ | return; | |||
LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read"); | ||||
GNUNET_DISK_npipe_close (control_pipe); | ||||
} | ||||
else | ||||
{ | ||||
#if DEBUG_OS | ||||
LOG (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d from parent\n", si | ||||
g); | ||||
#endif | ||||
GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||||
control_pipe, &parent_control_handler | ||||
, | ||||
control_pipe); | ||||
raise (sig); | ||||
} | ||||
} | } | |||
LOG (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d from parent\n", sig); | ||||
GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||||
control_pipe, &parent_control_handler, | ||||
control_pipe); | ||||
raise (sig); | ||||
} | } | |||
/** | /** | |||
* Task that connects this process to its parent via pipe | * Task that connects this process to its parent via pipe; | |||
* essentially, the parent control handler will read signal numbers | ||||
* from the 'GNUNET_OS_CONTROL_PIPE' (as given in an environment | ||||
* variable) and raise those signals. | ||||
* | ||||
* @param cls closure (unused) | ||||
* @param tc scheduler context (unused) | ||||
*/ | */ | |||
void | void | |||
GNUNET_OS_install_parent_control_handler (void *cls, | GNUNET_OS_install_parent_control_handler (void *cls, | |||
const struct | const struct | |||
GNUNET_SCHEDULER_TaskContext *tc) | GNUNET_SCHEDULER_TaskContext *tc) | |||
{ | { | |||
const char *env_buf; | const char *env_buf; | |||
struct GNUNET_DISK_FileHandle *control_pipe; | struct GNUNET_DISK_FileHandle *control_pipe; | |||
env_buf = getenv (GNUNET_OS_CONTROL_PIPE); | env_buf = getenv (GNUNET_OS_CONTROL_PIPE); | |||
if ((env_buf == NULL) || (strlen (env_buf) <= 0)) | if ( (env_buf == NULL) || (strlen (env_buf) <= 0) ) | |||
{ | { | |||
LOG (GNUNET_ERROR_TYPE_INFO, _("Not installing a handler because $%s=%s | LOG (GNUNET_ERROR_TYPE_DEBUG, | |||
\n"), | "Not installing a handler because $%s is empty\n", | |||
GNUNET_OS_CONTROL_PIPE, env_buf); | GNUNET_OS_CONTROL_PIPE); | |||
putenv ("GNUNET_OS_CONTROL_PIPE="); | putenv ("GNUNET_OS_CONTROL_PIPE="); | |||
return; | return; | |||
} | } | |||
control_pipe = | control_pipe = | |||
GNUNET_DISK_npipe_open (env_buf, GNUNET_DISK_OPEN_READ, | npipe_open (env_buf, GNUNET_DISK_OPEN_READ); | |||
GNUNET_DISK_PERM_USER_READ | | if (NULL == control_pipe) | |||
GNUNET_DISK_PERM_USER_WRITE); | ||||
if (control_pipe == NULL) | ||||
{ | { | |||
LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf); | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf); | |||
putenv ("GNUNET_OS_CONTROL_PIPE="); | putenv ("GNUNET_OS_CONTROL_PIPE="); | |||
return; | return; | |||
} | } | |||
#if DEBUG_OS | ||||
LOG (GNUNET_ERROR_TYPE_DEBUG, | LOG (GNUNET_ERROR_TYPE_DEBUG, | |||
"Adding parent control handler pipe `%s' to the scheduler\n", env_bu f); | "Adding parent control handler pipe `%s' to the scheduler\n", env_bu f); | |||
#endif | ||||
GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pip e, | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pip e, | |||
&parent_control_handler, control_pipe); | &parent_control_handler, control_pipe); | |||
putenv ("GNUNET_OS_CONTROL_PIPE="); | putenv ("GNUNET_OS_CONTROL_PIPE="); | |||
} | } | |||
/** | /** | |||
* Get process structure for current process | * Get process structure for current process | |||
* | * | |||
* The pointer it returns points to static memory location and must not be | * The pointer it returns points to static memory location and must not be | |||
* deallocated/closed | * deallocated/closed | |||
skipping to change at line 158 | skipping to change at line 408 | |||
{ | { | |||
#if WINDOWS | #if WINDOWS | |||
current_process.pid = GetCurrentProcessId (); | current_process.pid = GetCurrentProcessId (); | |||
current_process.handle = GetCurrentProcess (); | current_process.handle = GetCurrentProcess (); | |||
#else | #else | |||
current_process.pid = 0; | current_process.pid = 0; | |||
#endif | #endif | |||
return ¤t_process; | return ¤t_process; | |||
} | } | |||
/** | ||||
* Sends a signal to the process | ||||
* | ||||
* @param proc pointer to process structure | ||||
* @param sig signal | ||||
* @return 0 on success, -1 on error | ||||
*/ | ||||
int | int | |||
GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig) | GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig) | |||
{ | { | |||
#if ENABLE_WINDOWS_WORKAROUNDS | int ret; | |||
int res = 0; | ||||
int ret = 0; | ||||
ret = GNUNET_DISK_file_write (proc->control_pipe, &sig, sizeof (sig)); | #if !WINDOWS | |||
if (ret != sizeof (sig)) | if ( (NULL == proc->control_pipe) && | |||
(NULL != proc->childpipename) ) | ||||
proc->control_pipe = npipe_open (proc->childpipename, | ||||
GNUNET_DISK_OPEN_WRITE); | ||||
#endif | ||||
if (NULL == proc->control_pipe) | ||||
{ | { | |||
if (errno == ECOMM) | #if WINDOWS | |||
{ | /* no pipe and windows? can't do this */ | |||
/* Child process is not controllable via pipe */ | errno = EINVAL; | |||
#if DEBUG_OS | return -1; | |||
LOG (GNUNET_ERROR_TYPE_DEBUG, | #else | |||
"Child process is not controllable, will kill it directly\n"); | return kill (proc->pid, sig); | |||
#endif | #endif | |||
} | } | |||
else if (errno == EPIPE) | ret = GNUNET_DISK_file_write (proc->control_pipe, &sig, sizeof (sig)); | |||
if (ret == sizeof (sig)) | ||||
return 0; | ||||
/* pipe failed, try other methods */ | ||||
switch (sig) | ||||
{ | ||||
#if !WINDOWS | ||||
case SIGHUP: | ||||
#endif | ||||
case SIGINT: | ||||
case SIGKILL: | ||||
case SIGTERM: | ||||
#if WINDOWS && !defined(__CYGWIN__) | ||||
if (0 == TerminateProcess (proc->handle, 0)) | ||||
{ | { | |||
#if DEBUG_OS | /* FIXME: set 'errno' */ | |||
LOG (GNUNET_ERROR_TYPE_DEBUG, | return -1; | |||
"Failed to write into control pipe, because pipe is invalid (the | ||||
child is most likely dead)\n"); | ||||
#endif | ||||
} | } | |||
else | return 0; | |||
LOG (GNUNET_ERROR_TYPE_WARNING, | ||||
"Failed to write into control pipe , errno is %d\n", errno); | ||||
#if WINDOWS && !defined(__CYGWIN__) | ||||
TerminateProcess (proc->handle, 0); | ||||
#else | #else | |||
PLIBC_KILL (proc->pid, sig); | return PLIBC_KILL (proc->pid, sig); | |||
#endif | #endif | |||
} | default: | |||
else | ||||
{ | ||||
#if DEBUG_OS | ||||
LOG (GNUNET_ERROR_TYPE_DEBUG, | ||||
"Wrote control code into control pipe, now waiting\n"); | ||||
#endif | ||||
#if WINDOWS | #if WINDOWS | |||
/* Give it 3 seconds to die, then kill it in a nice Windows-specific wa | errno = EINVAL; | |||
y */ | return -1; | |||
if (WaitForSingleObject (proc->handle, 3000) != WAIT_OBJECT_0) | ||||
TerminateProcess (proc->handle, 0); | ||||
res = 0; | ||||
#else | #else | |||
struct GNUNET_NETWORK_FDSet *rfds; | return kill (proc->pid, sig); | |||
struct GNUNET_NETWORK_FDSet *efds; | ||||
rfds = GNUNET_NETWORK_fdset_create (); | ||||
efds = GNUNET_NETWORK_fdset_create (); | ||||
GNUNET_NETWORK_fdset_handle_set (rfds, proc->control_pipe); | ||||
GNUNET_NETWORK_fdset_handle_set (efds, proc->control_pipe); | ||||
/* Ndurner thought this up, and i have no idea what it does. | ||||
* There's have never been any code to answer the shutdown call | ||||
* (write a single int into the pipe, so that this function can read it | ||||
). | ||||
* On *nix select() will probably tell that pipe is ready | ||||
* for reading, once the other process shuts down, | ||||
* but the read () call will fail, triggering a kill () | ||||
* on the pid that is already dead. This will probably result in non-0 | ||||
* return from kill(), and therefore from this function. | ||||
*/ | ||||
while (1) | ||||
{ | ||||
ret = | ||||
GNUNET_NETWORK_socket_select (rfds, NULL, efds, | ||||
GNUNET_TIME_relative_multiply | ||||
(GNUNET_TIME_relative_get_unit (), | ||||
5000)); | ||||
if (ret < 1 || | ||||
GNUNET_NETWORK_fdset_handle_isset (efds, proc->control_pipe)) | ||||
{ | ||||
/* Just to be sure */ | ||||
PLIBC_KILL (proc->pid, sig); | ||||
res = 0; | ||||
break; | ||||
} | ||||
else | ||||
{ | ||||
if (GNUNET_DISK_file_read (proc->control_pipe, &ret, sizeof (ret)) | ||||
!= | ||||
GNUNET_OK) | ||||
res = PLIBC_KILL (proc->pid, sig); | ||||
/* Child signaled shutdown is in progress */ | ||||
continue; | ||||
} | ||||
} | ||||
#endif | #endif | |||
} | } | |||
return res; | ||||
#else | ||||
return kill (proc->pid, sig); | ||||
#endif | ||||
} | } | |||
/** | /** | |||
* Get the pid of the process in question | * Get the pid of the process in question | |||
* | * | |||
* @param proc the process to get the pid of | * @param proc the process to get the pid of | |||
* | * | |||
* @return the current process id | * @return the current process id | |||
*/ | */ | |||
pid_t | pid_t | |||
GNUNET_OS_process_get_pid (struct GNUNET_OS_Process * proc) | GNUNET_OS_process_get_pid (struct GNUNET_OS_Process * proc) | |||
{ | { | |||
return proc->pid; | return proc->pid; | |||
} | } | |||
void | void | |||
GNUNET_OS_process_close (struct GNUNET_OS_Process *proc) | GNUNET_OS_process_close (struct GNUNET_OS_Process *proc) | |||
{ | { | |||
#if ENABLE_WINDOWS_WORKAROUNDS | #if ENABLE_WINDOWS_WORKAROUNDS | |||
if (proc->control_pipe) | if (proc->control_pipe) | |||
GNUNET_DISK_npipe_close (proc->control_pipe); | GNUNET_DISK_file_close (proc->control_pipe); | |||
#endif | #endif | |||
// FIXME NILS | // FIXME NILS | |||
#ifdef WINDOWS | #ifdef WINDOWS | |||
if (proc->handle != NULL) | if (proc->handle != NULL) | |||
CloseHandle (proc->handle); | CloseHandle (proc->handle); | |||
#endif | #endif | |||
if (NULL != proc->childpipename) | ||||
{ | ||||
#if !WINDOWS | ||||
cleanup_npipe (proc->childpipename); | ||||
#endif | ||||
GNUNET_free (proc->childpipename); | ||||
} | ||||
GNUNET_free (proc); | GNUNET_free (proc); | |||
} | } | |||
// FIXME NILS | // FIXME NILS | |||
#if WINDOWS | #if WINDOWS | |||
#include "gnunet_signal_lib.h" | #include "gnunet_signal_lib.h" | |||
extern GNUNET_SIGNAL_Handler w32_sigchld_handler; | extern GNUNET_SIGNAL_Handler w32_sigchld_handler; | |||
/** | /** | |||
* Make seaspider happy. | * Make seaspider happy. | |||
*/ | */ | |||
#define DWORD_WINAPI DWORD WINAPI | #define DWORD_WINAPI DWORD WINAPI | |||
/** | /** | |||
* @brief Waits for a process to terminate and invokes the SIGCHLD handler | * @brief Waits for a process to terminate and invokes the SIGCHLD handler | |||
* @param proc pointer to process structure | * @param proc pointer to process structure | |||
*/ | */ | |||
static DWORD_WINAPI | static DWORD_WINAPI | |||
ChildWaitThread (void *arg) | child_wait_thread (void *arg) | |||
{ | { | |||
struct GNUNET_OS_Process *proc = (struct GNUNET_OS_Process *) arg; | struct GNUNET_OS_Process *proc = (struct GNUNET_OS_Process *) arg; | |||
WaitForSingleObject (proc->handle, INFINITE); | WaitForSingleObject (proc->handle, INFINITE); | |||
if (w32_sigchld_handler) | if (w32_sigchld_handler) | |||
w32_sigchld_handler (); | w32_sigchld_handler (); | |||
return 0; | return 0; | |||
} | } | |||
skipping to change at line 414 | skipping to change at line 631 | |||
else | else | |||
{ | { | |||
if (0 != setpriority (PRIO_PROCESS, pid, rprio)) | if (0 != setpriority (PRIO_PROCESS, pid, rprio)) | |||
{ | { | |||
LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, | |||
"setpriority"); | "setpriority"); | |||
return GNUNET_SYSERR; | return GNUNET_SYSERR; | |||
} | } | |||
} | } | |||
#else | #else | |||
#if DEBUG_OS | ||||
LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, | LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, | |||
"Priority management not availabe for this platform\n"); | "Priority management not availabe for this platform\n"); | |||
#endif | #endif | |||
#endif | ||||
return GNUNET_OK; | return GNUNET_OK; | |||
} | } | |||
#if MINGW | #if MINGW | |||
static char * | static char * | |||
CreateCustomEnvTable (char **vars) | CreateCustomEnvTable (char **vars) | |||
{ | { | |||
char *win32_env_table, *ptr, **var_ptr, *result, *result_ptr; | char *win32_env_table, *ptr, **var_ptr, *result, *result_ptr; | |||
size_t tablesize = 0; | size_t tablesize = 0; | |||
size_t items_count = 0; | size_t items_count = 0; | |||
skipping to change at line 527 | skipping to change at line 742 | |||
FreeEnvironmentStrings (win32_env_table); | FreeEnvironmentStrings (win32_env_table); | |||
GNUNET_free (index); | GNUNET_free (index); | |||
*result_ptr = 0; | *result_ptr = 0; | |||
return result; | return result; | |||
} | } | |||
#endif | #endif | |||
/** | /** | |||
* Start a process. | * Start a process. | |||
* | * | |||
* @param pipe_control should a pipe be used to send signals to the child? | ||||
* @param pipe_stdin pipe to use to send input to child process (or NULL) | * @param pipe_stdin pipe to use to send input to child process (or NULL) | |||
* @param pipe_stdout pipe to use to get output from child process (or NULL ) | * @param pipe_stdout pipe to use to get output from child process (or NULL ) | |||
* @param filename name of the binary | * @param filename name of the binary | |||
* @param va NULL-terminated list of arguments to the process | * @param argv NULL-terminated array of arguments to the process | |||
* @return pointer to process structure of the new process, NULL on error | * @return pointer to process structure of the new process, NULL on error | |||
*/ | */ | |||
struct GNUNET_OS_Process * | struct GNUNET_OS_Process * | |||
GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin, | GNUNET_OS_start_process_vap (int pipe_control, | |||
struct GNUNET_DISK_PipeHandle *pipe_stdout, | struct GNUNET_DISK_PipeHandle *pipe_stdin, | |||
const char *filename, va_list va) | struct GNUNET_DISK_PipeHandle *pipe_stdout, | |||
const char *filename, | ||||
char *const argv[]) | ||||
{ | { | |||
va_list ap; | #ifndef MINGW | |||
#if ENABLE_WINDOWS_WORKAROUNDS | ||||
char *childpipename = NULL; | char *childpipename = NULL; | |||
struct GNUNET_DISK_FileHandle *control_pipe = NULL; | ||||
#endif | ||||
struct GNUNET_OS_Process *gnunet_proc = NULL; | struct GNUNET_OS_Process *gnunet_proc = NULL; | |||
#ifndef MINGW | ||||
pid_t ret; | pid_t ret; | |||
char **argv; | ||||
int argc; | ||||
int fd_stdout_write; | int fd_stdout_write; | |||
int fd_stdout_read; | int fd_stdout_read; | |||
int fd_stdin_read; | int fd_stdin_read; | |||
int fd_stdin_write; | int fd_stdin_write; | |||
#if ENABLE_WINDOWS_WORKAROUNDS | if ( (GNUNET_YES == pipe_control) && | |||
control_pipe = | (GNUNET_OK != | |||
GNUNET_DISK_npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE, | npipe_setup (&childpipename)) ) | |||
GNUNET_DISK_PERM_USER_READ | | ||||
GNUNET_DISK_PERM_USER_WRITE); | ||||
if (control_pipe == NULL) | ||||
return NULL; | return NULL; | |||
#endif | ||||
argc = 0; | ||||
va_copy (ap, va); | ||||
while (NULL != va_arg (ap, char *)) | ||||
argc++; | ||||
va_end (ap); | ||||
argv = GNUNET_malloc (sizeof (char *) * (argc + 1)); | ||||
argc = 0; | ||||
va_copy (ap, va); | ||||
while (NULL != (argv[argc] = va_arg (ap, char *))) | ||||
argc++; | ||||
va_end (ap); | ||||
if (pipe_stdout != NULL) | if (pipe_stdout != NULL) | |||
{ | { | |||
GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle | GNUNET_assert (GNUNET_OK == | |||
(pipe_stdout, | GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handl | |||
GNUNET_DISK_PIPE_END_WRITE), | e | |||
&fd_stdout_write, sizeof (int)); | (pipe_stdout, | |||
GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle | GNUNET_DISK_PIPE_END_ | |||
(pipe_stdout, GNUNET_DISK_PIPE_END_R | WRITE), | |||
EAD), | &fd_stdout_write, size | |||
&fd_stdout_read, sizeof (int)); | of (int))); | |||
GNUNET_assert (GNUNET_OK == | ||||
GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handl | ||||
e | ||||
(pipe_stdout, GNUNET_D | ||||
ISK_PIPE_END_READ), | ||||
&fd_stdout_read, sizeo | ||||
f (int))); | ||||
} | } | |||
if (pipe_stdin != NULL) | if (pipe_stdin != NULL) | |||
{ | { | |||
GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle | GNUNET_assert (GNUNET_OK == | |||
(pipe_stdin, GNUNET_DISK_PIPE_END_RE | GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handl | |||
AD), | e | |||
&fd_stdin_read, sizeof (int)); | (pipe_stdin, GNUNET_DI | |||
GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle | SK_PIPE_END_READ), | |||
(pipe_stdin, GNUNET_DISK_PIPE_END_WR | &fd_stdin_read, sizeof | |||
ITE), | (int))); | |||
&fd_stdin_write, sizeof (int)); | GNUNET_assert (GNUNET_OK == | |||
GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handl | ||||
e | ||||
(pipe_stdin, GNUNET_DI | ||||
SK_PIPE_END_WRITE), | ||||
&fd_stdin_write, sizeo | ||||
f (int))); | ||||
} | } | |||
ret = fork (); | ret = fork (); | |||
if (ret != 0) | if (-1 == ret) | |||
{ | { | |||
if (ret == -1) | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); | |||
{ | GNUNET_free_non_null (childpipename); | |||
LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); | return NULL; | |||
#if ENABLE_WINDOWS_WORKAROUNDS | } | |||
GNUNET_DISK_npipe_close (control_pipe); | if (0 != ret) | |||
#endif | { | |||
} | gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); | |||
else | gnunet_proc->pid = ret; | |||
{ | gnunet_proc->childpipename = childpipename; | |||
gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); | ||||
gnunet_proc->pid = ret; | ||||
#if ENABLE_WINDOWS_WORKAROUNDS | ||||
gnunet_proc->control_pipe = control_pipe; | ||||
#endif | ||||
} | ||||
GNUNET_free (argv); | ||||
#if ENABLE_WINDOWS_WORKAROUNDS | ||||
GNUNET_free (childpipename); | ||||
#endif | ||||
return gnunet_proc; | return gnunet_proc; | |||
} | } | |||
if (NULL != childpipename) | ||||
#if ENABLE_WINDOWS_WORKAROUNDS | { | |||
setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1); | setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1); | |||
GNUNET_free (childpipename); | GNUNET_free (childpipename); | |||
#endif | } | |||
if (pipe_stdout != NULL) | if (pipe_stdout != NULL) | |||
{ | { | |||
GNUNET_break (0 == close (fd_stdout_read)); | GNUNET_break (0 == close (fd_stdout_read)); | |||
if (-1 == dup2 (fd_stdout_write, 1)) | if (-1 == dup2 (fd_stdout_write, 1)) | |||
LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2"); | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2"); | |||
GNUNET_break (0 == close (fd_stdout_write)); | GNUNET_break (0 == close (fd_stdout_write)); | |||
} | } | |||
if (pipe_stdin != NULL) | if (pipe_stdin != NULL) | |||
{ | { | |||
GNUNET_break (0 == close (fd_stdin_write)); | GNUNET_break (0 == close (fd_stdin_write)); | |||
if (-1 == dup2 (fd_stdin_read, 0)) | if (-1 == dup2 (fd_stdin_read, 0)) | |||
LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2"); | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2"); | |||
GNUNET_break (0 == close (fd_stdin_read)); | GNUNET_break (0 == close (fd_stdin_read)); | |||
} | } | |||
execvp (filename, argv); | execvp (filename, argv); | |||
LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename); | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename); | |||
_exit (1); | _exit (1); | |||
#else | #else | |||
char *childpipename = NULL; | ||||
struct GNUNET_OS_Process *gnunet_proc = NULL; | ||||
char *arg; | char *arg; | |||
unsigned int cmdlen; | unsigned int cmdlen; | |||
char *cmd, *idx; | char *cmd, *idx; | |||
STARTUPINFO start; | STARTUPINFOW start; | |||
PROCESS_INFORMATION proc; | PROCESS_INFORMATION proc; | |||
int argc, arg_count; | ||||
HANDLE stdin_handle; | HANDLE stdin_handle; | |||
HANDLE stdout_handle; | HANDLE stdout_handle; | |||
struct GNUNET_DISK_FileHandle *control_pipe; | ||||
char path[MAX_PATH + 1]; | char path[MAX_PATH + 1]; | |||
char *our_env[3] = { NULL, NULL, NULL }; | char *our_env[3] = { NULL, NULL, NULL }; | |||
char *env_block = NULL; | char *env_block = NULL; | |||
char *pathbuf; | char *pathbuf; | |||
DWORD pathbuf_len, alloc_len; | DWORD pathbuf_len, alloc_len; | |||
char *self_prefix; | char *self_prefix; | |||
char *bindir; | char *bindir; | |||
char *libdir; | char *libdir; | |||
char *ptr; | char *ptr; | |||
char *non_const_filename; | char *non_const_filename; | |||
wchar_t wpath[MAX_PATH + 1], wcmd[32768]; | ||||
/* Search in prefix dir (hopefully - the directory from which | /* Search in prefix dir (hopefully - the directory from which | |||
* the current module was loaded), bindir and libdir, then in PATH | * the current module was loaded), bindir and libdir, then in PATH | |||
*/ | */ | |||
self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX) ; | self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX) ; | |||
bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR); | bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR); | |||
libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR); | libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR); | |||
pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0); | pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0); | |||
skipping to change at line 716 | skipping to change at line 905 | |||
LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "SearchPath", | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "SearchPath", | |||
non_const_filename); | non_const_filename); | |||
GNUNET_free (non_const_filename); | GNUNET_free (non_const_filename); | |||
GNUNET_free (pathbuf); | GNUNET_free (pathbuf); | |||
return NULL; | return NULL; | |||
} | } | |||
GNUNET_free (pathbuf); | GNUNET_free (pathbuf); | |||
GNUNET_free (non_const_filename); | GNUNET_free (non_const_filename); | |||
cmdlen = 0; | cmdlen = 0; | |||
va_copy (ap, va); | argc = 0; | |||
while (NULL != (arg = va_arg (ap, char *))) | while (NULL != (arg = argv[argc++])) | |||
{ | { | |||
if (cmdlen == 0) | if (cmdlen == 0) | |||
cmdlen = cmdlen + strlen (path) + 3; | cmdlen = cmdlen + strlen (path) + 4; | |||
else | else | |||
cmdlen = cmdlen + strlen (arg) + 3; | cmdlen = cmdlen + strlen (arg) + 4; | |||
} | } | |||
va_end (ap); | arg_count = argc; | |||
cmd = idx = GNUNET_malloc (sizeof (char) * (cmdlen + 1)); | cmd = idx = GNUNET_malloc (sizeof (char) * (cmdlen + 1)); | |||
va_copy (ap, va); | argc = 0; | |||
while (NULL != (arg = va_arg (ap, char *))) | while (NULL != (arg = argv[argc++])) | |||
{ | { | |||
/* This is to escape trailing slash */ | ||||
char arg_lastchar = arg[strlen (arg) - 1]; | ||||
if (idx == cmd) | if (idx == cmd) | |||
idx += sprintf (idx, "\"%s\" ", path); | idx += sprintf (idx, "\"%s%s\"%s", path, | |||
arg_lastchar == '\\' ? "\\" : "", argc + 1 == arg_count ? "" : " | ||||
"); | ||||
else | else | |||
idx += sprintf (idx, "\"%s\" ", arg); | idx += sprintf (idx, "\"%s%s\"%s", arg, | |||
arg_lastchar == '\\' ? "\\" : "", argc + 1 == arg_count ? "" : " | ||||
"); | ||||
} | } | |||
va_end (ap); | ||||
memset (&start, 0, sizeof (start)); | memset (&start, 0, sizeof (start)); | |||
start.cb = sizeof (start); | start.cb = sizeof (start); | |||
if ((pipe_stdin != NULL) || (pipe_stdout != NULL)) | if ((pipe_stdin != NULL) || (pipe_stdout != NULL)) | |||
start.dwFlags |= STARTF_USESTDHANDLES; | start.dwFlags |= STARTF_USESTDHANDLES; | |||
if (pipe_stdin != NULL) | if (pipe_stdin != NULL) | |||
{ | { | |||
GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle | GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle | |||
skipping to change at line 759 | skipping to change at line 951 | |||
} | } | |||
if (pipe_stdout != NULL) | if (pipe_stdout != NULL) | |||
{ | { | |||
GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle | GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle | |||
(pipe_stdout, | (pipe_stdout, | |||
GNUNET_DISK_PIPE_END_WRITE), | GNUNET_DISK_PIPE_END_WRITE), | |||
&stdout_handle, sizeof (HANDLE)); | &stdout_handle, sizeof (HANDLE)); | |||
start.hStdOutput = stdout_handle; | start.hStdOutput = stdout_handle; | |||
} | } | |||
if (GNUNET_YES == pipe_control) | ||||
control_pipe = | ||||
GNUNET_DISK_npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE, | ||||
GNUNET_DISK_PERM_USER_READ | | ||||
GNUNET_DISK_PERM_USER_WRITE); | ||||
if (control_pipe == NULL) | ||||
{ | { | |||
GNUNET_free (cmd); | control_pipe = | |||
GNUNET_free (path); | npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE, | |||
return NULL; | GNUNET_DISK_PERM_USER_READ | | |||
GNUNET_DISK_PERM_USER_WRITE); | ||||
if (control_pipe == NULL) | ||||
{ | ||||
GNUNET_free (cmd); | ||||
GNUNET_free (path); | ||||
return NULL; | ||||
} | ||||
} | ||||
if (NULL != childpipename) | ||||
{ | ||||
LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n | ||||
", | ||||
childpipename); | ||||
GNUNET_asprintf (&our_env[0], "%s=", GNUNET_OS_CONTROL_PIPE); | ||||
GNUNET_asprintf (&our_env[1], "%s", childpipename); | ||||
our_env[2] = NULL; | ||||
} | ||||
else | ||||
{ | ||||
our_env[0] = NULL; | ||||
} | } | |||
#if DEBUG_OS | ||||
LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n", | ||||
childpipename); | ||||
#endif | ||||
GNUNET_asprintf (&our_env[0], "%s=", GNUNET_OS_CONTROL_PIPE); | ||||
GNUNET_asprintf (&our_env[1], "%s", childpipename); | ||||
our_env[2] = NULL; | ||||
env_block = CreateCustomEnvTable (our_env); | env_block = CreateCustomEnvTable (our_env); | |||
GNUNET_free (our_env[0]); | GNUNET_free (our_env[0]); | |||
GNUNET_free (our_env[1]); | GNUNET_free (our_env[1]); | |||
if (!CreateProcessA | if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath) | |||
(path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED, | || ERROR_SUCCESS != plibc_conv_to_win_pathwconv(cmd, wcmd) | |||
|| !CreateProcessW | ||||
(wpath, wcmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED, | ||||
env_block, NULL, &start, &proc)) | env_block, NULL, &start, &proc)) | |||
{ | { | |||
SetErrnoFromWinError (GetLastError ()); | SetErrnoFromWinError (GetLastError ()); | |||
LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path); | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path); | |||
GNUNET_free (env_block); | GNUNET_free (env_block); | |||
GNUNET_free (cmd); | GNUNET_free (cmd); | |||
return NULL; | return NULL; | |||
} | } | |||
GNUNET_free (env_block); | GNUNET_free (env_block); | |||
gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); | gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); | |||
gnunet_proc->pid = proc.dwProcessId; | gnunet_proc->pid = proc.dwProcessId; | |||
gnunet_proc->handle = proc.hProcess; | gnunet_proc->handle = proc.hProcess; | |||
gnunet_proc->control_pipe = control_pipe; | gnunet_proc->control_pipe = control_pipe; | |||
CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL ); | CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, N ULL); | |||
ResumeThread (proc.hThread); | ResumeThread (proc.hThread); | |||
CloseHandle (proc.hThread); | CloseHandle (proc.hThread); | |||
GNUNET_free (cmd); | GNUNET_free (cmd); | |||
return gnunet_proc; | return gnunet_proc; | |||
#endif | #endif | |||
} | } | |||
/** | /** | |||
* Start a process. | * Start a process. | |||
* | * | |||
* @param pipe_control should a pipe be used to send signals to the child? | ||||
* @param pipe_stdin pipe to use to send input to child process (or NULL) | ||||
* @param pipe_stdout pipe to use to get output from child process (or NULL | ||||
) | ||||
* @param filename name of the binary | ||||
* @param va NULL-terminated list of arguments to the process | ||||
* @return pointer to process structure of the new process, NULL on error | ||||
*/ | ||||
struct GNUNET_OS_Process * | ||||
GNUNET_OS_start_process_va (int pipe_control, | ||||
struct GNUNET_DISK_PipeHandle *pipe_stdin, | ||||
struct GNUNET_DISK_PipeHandle *pipe_stdout, | ||||
const char *filename, va_list va) | ||||
{ | ||||
struct GNUNET_OS_Process *ret; | ||||
va_list ap; | ||||
char **argv; | ||||
int argc; | ||||
argc = 0; | ||||
va_copy (ap, va); | ||||
while (NULL != va_arg (ap, char *)) | ||||
argc++; | ||||
va_end (ap); | ||||
argv = GNUNET_malloc (sizeof (char *) * (argc + 1)); | ||||
argc = 0; | ||||
va_copy (ap, va); | ||||
while (NULL != (argv[argc] = va_arg (ap, char *))) | ||||
argc++; | ||||
va_end (ap); | ||||
ret = GNUNET_OS_start_process_vap (pipe_control, | ||||
pipe_stdin, | ||||
pipe_stdout, | ||||
filename, | ||||
argv); | ||||
GNUNET_free (argv); | ||||
return ret; | ||||
} | ||||
/** | ||||
* Start a process. | ||||
* | ||||
* @param pipe_control should a pipe be used to send signals to the child? | ||||
* @param pipe_stdin pipe to use to send input to child process (or NULL) | * @param pipe_stdin pipe to use to send input to child process (or NULL) | |||
* @param pipe_stdout pipe to use to get output from child process (or NULL ) | * @param pipe_stdout pipe to use to get output from child process (or NULL ) | |||
* @param filename name of the binary | * @param filename name of the binary | |||
* @param ... NULL-terminated list of arguments to the process | * @param ... NULL-terminated list of arguments to the process | |||
* | * | |||
* @return pointer to process structure of the new process, NULL on error | * @return pointer to process structure of the new process, NULL on error | |||
* | * | |||
*/ | */ | |||
struct GNUNET_OS_Process * | struct GNUNET_OS_Process * | |||
GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin, | GNUNET_OS_start_process (int pipe_control, | |||
struct GNUNET_DISK_PipeHandle *pipe_stdin, | ||||
struct GNUNET_DISK_PipeHandle *pipe_stdout, | struct GNUNET_DISK_PipeHandle *pipe_stdout, | |||
const char *filename, ...) | const char *filename, ...) | |||
{ | { | |||
struct GNUNET_OS_Process *ret; | struct GNUNET_OS_Process *ret; | |||
va_list ap; | va_list ap; | |||
va_start (ap, filename); | va_start (ap, filename); | |||
ret = GNUNET_OS_start_process_va (pipe_stdin, pipe_stdout, filename, ap); | ret = GNUNET_OS_start_process_va (pipe_control, pipe_stdin, pipe_stdout, filename, ap); | |||
va_end (ap); | va_end (ap); | |||
return ret; | return ret; | |||
} | } | |||
/** | /** | |||
* Start a process. | * Start a process. | |||
* | * | |||
* @param pipe_control should a pipe be used to send signals to the child? | ||||
* @param lsocks array of listen sockets to dup systemd-style (or NULL); | * @param lsocks array of listen sockets to dup systemd-style (or NULL); | |||
* must be NULL on platforms where dup is not supported | * must be NULL on platforms where dup is not supported | |||
* @param filename name of the binary | * @param filename name of the binary | |||
* @param argv NULL-terminated list of arguments to the process | * @param argv NULL-terminated list of arguments to the process | |||
* @return process ID of the new process, -1 on error | * @return process ID of the new process, -1 on error | |||
*/ | */ | |||
struct GNUNET_OS_Process * | struct GNUNET_OS_Process * | |||
GNUNET_OS_start_process_v (const SOCKTYPE *lsocks, | GNUNET_OS_start_process_v (int pipe_control, | |||
const SOCKTYPE *lsocks, | ||||
const char *filename, | const char *filename, | |||
char *const argv[]) | char *const argv[]) | |||
{ | { | |||
#if ENABLE_WINDOWS_WORKAROUNDS | ||||
struct GNUNET_DISK_FileHandle *control_pipe = NULL; | ||||
char *childpipename = NULL; | ||||
#endif | ||||
#ifndef MINGW | #ifndef MINGW | |||
pid_t ret; | pid_t ret; | |||
char lpid[16]; | char lpid[16]; | |||
char fds[16]; | char fds[16]; | |||
struct GNUNET_OS_Process *gnunet_proc = NULL; | struct GNUNET_OS_Process *gnunet_proc = NULL; | |||
char *childpipename = NULL; | ||||
int i; | int i; | |||
int j; | int j; | |||
int k; | int k; | |||
int tgt; | int tgt; | |||
int flags; | int flags; | |||
int *lscp; | int *lscp; | |||
unsigned int ls; | unsigned int ls; | |||
#if ENABLE_WINDOWS_WORKAROUNDS | if ( (GNUNET_YES == pipe_control) && | |||
control_pipe = | (GNUNET_OK != npipe_setup (&childpipename)) ) | |||
GNUNET_DISK_npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE, | ||||
GNUNET_DISK_PERM_USER_READ | | ||||
GNUNET_DISK_PERM_USER_WRITE); | ||||
if (control_pipe == NULL) | ||||
return NULL; | return NULL; | |||
#endif | ||||
lscp = NULL; | lscp = NULL; | |||
ls = 0; | ls = 0; | |||
if (lsocks != NULL) | if (lsocks != NULL) | |||
{ | { | |||
i = 0; | i = 0; | |||
while (-1 != (k = lsocks[i++])) | while (-1 != (k = lsocks[i++])) | |||
GNUNET_array_append (lscp, ls, k); | GNUNET_array_append (lscp, ls, k); | |||
GNUNET_array_append (lscp, ls, -1); | GNUNET_array_append (lscp, ls, -1); | |||
} | } | |||
ret = fork (); | ret = fork (); | |||
if (ret != 0) | if (-1 == ret) | |||
{ | { | |||
if (ret == -1) | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); | |||
{ | GNUNET_free_non_null (childpipename); | |||
LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); | GNUNET_array_grow (lscp, ls, 0); | |||
#if ENABLE_WINDOWS_WORKAROUNDS | return NULL; | |||
GNUNET_DISK_npipe_close (control_pipe); | } | |||
#endif | if (0 != ret) | |||
} | { | |||
else | gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); | |||
{ | gnunet_proc->pid = ret; | |||
gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); | gnunet_proc->childpipename = childpipename; | |||
gnunet_proc->pid = ret; | ||||
#if ENABLE_WINDOWS_WORKAROUNDS | ||||
gnunet_proc->control_pipe = control_pipe; | ||||
#endif | ||||
} | ||||
GNUNET_array_grow (lscp, ls, 0); | GNUNET_array_grow (lscp, ls, 0); | |||
#if ENABLE_WINDOWS_WORKAROUNDS | ||||
GNUNET_free (childpipename); | ||||
#endif | ||||
return gnunet_proc; | return gnunet_proc; | |||
} | } | |||
if (NULL != childpipename) | ||||
#if ENABLE_WINDOWS_WORKAROUNDS | { | |||
setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1); | setenv (GNUNET_OS_CONTROL_PIPE, childpipename, 1); | |||
GNUNET_free (childpipename); | GNUNET_free (childpipename); | |||
#endif | } | |||
if (lscp != NULL) | if (lscp != NULL) | |||
{ | { | |||
/* read systemd documentation... */ | /* read systemd documentation... */ | |||
GNUNET_snprintf (lpid, sizeof (lpid), "%u", getpid ()); | GNUNET_snprintf (lpid, sizeof (lpid), "%u", getpid ()); | |||
setenv ("LISTEN_PID", lpid, 1); | setenv ("LISTEN_PID", lpid, 1); | |||
i = 0; | i = 0; | |||
tgt = 3; | tgt = 3; | |||
while (-1 != lscp[i]) | while (-1 != lscp[i]) | |||
{ | { | |||
j = i + 1; | j = i + 1; | |||
skipping to change at line 965 | skipping to change at line 1189 | |||
i++; | i++; | |||
} | } | |||
GNUNET_snprintf (fds, sizeof (fds), "%u", i); | GNUNET_snprintf (fds, sizeof (fds), "%u", i); | |||
setenv ("LISTEN_FDS", fds, 1); | setenv ("LISTEN_FDS", fds, 1); | |||
} | } | |||
GNUNET_array_grow (lscp, ls, 0); | GNUNET_array_grow (lscp, ls, 0); | |||
execvp (filename, argv); | execvp (filename, argv); | |||
LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename); | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "execvp", filename); | |||
_exit (1); | _exit (1); | |||
#else | #else | |||
struct GNUNET_DISK_FileHandle *control_pipe = NULL; | ||||
char *childpipename = NULL; | ||||
char **arg, **non_const_argv; | char **arg, **non_const_argv; | |||
unsigned int cmdlen; | unsigned int cmdlen; | |||
char *cmd, *idx; | char *cmd, *idx; | |||
STARTUPINFO start; | STARTUPINFOW start; | |||
PROCESS_INFORMATION proc; | PROCESS_INFORMATION proc; | |||
int argcount = 0; | int argcount = 0; | |||
struct GNUNET_OS_Process *gnunet_proc = NULL; | struct GNUNET_OS_Process *gnunet_proc = NULL; | |||
char path[MAX_PATH + 1]; | char path[MAX_PATH + 1]; | |||
char *our_env[5] = { NULL, NULL, NULL, NULL, NULL }; | char *our_env[5] = { NULL, NULL, NULL, NULL, NULL }; | |||
char *env_block = NULL; | char *env_block = NULL; | |||
char *pathbuf; | char *pathbuf; | |||
DWORD pathbuf_len, alloc_len; | DWORD pathbuf_len, alloc_len; | |||
char *self_prefix; | char *self_prefix; | |||
char *bindir; | char *bindir; | |||
char *libdir; | char *libdir; | |||
char *ptr; | char *ptr; | |||
char *non_const_filename; | char *non_const_filename; | |||
struct GNUNET_DISK_PipeHandle *lsocks_pipe; | struct GNUNET_DISK_PipeHandle *lsocks_pipe; | |||
const struct GNUNET_DISK_FileHandle *lsocks_write_fd; | const struct GNUNET_DISK_FileHandle *lsocks_write_fd; | |||
HANDLE lsocks_read; | HANDLE lsocks_read; | |||
HANDLE lsocks_write; | HANDLE lsocks_write; | |||
wchar_t wpath[MAX_PATH + 1], wcmd[32768]; | ||||
int env_off; | ||||
int fail; | int fail; | |||
/* Search in prefix dir (hopefully - the directory from which | /* Search in prefix dir (hopefully - the directory from which | |||
* the current module was loaded), bindir and libdir, then in PATH | * the current module was loaded), bindir and libdir, then in PATH | |||
*/ | */ | |||
self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX) ; | self_prefix = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX) ; | |||
bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR); | bindir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR); | |||
libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR); | libdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR); | |||
pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0); | pathbuf_len = GetEnvironmentVariableA ("PATH", (char *) &pathbuf, 0); | |||
skipping to change at line 1073 | skipping to change at line 1298 | |||
arg++; | arg++; | |||
argcount++; | argcount++; | |||
} | } | |||
non_const_argv[argcount] = NULL; | non_const_argv[argcount] = NULL; | |||
/* Count cmd len */ | /* Count cmd len */ | |||
cmdlen = 1; | cmdlen = 1; | |||
arg = non_const_argv; | arg = non_const_argv; | |||
while (*arg) | while (*arg) | |||
{ | { | |||
cmdlen = cmdlen + strlen (*arg) + 3; | cmdlen = cmdlen + strlen (*arg) + 4; | |||
arg++; | arg++; | |||
} | } | |||
/* Allocate and create cmd */ | /* Allocate and create cmd */ | |||
cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen); | cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen); | |||
arg = non_const_argv; | arg = non_const_argv; | |||
while (*arg) | while (*arg) | |||
{ | { | |||
idx += sprintf (idx, "\"%s\" ", *arg); | char arg_last_char = (*arg)[strlen (*arg) - 1]; | |||
idx += sprintf (idx, "\"%s%s\"%s", *arg, | ||||
arg_last_char == '\\' ? "\\" : "", *(arg + 1) ? " " : ""); | ||||
arg++; | arg++; | |||
} | } | |||
while (argcount > 0) | while (argcount > 0) | |||
GNUNET_free (non_const_argv[--argcount]); | GNUNET_free (non_const_argv[--argcount]); | |||
GNUNET_free (non_const_argv); | GNUNET_free (non_const_argv); | |||
memset (&start, 0, sizeof (start)); | memset (&start, 0, sizeof (start)); | |||
start.cb = sizeof (start); | start.cb = sizeof (start); | |||
control_pipe = | if (GNUNET_YES == pipe_control) | |||
GNUNET_DISK_npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE, | ||||
GNUNET_DISK_PERM_USER_READ | | ||||
GNUNET_DISK_PERM_USER_WRITE); | ||||
if (control_pipe == NULL) | ||||
{ | { | |||
GNUNET_free (cmd); | control_pipe = | |||
GNUNET_free (path); | npipe_create (&childpipename, GNUNET_DISK_OPEN_WRITE, | |||
return NULL; | GNUNET_DISK_PERM_USER_READ | | |||
GNUNET_DISK_PERM_USER_WRITE); | ||||
if (control_pipe == NULL) | ||||
{ | ||||
GNUNET_free (cmd); | ||||
GNUNET_free (path); | ||||
return NULL; | ||||
} | ||||
} | } | |||
if (lsocks != NULL && lsocks[0] != INVALID_SOCKET) | if (lsocks != NULL && lsocks[0] != INVALID_SOCKET) | |||
{ | { | |||
lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO); | lsocks_pipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNU NET_NO); | |||
if (lsocks_pipe == NULL) | if (lsocks_pipe == NULL) | |||
{ | { | |||
GNUNET_free (cmd); | GNUNET_free (cmd); | |||
GNUNET_free (path); | GNUNET_free (path); | |||
GNUNET_DISK_pipe_close (lsocks_pipe); | GNUNET_DISK_pipe_close (lsocks_pipe); | |||
return NULL; | return NULL; | |||
} | } | |||
lsocks_write_fd = GNUNET_DISK_pipe_handle (lsocks_pipe, | lsocks_write_fd = GNUNET_DISK_pipe_handle (lsocks_pipe, | |||
GNUNET_DISK_PIPE_END_WRITE); | GNUNET_DISK_PIPE_END_WRITE); | |||
GNUNET_DISK_internal_file_handle_ (lsocks_write_fd, | GNUNET_DISK_internal_file_handle_ (lsocks_write_fd, | |||
&lsocks_write, sizeof (HANDLE)); | &lsocks_write, sizeof (HANDLE)); | |||
GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle | GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle | |||
(lsocks_pipe, GNUNET_DISK_PIPE_END_R EAD), | (lsocks_pipe, GNUNET_DISK_PIPE_END_R EAD), | |||
&lsocks_read, sizeof (HANDLE)); | &lsocks_read, sizeof (HANDLE)); | |||
} | } | |||
#if DEBUG_OS | env_off = 0; | |||
LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n", | if (NULL != childpipename) | |||
childpipename); | { | |||
#endif | LOG (GNUNET_ERROR_TYPE_DEBUG, "Opened the parent end of the pipe `%s'\n | |||
", | ||||
GNUNET_asprintf (&our_env[0], "%s=", GNUNET_OS_CONTROL_PIPE); | childpipename); | |||
GNUNET_asprintf (&our_env[1], "%s", childpipename); | GNUNET_asprintf (&our_env[env_off++], "%s=", GNUNET_OS_CONTROL_PIPE); | |||
GNUNET_free (childpipename); | GNUNET_asprintf (&our_env[env_off++], "%s", childpipename); | |||
if (lsocks == NULL || lsocks[0] == INVALID_SOCKET) | GNUNET_free (childpipename); | |||
our_env[2] = NULL; | } | |||
else | if ( (lsocks != NULL) && (lsocks[0] != INVALID_SOCKET)) | |||
{ | { | |||
/*This will tell the child that we're going to send lsocks over the pip e*/ | /*This will tell the child that we're going to send lsocks over the pip e*/ | |||
GNUNET_asprintf (&our_env[2], "%s=", "GNUNET_OS_READ_LSOCKS"); | GNUNET_asprintf (&our_env[env_off++], "%s=", "GNUNET_OS_READ_LSOCKS"); | |||
GNUNET_asprintf (&our_env[3], "%lu", lsocks_read); | GNUNET_asprintf (&our_env[env_off++], "%lu", lsocks_read); | |||
our_env[4] = NULL; | ||||
} | } | |||
our_env[env_off++] = NULL; | ||||
env_block = CreateCustomEnvTable (our_env); | env_block = CreateCustomEnvTable (our_env); | |||
GNUNET_free_non_null (our_env[0]); | while (0 > env_off) | |||
GNUNET_free_non_null (our_env[1]); | GNUNET_free_non_null (our_env[--env_off]); | |||
GNUNET_free_non_null (our_env[2]); | if (ERROR_SUCCESS != plibc_conv_to_win_pathwconv(path, wpath) | |||
GNUNET_free_non_null (our_env[3]); | || ERROR_SUCCESS != plibc_conv_to_win_pathwconv(cmd, wcmd) | |||
|| !CreateProcessW | ||||
if (!CreateProcessA | (wpath, wcmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED, | |||
(path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED, | ||||
env_block, NULL, &start, &proc)) | env_block, NULL, &start, &proc)) | |||
{ | { | |||
SetErrnoFromWinError (GetLastError ()); | SetErrnoFromWinError (GetLastError ()); | |||
LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess"); | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "CreateProcess"); | |||
GNUNET_DISK_npipe_close (control_pipe); | if (NULL != control_pipe) | |||
if (lsocks != NULL) | GNUNET_DISK_file_close (control_pipe); | |||
if (NULL != lsocks) | ||||
GNUNET_DISK_pipe_close (lsocks_pipe); | GNUNET_DISK_pipe_close (lsocks_pipe); | |||
GNUNET_free (env_block); | GNUNET_free (env_block); | |||
GNUNET_free (cmd); | GNUNET_free (cmd); | |||
return NULL; | return NULL; | |||
} | } | |||
GNUNET_free (env_block); | GNUNET_free (env_block); | |||
gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); | gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process)); | |||
gnunet_proc->pid = proc.dwProcessId; | gnunet_proc->pid = proc.dwProcessId; | |||
gnunet_proc->handle = proc.hProcess; | gnunet_proc->handle = proc.hProcess; | |||
gnunet_proc->control_pipe = control_pipe; | gnunet_proc->control_pipe = control_pipe; | |||
CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL ); | CreateThread (NULL, 64000, &child_wait_thread, (void *) gnunet_proc, 0, N ULL); | |||
ResumeThread (proc.hThread); | ResumeThread (proc.hThread); | |||
CloseHandle (proc.hThread); | CloseHandle (proc.hThread); | |||
GNUNET_free (cmd); | GNUNET_free (cmd); | |||
if (lsocks == NULL || lsocks[0] == INVALID_SOCKET) | if (lsocks == NULL || lsocks[0] == INVALID_SOCKET) | |||
return gnunet_proc; | return gnunet_proc; | |||
GNUNET_DISK_pipe_close_end (lsocks_pipe, GNUNET_DISK_PIPE_END_READ); | GNUNET_DISK_pipe_close_end (lsocks_pipe, GNUNET_DISK_PIPE_END_READ); | |||
skipping to change at line 1247 | skipping to change at line 1476 | |||
GNUNET_DISK_file_sync (lsocks_write_fd); | GNUNET_DISK_file_sync (lsocks_write_fd); | |||
GNUNET_DISK_pipe_close (lsocks_pipe); | GNUNET_DISK_pipe_close (lsocks_pipe); | |||
if (fail) | if (fail) | |||
{ | { | |||
/* If we can't pass on the socket(s), the child will block forever, | /* If we can't pass on the socket(s), the child will block forever, | |||
* better put it out of its misery. | * better put it out of its misery. | |||
*/ | */ | |||
TerminateProcess (gnunet_proc->handle, 0); | TerminateProcess (gnunet_proc->handle, 0); | |||
CloseHandle (gnunet_proc->handle); | CloseHandle (gnunet_proc->handle); | |||
GNUNET_DISK_npipe_close (gnunet_proc->control_pipe); | if (NULL != gnunet_proc->control_pipe) | |||
GNUNET_DISK_file_close (gnunet_proc->control_pipe); | ||||
GNUNET_free (gnunet_proc); | GNUNET_free (gnunet_proc); | |||
return NULL; | return NULL; | |||
} | } | |||
return gnunet_proc; | return gnunet_proc; | |||
#endif | #endif | |||
} | } | |||
/** | /** | |||
* Retrieve the status of a process | * Retrieve the status of a process | |||
* @param proc process ID | * @param proc process ID | |||
* @param type status type | * @param type status type | |||
* @param code return code/signal number | * @param code return code/signal number | |||
* @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise | * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise | |||
skipping to change at line 1365 | skipping to change at line 1594 | |||
* Wait for a process | * Wait for a process | |||
* @param proc pointer to process structure | * @param proc pointer to process structure | |||
* @return GNUNET_OK on success, GNUNET_SYSERR otherwise | * @return GNUNET_OK on success, GNUNET_SYSERR otherwise | |||
*/ | */ | |||
int | int | |||
GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc) | GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc) | |||
{ | { | |||
#ifndef MINGW | #ifndef MINGW | |||
pid_t pid = proc->pid; | pid_t pid = proc->pid; | |||
pid_t ret; | ||||
if (pid != waitpid (pid, NULL, 0)) | while ( (pid != (ret = waitpid (pid, NULL, 0))) && | |||
(EINTR == errno) ) ; | ||||
if (pid != ret) | ||||
{ | ||||
LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "waitpid"); | ||||
return GNUNET_SYSERR; | return GNUNET_SYSERR; | |||
} | ||||
return GNUNET_OK; | return GNUNET_OK; | |||
#else | #else | |||
HANDLE h; | HANDLE h; | |||
int ret; | int ret; | |||
h = proc->handle; | h = proc->handle; | |||
if (NULL == h) | if (NULL == h) | |||
{ | { | |||
LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X} \n", | LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X} \n", | |||
proc->pid, h); | proc->pid, h); | |||
skipping to change at line 1544 | skipping to change at line 1779 | |||
struct GNUNET_OS_CommandHandle * | struct GNUNET_OS_CommandHandle * | |||
GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls, | GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls, | |||
struct GNUNET_TIME_Relative timeout, const char *bin ary, | struct GNUNET_TIME_Relative timeout, const char *bin ary, | |||
...) | ...) | |||
{ | { | |||
struct GNUNET_OS_CommandHandle *cmd; | struct GNUNET_OS_CommandHandle *cmd; | |||
struct GNUNET_OS_Process *eip; | struct GNUNET_OS_Process *eip; | |||
struct GNUNET_DISK_PipeHandle *opipe; | struct GNUNET_DISK_PipeHandle *opipe; | |||
va_list ap; | va_list ap; | |||
opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES); | opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES); | |||
if (NULL == opipe) | if (NULL == opipe) | |||
return NULL; | return NULL; | |||
va_start (ap, binary); | va_start (ap, binary); | |||
eip = GNUNET_OS_start_process_va (NULL, opipe, binary, ap); | eip = GNUNET_OS_start_process_va (GNUNET_NO, NULL, opipe, binary, ap); | |||
va_end (ap); | va_end (ap); | |||
if (NULL == eip) | if (NULL == eip) | |||
{ | { | |||
GNUNET_DISK_pipe_close (opipe); | GNUNET_DISK_pipe_close (opipe); | |||
return NULL; | return NULL; | |||
} | } | |||
GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE); | GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE); | |||
cmd = GNUNET_malloc (sizeof (struct GNUNET_OS_CommandHandle)); | cmd = GNUNET_malloc (sizeof (struct GNUNET_OS_CommandHandle)); | |||
cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout); | cmd->timeout = GNUNET_TIME_relative_to_absolute (timeout); | |||
cmd->eip = eip; | cmd->eip = eip; | |||
End of changes. 108 change blocks. | ||||
325 lines changed or deleted | 577 lines changed or added | |||
This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |