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 &current_process; return &current_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/