#include "apr_arch_threadproc.h"
#include "apr_arch_file_io.h"
#include "apr_thread_proc.h"
#include "apr_file_io.h"
#include "apr_general.h"
#include "apr_strings.h"
#include "apr_portable.h"
#include "apr_lib.h"
#include <stdlib.h>
#if APR_HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <string.h>
#if APR_HAVE_PROCESS_H
#include <process.h>
#endif
static apr_file_t no_file = { NULL, INVALID_HANDLE_VALUE, };
#ifndef LOGON32_LOGON_NETWORK
#define LOGON32_LOGON_NETWORK 3
#endif
#ifdef _WIN32_WCE
#ifndef DETACHED_PROCESS
#define DETACHED_PROCESS 0
#endif
#ifndef CREATE_UNICODE_ENVIRONMENT
#define CREATE_UNICODE_ENVIRONMENT 0
#endif
#ifndef STARTF_USESHOWWINDOW
#define STARTF_USESHOWWINDOW 0
#endif
#ifndef SW_HIDE
#define SW_HIDE 0
#endif
#endif
APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new,
apr_pool_t *pool)
{
(*new) = (apr_procattr_t *)apr_pcalloc(pool, sizeof(apr_procattr_t));
(*new)->pool = pool;
(*new)->cmdtype = APR_PROGRAM;
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr,
apr_int32_t in,
apr_int32_t out,
apr_int32_t err)
{
apr_status_t stat = APR_SUCCESS;
if (in) {
if (in == APR_CHILD_BLOCK)
in = APR_READ_BLOCK;
else if (in == APR_PARENT_BLOCK)
in = APR_WRITE_BLOCK;
if (in == APR_NO_FILE)
attr->child_in = &no_file;
else {
stat = apr_file_pipe_create_ex(&attr->child_in, &attr->parent_in,
in, attr->pool);
}
if (stat == APR_SUCCESS)
stat = apr_file_inherit_unset(attr->parent_in);
}
if (out && stat == APR_SUCCESS) {
if (out == APR_NO_FILE)
attr->child_out = &no_file;
else {
stat = apr_file_pipe_create_ex(&attr->parent_out, &attr->child_out,
out, attr->pool);
}
if (stat == APR_SUCCESS)
stat = apr_file_inherit_unset(attr->parent_out);
}
if (err && stat == APR_SUCCESS) {
if (err == APR_NO_FILE)
attr->child_err = &no_file;
else {
stat = apr_file_pipe_create_ex(&attr->parent_err, &attr->child_err,
err, attr->pool);
}
if (stat == APR_SUCCESS)
stat = apr_file_inherit_unset(attr->parent_err);
}
return stat;
}
APR_DECLARE(apr_status_t) apr_procattr_child_in_set(apr_procattr_t *attr,
apr_file_t *child_in,
apr_file_t *parent_in)
{
apr_status_t rv = APR_SUCCESS;
if (child_in) {
if ((attr->child_in == NULL) || (attr->child_in == &no_file))
rv = apr_file_dup(&attr->child_in, child_in, attr->pool);
else
rv = apr_file_dup2(attr->child_in, child_in, attr->pool);
if (rv == APR_SUCCESS)
rv = apr_file_inherit_set(attr->child_in);
}
if (parent_in && rv == APR_SUCCESS) {
if (attr->parent_in == NULL)
rv = apr_file_dup(&attr->parent_in, parent_in, attr->pool);
else
rv = apr_file_dup2(attr->parent_in, parent_in, attr->pool);
}
return rv;
}
APR_DECLARE(apr_status_t) apr_procattr_child_out_set(apr_procattr_t *attr,
apr_file_t *child_out,
apr_file_t *parent_out)
{
apr_status_t rv = APR_SUCCESS;
if (child_out) {
if ((attr->child_out == NULL) || (attr->child_out == &no_file))
rv = apr_file_dup(&attr->child_out, child_out, attr->pool);
else
rv = apr_file_dup2(attr->child_out, child_out, attr->pool);
if (rv == APR_SUCCESS)
rv = apr_file_inherit_set(attr->child_out);
}
if (parent_out && rv == APR_SUCCESS) {
if (attr->parent_out == NULL)
rv = apr_file_dup(&attr->parent_out, parent_out, attr->pool);
else
rv = apr_file_dup2(attr->parent_out, parent_out, attr->pool);
}
return rv;
}
APR_DECLARE(apr_status_t) apr_procattr_child_err_set(apr_procattr_t *attr,
apr_file_t *child_err,
apr_file_t *parent_err)
{
apr_status_t rv = APR_SUCCESS;
if (child_err) {
if ((attr->child_err == NULL) || (attr->child_err == &no_file))
rv = apr_file_dup(&attr->child_err, child_err, attr->pool);
else
rv = apr_file_dup2(attr->child_err, child_err, attr->pool);
if (rv == APR_SUCCESS)
rv = apr_file_inherit_set(attr->child_err);
}
if (parent_err && rv == APR_SUCCESS) {
if (attr->parent_err == NULL)
rv = apr_file_dup(&attr->parent_err, parent_err, attr->pool);
else
rv = apr_file_dup2(attr->parent_err, parent_err, attr->pool);
}
return rv;
}
APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr,
const char *dir)
{
return apr_filepath_merge(&attr->currdir, NULL, dir,
APR_FILEPATH_NATIVE, attr->pool);
}
APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr,
apr_cmdtype_e cmd)
{
attr->cmdtype = cmd;
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr,
apr_int32_t det)
{
attr->detached = det;
return APR_SUCCESS;
}
#ifndef _WIN32_WCE
static apr_status_t attr_cleanup(void *theattr)
{
apr_procattr_t *attr = (apr_procattr_t *)theattr;
if (attr->user_token)
CloseHandle(attr->user_token);
attr->user_token = NULL;
return APR_SUCCESS;
}
#endif
APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr,
const char *username,
const char *password)
{
#ifdef _WIN32_WCE
return APR_ENOTIMPL;
#else
HANDLE user;
apr_wchar_t *wusername = NULL;
apr_wchar_t *wpassword = NULL;
apr_status_t rv;
apr_size_t len, wlen;
if (apr_os_level >= APR_WIN_NT_4)
{
if (attr->user_token) {
if (attr->errfn) {
attr->errfn(attr->pool, 0,
apr_pstrcat(attr->pool,
"function called twice"
" on username: ", username, NULL));
}
return APR_EINVAL;
}
len = strlen(username) + 1;
wlen = len;
wusername = apr_palloc(attr->pool, wlen * sizeof(apr_wchar_t));
if ((rv = apr_conv_utf8_to_ucs2(username, &len, wusername, &wlen))
!= APR_SUCCESS) {
if (attr->errfn) {
attr->errfn(attr->pool, rv,
apr_pstrcat(attr->pool,
"utf8 to ucs2 conversion failed"
" on username: ", username, NULL));
}
return rv;
}
if (password) {
len = strlen(password) + 1;
wlen = len;
wpassword = apr_palloc(attr->pool, wlen * sizeof(apr_wchar_t));
if ((rv = apr_conv_utf8_to_ucs2(password, &len, wpassword, &wlen))
!= APR_SUCCESS) {
if (attr->errfn) {
attr->errfn(attr->pool, rv,
apr_pstrcat(attr->pool,
"utf8 to ucs2 conversion failed"
" on password: ", password, NULL));
}
return rv;
}
}
if (!LogonUserW(wusername,
NULL,
wpassword ? wpassword : L"",
LOGON32_LOGON_NETWORK,
LOGON32_PROVIDER_DEFAULT,
&user)) {
return apr_get_os_error();
}
if (wpassword)
memset(wpassword, 0, wlen * sizeof(apr_wchar_t));
if (!DuplicateTokenEx(user,
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
NULL,
SecurityImpersonation,
TokenPrimary,
&(attr->user_token))) {
rv = apr_get_os_error();
CloseHandle(user);
return rv;
}
CloseHandle(user);
attr->sd = apr_pcalloc(attr->pool, SECURITY_DESCRIPTOR_MIN_LENGTH);
InitializeSecurityDescriptor(attr->sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(attr->sd, -1, 0, 0);
attr->sa = apr_palloc(attr->pool, sizeof(SECURITY_ATTRIBUTES));
attr->sa->nLength = sizeof (SECURITY_ATTRIBUTES);
attr->sa->lpSecurityDescriptor = attr->sd;
attr->sa->bInheritHandle = FALSE;
apr_pool_cleanup_register(attr->pool, (void *)attr,
attr_cleanup,
apr_pool_cleanup_null);
return APR_SUCCESS;
}
else
return APR_ENOTIMPL;
#endif
}
APR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr,
const char *groupname)
{
return APR_SUCCESS;
}
static const char* has_space(const char *str)
{
const char *ch;
for (ch = str; *ch; ++ch) {
if (apr_isspace(*ch)) {
return ch;
}
}
return NULL;
}
static char *apr_caret_escape_args(apr_pool_t *p, const char *str)
{
char *cmd;
unsigned char *d;
const unsigned char *s;
cmd = apr_palloc(p, 2 * strlen(str) + 1);
d = (unsigned char *)cmd;
s = (const unsigned char *)str;
for (; *s; ++s) {
if (*s == '\r' || *s == '\n') {
*d++ = ' ';
continue;
}
if (IS_SHCHAR(*s)) {
*d++ = '^';
}
*d++ = *s;
}
*d = '\0';
return cmd;
}
APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr,
apr_child_errfn_t *errfn)
{
attr->errfn = errfn;
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr,
apr_int32_t chk)
{
attr->errchk = chk;
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr,
apr_int32_t addrspace)
{
return APR_SUCCESS;
}
#if APR_HAS_UNICODE_FS && !defined(_WIN32_WCE)
static CRITICAL_SECTION proc_lock;
static apr_status_t threadproc_global_cleanup(void *ignored)
{
DeleteCriticalSection(&proc_lock);
return APR_SUCCESS;
}
apr_status_t apr_threadproc_init(apr_pool_t *pool)
{
IF_WIN_OS_IS_UNICODE
{
InitializeCriticalSection(&proc_lock);
apr_pool_cleanup_register(pool, &proc_lock,
threadproc_global_cleanup,
apr_pool_cleanup_null);
}
return APR_SUCCESS;
}
#else
apr_status_t apr_threadproc_init(apr_pool_t *pool)
{
return APR_SUCCESS;
}
#endif
APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new,
const char *progname,
const char * const *args,
const char * const *env,
apr_procattr_t *attr,
apr_pool_t *pool)
{
apr_status_t rv;
apr_size_t i;
const char *argv0;
char *cmdline;
char *pEnvBlock;
PROCESS_INFORMATION pi;
DWORD dwCreationFlags = 0;
new->in = attr->parent_in;
new->out = attr->parent_out;
new->err = attr->parent_err;
if (attr->detached) {
if (apr_os_level >= APR_WIN_NT) {
dwCreationFlags |= DETACHED_PROCESS;
}
}
if (progname[0] == '\"') {
progname = apr_pstrndup(pool, progname + 1, strlen(progname) - 2);
}
if (attr->cmdtype == APR_PROGRAM || attr->cmdtype == APR_PROGRAM_ENV) {
char *fullpath = NULL;
if ((rv = apr_filepath_merge(&fullpath, attr->currdir, progname,
APR_FILEPATH_NATIVE, pool)) != APR_SUCCESS) {
if (attr->errfn) {
attr->errfn(pool, rv,
apr_pstrcat(pool, "filepath_merge failed.",
" currdir: ", attr->currdir,
" progname: ", progname, NULL));
}
return rv;
}
progname = fullpath;
}
else {
char *fullpath = NULL;
if ((rv = apr_filepath_merge(&fullpath, "", progname,
APR_FILEPATH_NATIVE, pool)) == APR_SUCCESS) {
progname = fullpath;
}
}
if (has_space(progname)) {
argv0 = apr_pstrcat(pool, "\"", progname, "\"", NULL);
}
else {
argv0 = progname;
}
cmdline = "";
for (i = 1; args && args[i]; ++i) {
if (has_space(args[i]) || !args[i][0]) {
cmdline = apr_pstrcat(pool, cmdline, " \"", args[i], "\"", NULL);
}
else {
cmdline = apr_pstrcat(pool, cmdline, " ", args[i], NULL);
}
}
#ifndef _WIN32_WCE
if (attr->cmdtype == APR_SHELLCMD || attr->cmdtype == APR_SHELLCMD_ENV) {
char *shellcmd = getenv("COMSPEC");
if (!shellcmd) {
if (attr->errfn) {
attr->errfn(pool, APR_EINVAL, "COMSPEC envar is not set");
}
return APR_EINVAL;
}
if (shellcmd[0] == '"') {
progname = apr_pstrndup(pool, shellcmd + 1, strlen(shellcmd) - 2);
}
else {
progname = shellcmd;
if (has_space(shellcmd)) {
shellcmd = apr_pstrcat(pool, "\"", shellcmd, "\"", NULL);
}
}
i = strlen(progname);
if (i >= 11 && strcasecmp(progname + i - 11, "command.com") == 0) {
cmdline = apr_pstrcat(pool, shellcmd, " /C ", argv0, cmdline, NULL);
}
else {
cmdline = apr_pstrcat(pool, shellcmd, " /C \"", argv0, cmdline, "\"", NULL);
}
}
else
#endif
{
#if defined(_WIN32_WCE)
{
#else
i = strlen(progname);
if (i >= 4 && (strcasecmp(progname + i - 4, ".bat") == 0
|| strcasecmp(progname + i - 4, ".cmd") == 0))
{
char *shellcmd = getenv("COMSPEC");
if (!shellcmd) {
if (attr->errfn) {
attr->errfn(pool, APR_EINVAL, "COMSPEC envar is not set");
}
return APR_EINVAL;
}
if (shellcmd[0] == '"') {
progname = apr_pstrndup(pool, shellcmd + 1, strlen(shellcmd) - 2);
}
else {
progname = shellcmd;
if (has_space(shellcmd)) {
shellcmd = apr_pstrcat(pool, "\"", shellcmd, "\"", NULL);
}
}
i = strlen(progname);
if (i >= 11 && strcasecmp(progname + i - 11, "command.com") == 0) {
cmdline = apr_pstrcat(pool, shellcmd, " /C ", argv0, cmdline, NULL);
}
else {
cmdline = apr_caret_escape_args(pool, cmdline);
if (*argv0 != '"') {
cmdline = apr_pstrcat(pool, shellcmd, " /C \"\"", argv0, "\"", cmdline, "\"", NULL);
}
else {
cmdline = apr_pstrcat(pool, shellcmd, " /C \"", argv0, cmdline, "\"", NULL);
}
}
}
else {
#endif
cmdline = apr_pstrcat(pool, argv0, cmdline, NULL);
if (attr->cmdtype == APR_PROGRAM_PATH) {
progname = NULL;
}
}
}
if (!env || attr->cmdtype == APR_PROGRAM_ENV ||
attr->cmdtype == APR_SHELLCMD_ENV) {
pEnvBlock = NULL;
}
else {
apr_size_t iEnvBlockLen;
i = 0;
iEnvBlockLen = 1;
while (env[i]) {
iEnvBlockLen += strlen(env[i]) + 1;
i++;
}
if (!i)
++iEnvBlockLen;
#if APR_HAS_UNICODE_FS
IF_WIN_OS_IS_UNICODE
{
apr_wchar_t *pNext;
pEnvBlock = (char *)apr_palloc(pool, iEnvBlockLen * 2);
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
i = 0;
pNext = (apr_wchar_t*)pEnvBlock;
while (env[i]) {
apr_size_t in = strlen(env[i]) + 1;
if ((rv = apr_conv_utf8_to_ucs2(env[i], &in,
pNext, &iEnvBlockLen))
!= APR_SUCCESS) {
if (attr->errfn) {
attr->errfn(pool, rv,
apr_pstrcat(pool,
"utf8 to ucs2 conversion failed"
" on this string: ", env[i], NULL));
}
return rv;
}
pNext = wcschr(pNext, L'\0') + 1;
i++;
}
if (!i)
*(pNext++) = L'\0';
*pNext = L'\0';
}
#endif
#if APR_HAS_ANSI_FS
ELSE_WIN_OS_IS_ANSI
{
char *pNext;
pEnvBlock = (char *)apr_palloc(pool, iEnvBlockLen);
i = 0;
pNext = pEnvBlock;
while (env[i]) {
strcpy(pNext, env[i]);
pNext = strchr(pNext, '\0') + 1;
i++;
}
if (!i)
*(pNext++) = '\0';
*pNext = '\0';
}
#endif
}
new->invoked = cmdline;
#if APR_HAS_UNICODE_FS
IF_WIN_OS_IS_UNICODE
{
STARTUPINFOW si;
DWORD stdin_reset = 0;
DWORD stdout_reset = 0;
DWORD stderr_reset = 0;
apr_wchar_t *wprg = NULL;
apr_wchar_t *wcmd = NULL;
apr_wchar_t *wcwd = NULL;
if (progname) {
apr_size_t nprg = strlen(progname) + 1;
apr_size_t nwprg = nprg + 6;
wprg = apr_palloc(pool, nwprg * sizeof(wprg[0]));
if ((rv = apr_conv_utf8_to_ucs2(progname, &nprg, wprg, &nwprg))
!= APR_SUCCESS) {
if (attr->errfn) {
attr->errfn(pool, rv,
apr_pstrcat(pool,
"utf8 to ucs2 conversion failed"
" on progname: ", progname, NULL));
}
return rv;
}
}
if (cmdline) {
apr_size_t ncmd = strlen(cmdline) + 1;
apr_size_t nwcmd = ncmd;
wcmd = apr_palloc(pool, nwcmd * sizeof(wcmd[0]));
if ((rv = apr_conv_utf8_to_ucs2(cmdline, &ncmd, wcmd, &nwcmd))
!= APR_SUCCESS) {
if (attr->errfn) {
attr->errfn(pool, rv,
apr_pstrcat(pool,
"utf8 to ucs2 conversion failed"
" on cmdline: ", cmdline, NULL));
}
return rv;
}
}
if (attr->currdir)
{
apr_size_t ncwd = strlen(attr->currdir) + 1;
apr_size_t nwcwd = ncwd;
wcwd = apr_palloc(pool, ncwd * sizeof(wcwd[0]));
if ((rv = apr_conv_utf8_to_ucs2(attr->currdir, &ncwd,
wcwd, &nwcwd))
!= APR_SUCCESS) {
if (attr->errfn) {
attr->errfn(pool, rv,
apr_pstrcat(pool,
"utf8 to ucs2 conversion failed"
" on currdir: ", attr->currdir, NULL));
}
return rv;
}
}
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if (attr->detached) {
si.dwFlags |= STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
}
#ifndef _WIN32_WCE
EnterCriticalSection(&proc_lock);
if ((attr->child_in && attr->child_in->filehand)
|| (attr->child_out && attr->child_out->filehand)
|| (attr->child_err && attr->child_err->filehand))
{
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
if (attr->child_in && attr->child_in->filehand)
{
if (GetHandleInformation(si.hStdInput,
&stdin_reset)
&& (stdin_reset &= HANDLE_FLAG_INHERIT))
SetHandleInformation(si.hStdInput,
HANDLE_FLAG_INHERIT, 0);
if ( (si.hStdInput = attr->child_in->filehand)
!= INVALID_HANDLE_VALUE )
SetHandleInformation(si.hStdInput, HANDLE_FLAG_INHERIT,
HANDLE_FLAG_INHERIT);
}
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
if (attr->child_out && attr->child_out->filehand)
{
if (GetHandleInformation(si.hStdOutput,
&stdout_reset)
&& (stdout_reset &= HANDLE_FLAG_INHERIT))
SetHandleInformation(si.hStdOutput,
HANDLE_FLAG_INHERIT, 0);
if ( (si.hStdOutput = attr->child_out->filehand)
!= INVALID_HANDLE_VALUE )
SetHandleInformation(si.hStdOutput, HANDLE_FLAG_INHERIT,
HANDLE_FLAG_INHERIT);
}
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
if (attr->child_err && attr->child_err->filehand)
{
if (GetHandleInformation(si.hStdError,
&stderr_reset)
&& (stderr_reset &= HANDLE_FLAG_INHERIT))
SetHandleInformation(si.hStdError,
HANDLE_FLAG_INHERIT, 0);
if ( (si.hStdError = attr->child_err->filehand)
!= INVALID_HANDLE_VALUE )
SetHandleInformation(si.hStdError, HANDLE_FLAG_INHERIT,
HANDLE_FLAG_INHERIT);
}
}
if (attr->user_token) {
si.lpDesktop = L"Winsta0\\Default";
if (!ImpersonateLoggedOnUser(attr->user_token)) {
rv = apr_get_os_error();
CloseHandle(attr->user_token);
attr->user_token = NULL;
return rv;
}
rv = CreateProcessAsUserW(attr->user_token,
wprg, wcmd,
attr->sa,
NULL,
TRUE,
dwCreationFlags,
pEnvBlock,
wcwd,
&si, &pi);
RevertToSelf();
}
else {
rv = CreateProcessW(wprg, wcmd,
NULL, NULL,
TRUE,
dwCreationFlags,
pEnvBlock,
wcwd,
&si, &pi);
}
if ((attr->child_in && attr->child_in->filehand)
|| (attr->child_out && attr->child_out->filehand)
|| (attr->child_err && attr->child_err->filehand))
{
if (stdin_reset)
SetHandleInformation(GetStdHandle(STD_INPUT_HANDLE),
stdin_reset, stdin_reset);
if (stdout_reset)
SetHandleInformation(GetStdHandle(STD_OUTPUT_HANDLE),
stdout_reset, stdout_reset);
if (stderr_reset)
SetHandleInformation(GetStdHandle(STD_ERROR_HANDLE),
stderr_reset, stderr_reset);
}
LeaveCriticalSection(&proc_lock);
#else
rv = CreateProcessW(wprg, wcmd,
NULL, NULL,
FALSE,
dwCreationFlags,
NULL,
NULL,
NULL,
&pi);
#endif
}
#endif
#if APR_HAS_ANSI_FS
ELSE_WIN_OS_IS_ANSI
{
STARTUPINFOA si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if (attr->detached) {
si.dwFlags |= STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
}
if ((attr->child_in && attr->child_in->filehand)
|| (attr->child_out && attr->child_out->filehand)
|| (attr->child_err && attr->child_err->filehand))
{
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdInput = (attr->child_in)
? attr->child_in->filehand
: GetStdHandle(STD_INPUT_HANDLE);
si.hStdOutput = (attr->child_out)
? attr->child_out->filehand
: GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = (attr->child_err)
? attr->child_err->filehand
: GetStdHandle(STD_ERROR_HANDLE);
}
rv = CreateProcessA(progname, cmdline,
NULL, NULL,
TRUE,
dwCreationFlags,
pEnvBlock,
attr->currdir,
&si, &pi);
}
#endif
if (!rv)
return apr_get_os_error();
new->hproc = pi.hProcess;
new->pid = pi.dwProcessId;
if ((attr->child_in) && (attr->child_in != &no_file)) {
apr_file_close(attr->child_in);
}
if ((attr->child_out) && (attr->child_out != &no_file)) {
apr_file_close(attr->child_out);
}
if ((attr->child_err) && (attr->child_err != &no_file)) {
apr_file_close(attr->child_err);
}
CloseHandle(pi.hThread);
return APR_SUCCESS;
}
static apr_exit_why_e why_from_exit_code(DWORD exit) {
if (((exit & 0xC0000000) == 0xC0000000)
&& !(exit & 0x3FFF0000))
return APR_PROC_SIGNAL;
else
return APR_PROC_EXIT;
}
APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc,
int *exitcode,
apr_exit_why_e *exitwhy,
apr_wait_how_e waithow,
apr_pool_t *p)
{
#if APR_HAS_UNICODE_FS
#ifndef _WIN32_WCE
IF_WIN_OS_IS_UNICODE
{
DWORD dwId = GetCurrentProcessId();
DWORD i;
DWORD nChilds = 0;
DWORD nActive = 0;
HANDLE ps32;
PROCESSENTRY32W pe32;
BOOL bHasMore = FALSE;
DWORD dwFlags = PROCESS_QUERY_INFORMATION;
apr_status_t rv = APR_EGENERAL;
if (waithow == APR_WAIT)
dwFlags |= SYNCHRONIZE;
if (!(ps32 = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0))) {
return apr_get_os_error();
}
pe32.dwSize = sizeof(PROCESSENTRY32W);
if (!Process32FirstW(ps32, &pe32)) {
if (GetLastError() == ERROR_NO_MORE_FILES)
return APR_EOF;
else
return apr_get_os_error();
}
do {
DWORD dwRetval = 0;
DWORD nHandles = 0;
HANDLE hProcess = NULL;
HANDLE pHandles[MAXIMUM_WAIT_OBJECTS];
do {
if (pe32.th32ParentProcessID == dwId) {
nChilds++;
if ((hProcess = OpenProcess(dwFlags, FALSE,
pe32.th32ProcessID)) != NULL) {
if (GetExitCodeProcess(hProcess, &dwRetval)) {
if (dwRetval == STILL_ACTIVE) {
nActive++;
if (waithow == APR_WAIT)
pHandles[nHandles++] = hProcess;
else
CloseHandle(hProcess);
}
else {
CloseHandle(hProcess);
if (exitcode)
*exitcode = dwRetval;
if (exitwhy)
*exitwhy = why_from_exit_code(dwRetval);
proc->pid = pe32.th32ProcessID;
}
}
else {
rv = apr_get_os_error();
CloseHandle(hProcess);
for (i = 0; i < nHandles; i++)
CloseHandle(pHandles[i]);
return rv;
}
}
else {
}
}
} while ((bHasMore = Process32NextW(ps32, &pe32)) &&
nHandles < MAXIMUM_WAIT_OBJECTS);
if (nHandles) {
DWORD waitStatus = WaitForMultipleObjects(nHandles, pHandles,
TRUE, INFINITE);
for (i = 0; i < nHandles; i++)
CloseHandle(pHandles[i]);
if (waitStatus == WAIT_OBJECT_0) {
nActive -= nHandles;
}
else {
break;
}
}
} while (bHasMore);
CloseHandle(ps32);
if (waithow != APR_WAIT) {
if (nChilds && nChilds == nActive) {
rv = APR_CHILD_NOTDONE;
proc->pid = -1;
}
else {
rv = APR_CHILD_DONE;
}
}
if (nActive == 0) {
rv = APR_CHILD_DONE;
proc->pid = -1;
}
return rv;
}
#endif
#endif
return APR_ENOTIMPL;
}
APR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc,
int *exitcode, apr_exit_why_e *exitwhy,
apr_wait_how_e waithow)
{
DWORD stat;
DWORD time;
if (waithow == APR_WAIT)
time = INFINITE;
else
time = 0;
if ((stat = WaitForSingleObject(proc->hproc, time)) == WAIT_OBJECT_0) {
if (GetExitCodeProcess(proc->hproc, &stat)) {
if (exitcode)
*exitcode = stat;
if (exitwhy)
*exitwhy = why_from_exit_code(stat);
CloseHandle(proc->hproc);
proc->hproc = NULL;
return APR_CHILD_DONE;
}
}
else if (stat == WAIT_TIMEOUT) {
return APR_CHILD_NOTDONE;
}
return apr_get_os_error();
}
APR_DECLARE(apr_status_t) apr_proc_detach(int daemonize)
{
return APR_ENOTIMPL;
}