You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mt...@apache.org on 2011/04/28 15:22:15 UTC
svn commit: r1097447 - in /commons/sandbox/runtime/trunk/src/main:
java/org/apache/commons/runtime/platform/windows/ native/include/acr/
native/os/win32/ test/org/apache/commons/runtime/
Author: mturk
Date: Thu Apr 28 13:22:14 2011
New Revision: 1097447
URL: http://svn.apache.org/viewvc?rev=1097447&view=rev
Log:
Implement initial win32 Exec
Modified:
commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/platform/windows/WindowsExec.java
commons/sandbox/runtime/trunk/src/main/native/include/acr/iodefs.h
commons/sandbox/runtime/trunk/src/main/native/os/win32/arch_opts.h
commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c
commons/sandbox/runtime/trunk/src/main/native/os/win32/util.c
commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestExec.java
Modified: commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/platform/windows/WindowsExec.java
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/platform/windows/WindowsExec.java?rev=1097447&r1=1097446&r2=1097447&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/platform/windows/WindowsExec.java (original)
+++ commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/platform/windows/WindowsExec.java Thu Apr 28 13:22:14 2011
@@ -20,6 +20,10 @@ import org.apache.commons.runtime.Errno;
import org.apache.commons.runtime.Status;
import org.apache.commons.runtime.InvalidArgumentException;
import org.apache.commons.runtime.SystemException;
+import java.io.ByteArrayOutputStream;
+import java.io.CharArrayWriter;
+import java.io.OutputStream;
+import java.util.List;
/**
* WindowsExec class.
@@ -35,5 +39,65 @@ final class WindowsExec extends Exec
{
}
+ private static native long run0(String executable,
+ String cmdline,
+ char[] envb,
+ String cwd,
+ byte[] inp,
+ ByteArrayOutputStream out,
+ ByteArrayOutputStream err,
+ int timeout);
+ public int run(List<String> argv)
+ {
+ String executable = null;
+ StringBuffer args = new StringBuffer();
+
+ for (String s : argv) {
+ if (executable == null) {
+ executable = s;
+ // TODO: Check for both SPACE and TAB
+ // Make sure quotes are properly handled.
+ if (executable.indexOf(' ') != -1) {
+ args.append('"');
+ args.append(executable);
+ args.append('"');
+ }
+ else
+ args.append(executable);
+ }
+ else {
+ args.append(' ');
+ if (s.indexOf(' ') != -1) {
+ args.append('"');
+ args.append(s);
+ args.append('"');
+ }
+ else
+ args.append(s);
+ }
+ }
+ if (executable == null) {
+ return Status.PARENT_ERROR;
+ }
+ char [] envb = null;
+ if (env != null) {
+ CharArrayWriter ew = new CharArrayWriter();
+ for (int i = 0; i < env.length; i++) {
+ try {
+ ew.write(env[i]);
+ ew.append('\0');
+ } catch (Exception x) {
+ //TODO: Handle OOM errors
+ }
+ }
+ ew.append('\0');
+ envb = ew.toCharArray();
+ }
+ long rv = run0(executable, args.toString(), envb, cwd, inp, out, err, timeout);
+ exitval = (int)(rv & 0xffffffffL);
+ int res = (int)(rv >>> 32);
+
+ return res;
+ }
}
Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr/iodefs.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr/iodefs.h?rev=1097447&r1=1097446&r2=1097447&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr/iodefs.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr/iodefs.h Thu Apr 28 13:22:14 2011
@@ -29,5 +29,10 @@
#define ACR_PIPE_MODE_MASK 0x000F
#define ACR_PIPE_NOINHERIT 0x0010
+#define ACR_FOPEN_RDONLY 0x000000 /**< Open the file for reading */
+#define ACR_FOPEN_WRITE 0x000001 /**< Open the file for writing */
+#define ACR_FOPEN_RW 0x000002 /**< Convenience for READ | WRITE */
+#define ACR_FOPEN_NOINHERIT 0x010000 /**< Do not inherit files on exec */
+#define ACR_FOPEN_INFO 0x020000 /**< Open without READ or WRITE access */
#endif /* _ACR_IODEFS_H */
Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/arch_opts.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/arch_opts.h?rev=1097447&r1=1097446&r2=1097447&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/arch_opts.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/arch_opts.h Thu Apr 28 13:22:14 2011
@@ -233,4 +233,7 @@ ACR_INLINE(void) MsecTimeToFileTime(LPFI
return;
}
+HANDLE AcrNullPipe(int flags, int fd);
+int AcrPipePair(HANDLE *rd, HANDLE *wr, int flags, char *name);
+
#endif /* _ACR_ARCH_OPTS_H_ */
Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c?rev=1097447&r1=1097446&r2=1097447&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c Thu Apr 28 13:22:14 2011
@@ -27,22 +27,17 @@
#define PROC_TIMEOUT_STEP 100
#define PROC_BUFFER_SIZE 512
-#define PIPE_STDINP 0
#define PIPE_STDINP_RDS 0
#define PIPE_STDINP_WRS 1
-#define PIPE_STDOUT 2
#define PIPE_STDOUT_RDS 2
#define PIPE_STDOUT_WRS 3
-#define PIPE_STDERR 4
#define PIPE_STDERR_RDS 4
#define PIPE_STDERR_WRS 5
-#define PIPE_SIGERR 6
-#define PIPE_SIGERR_RDS 6
-#define PIPE_SIGERR_WRS 7
-#define PIPE_SIGPID 8
-#define PIPE_SIGPID_RDS 8
-#define PIPE_SIGPID_WRS 9
-#define PIPE_COUNT 10
+#define PIPE_COUNT 6
+#define SIGKILL 9
+
+static CRITICAL_SECTION _procmgr_lock;
+static wchar_t *SHELL_PATH;
J_DECLARE_CLAZZ = {
INVALID_FIELD_OFFSET,
@@ -58,10 +53,27 @@ J_DECLARE_M_ID(0000) = {
"()V"
};
+static int _procmgr_init(void)
+{
+ InitializeCriticalSection(&_procmgr_lock);
+
+ SHELL_PATH = _wgetenv(L"COMSPEC");
+ if (SHELL_PATH == 0) {
+ wchar_t b[PATH_MAX];
+ UINT r;
+ r = GetSystemDirectoryW(b, PATH_MAX - 10);
+ if (r == 0 || r > (PATH_MAX - 10))
+ wcscpy(b, L"C:\\Windows\\System32\\cmd.exe");
+ else
+ wcscat(b, L"\\cmd.exe");
+ SHELL_PATH = wcsdup(b);
+ }
+ return 0;
+}
static int _run_exec(const wchar_t *executable,
- const wchar_t *cmdline,
- const wchar_t *envb,
+ wchar_t *argb,
+ wchar_t *envb,
const wchar_t *workdir,
acr_buf_t *out,
acr_buf_t *err,
@@ -69,6 +81,436 @@ static int _run_exec(const wchar_t *exec
int timeout,
int *retval)
{
+ PROCESS_INFORMATION pi;
+ STARTUPINFOW si;
+ BOOL rs;
+ int i, rc = 0;
+ int exitwhy = 0;
+ int exitval = 0;
+ HANDLE pipes[PIPE_COUNT] = { 0, 0, 0, 0, 0, 0 };
+ HANDLE waithandle[3] = { 0, 0, 0 };
+ HANDLE stdhandles[3] = { 0, 0, 0 };
+ DWORD stdhinfo[3] = { 0, 0, 0 };
+ OVERLAPPED_SBUFF overlap[3];
+ HANDLE cproc = GetCurrentProcess();
+ int sigerr = 0;
+ int detach = 0;
+ DWORD waitn = 0;
+ DWORD cflags = CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED;
+ DWORD dflags;
+ DWORD polltime = INFINITE;
+ int pid;
+ acr_time_t endat = 0;
+ acr_sb_t obuf_s;
+ acr_sb_t ebuf_s;
+ acr_sb_t *obuf = 0;
+ acr_sb_t *ebuf = 0;
+ acr_buf_t ibuf = { 0, 0, 0, 0};
+
+ ACR_MEMZERO(PROCESS_INFORMATION, &pi, 1);
+ ACR_MEMZERO(STARTUPINFOW, &si, 1);
+ ACR_MEMZERO(OVERLAPPED_SBUFF, overlap, 3);
+ si.cb = sizeof(si);
+
+ fflush(stdout);
+ if (timeout == 0)
+ detach = 1;
+ if (!detach) {
+ if (inp != 0 && inp->buf != 0 && inp->len != 0) {
+ if ((rc = AcrPipePair(&pipes[PIPE_STDINP_RDS],
+ &pipes[PIPE_STDINP_WRS],
+ ACR_PIPE_READ_BLOCK, 0)))
+ goto cleanup;
+ ibuf.buf = inp->buf;
+ ibuf.len = inp->len;
+ }
+ if (out != 0) {
+ if ((rc = AcrPipePair(&pipes[PIPE_STDOUT_RDS],
+ &pipes[PIPE_STDOUT_WRS],
+ ACR_PIPE_WRITE_BLOCK, 0)))
+ goto cleanup;
+ if ((rc = AcrSbInitAuto(&obuf_s, PROC_BUFFER_SIZE)))
+ goto cleanup;
+ obuf = &obuf_s;
+ }
+ if (err != 0 && err != out) {
+ if ((rc = AcrPipePair(&pipes[PIPE_STDERR_RDS],
+ &pipes[PIPE_STDERR_WRS],
+ ACR_PIPE_WRITE_BLOCK, 0)))
+ goto cleanup;
+ if ((rc = AcrSbInitAuto(&ebuf_s, PROC_BUFFER_SIZE)))
+ goto cleanup;
+ ebuf = &ebuf_s;
+ }
+ }
+ /* Fill in missing pipes */
+ if (IS_INVALID_HANDLE(pipes[PIPE_STDINP_RDS])) {
+ pipes[PIPE_STDINP_RDS] = AcrNullPipe(GENERIC_READ, -1);
+ if (IS_INVALID_HANDLE(pipes[PIPE_STDINP_RDS])) {
+ rc = ACR_GET_OS_ERROR();
+ goto cleanup;
+ }
+ }
+ if (IS_INVALID_HANDLE(pipes[PIPE_STDOUT_WRS])) {
+ pipes[PIPE_STDOUT_WRS] = AcrNullPipe(GENERIC_WRITE, -1);
+ if (IS_INVALID_HANDLE(pipes[PIPE_STDOUT_WRS])) {
+ rc = ACR_GET_OS_ERROR();
+ goto cleanup;
+ }
+ }
+ if (IS_INVALID_HANDLE(pipes[PIPE_STDERR_WRS])) {
+ if (out == 0) {
+ pipes[PIPE_STDERR_WRS] = AcrNullPipe(GENERIC_WRITE, -1);
+ if (IS_INVALID_HANDLE(pipes[PIPE_STDERR_WRS])) {
+ rc = ACR_GET_OS_ERROR();
+ goto cleanup;
+ }
+ }
+ else
+ pipes[PIPE_STDERR_WRS] = pipes[PIPE_STDOUT_WRS];
+ }
+
+ /* Always use STDHANDLES
+ * They are either real handles or handles to NUL device
+ */
+ si.dwFlags |= STARTF_USESTDHANDLES;
+ dflags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
+ if (!DuplicateHandle(cproc, pipes[PIPE_STDINP_RDS],
+ cproc, &pipes[PIPE_STDINP_RDS],
+ 0, TRUE, dflags)) {
+ rc = ACR_GET_OS_ERROR();
+ goto cleanup;
+ }
+ dflags = DUPLICATE_SAME_ACCESS;
+ if (pipes[PIPE_STDERR_WRS] != pipes[PIPE_STDOUT_WRS])
+ dflags |= DUPLICATE_CLOSE_SOURCE;
+
+ if (!DuplicateHandle(cproc, pipes[PIPE_STDOUT_WRS],
+ cproc, &pipes[PIPE_STDOUT_WRS],
+ 0, TRUE, dflags)) {
+ rc = ACR_GET_OS_ERROR();
+ goto cleanup;
+ }
+ dflags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
+ if (!DuplicateHandle(cproc, pipes[PIPE_STDERR_WRS],
+ cproc, &pipes[PIPE_STDERR_WRS],
+ 0, TRUE, dflags)) {
+ rc = ACR_GET_OS_ERROR();
+ goto cleanup;
+ }
+
+ si.hStdInput = pipes[PIPE_STDINP_RDS];
+ si.hStdOutput = pipes[PIPE_STDOUT_WRS];
+ si.hStdError = pipes[PIPE_STDERR_WRS];
+ if (timeout > 0) {
+ endat = AcrTimeNow() + AcrTimeFromMsec(timeout);
+ polltime = PROC_TIMEOUT_STEP;
+ }
+ stdhandles[0] = GetStdHandle(STD_INPUT_HANDLE);
+ stdhandles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
+ stdhandles[2] = GetStdHandle(STD_ERROR_HANDLE);
+
+ /* Serialize access to STD handles
+ * Since we never inherit std handles directly, make sure their
+ * handle is non inherited.
+ */
+ EnterCriticalSection(&_procmgr_lock);
+ if (IS_INVALID_HANDLE(stdhandles[0]) &&
+ GetHandleInformation(stdhandles[0], &stdhinfo[0]) && (stdhinfo[0] &= HANDLE_FLAG_INHERIT))
+ SetHandleInformation(stdhandles[0], HANDLE_FLAG_INHERIT, 0);
+ if (IS_INVALID_HANDLE(stdhandles[1]) &&
+ GetHandleInformation(stdhandles[1], &stdhinfo[1]) && (stdhinfo[1] &= HANDLE_FLAG_INHERIT))
+ SetHandleInformation(stdhandles[1], HANDLE_FLAG_INHERIT, 0);
+ if (IS_INVALID_HANDLE(stdhandles[2]) &&
+ GetHandleInformation(stdhandles[2], &stdhinfo[2]) && (stdhinfo[2] &= HANDLE_FLAG_INHERIT))
+ SetHandleInformation(stdhandles[2], HANDLE_FLAG_INHERIT, 0);
+ /* Create a child
+ */
+ if (!CreateProcessW(executable, /* Executable */
+ argb, /* Command line */
+ 0,
+ 0, /* Proc & thread security attributes */
+ TRUE, /* Inherit handles */
+ cflags, /* Creation flags */
+ envb, /* Environment block */
+ workdir, /* Current directory name */
+ &si,
+ &pi))
+ rc = ACR_GET_OS_ERROR();
+ else
+ rs = TRUE;
+ /* Restore STD handle inheritance
+ */
+ if (stdhinfo[0])
+ SetHandleInformation(GetStdHandle(STD_INPUT_HANDLE),
+ stdhinfo[0], stdhinfo[0]);
+ if (stdhinfo[1])
+ SetHandleInformation(GetStdHandle(STD_OUTPUT_HANDLE),
+ stdhinfo[1], stdhinfo[1]);
+ if (stdhinfo[2])
+ SetHandleInformation(GetStdHandle(STD_ERROR_HANDLE),
+ stdhinfo[2], stdhinfo[2]);
+ LeaveCriticalSection(&_procmgr_lock);
+ if (rc != 0)
+ goto cleanup;
+ pid = pi.dwProcessId;
+ /* Close our side of the pipes
+ */
+ SAFE_CLOSE_HANDLE(pipes[PIPE_STDINP_RDS]);
+ SAFE_CLOSE_HANDLE(pipes[PIPE_STDOUT_WRS]);
+ SAFE_CLOSE_HANDLE(pipes[PIPE_STDERR_WRS]);
+
+ if (detach) {
+ /* We are done in case of detached process
+ */
+ exitval = pid;
+ exitwhy = ACR_CHILD_NOTDONE;
+ ResumeThread(pi.hThread);
+ goto finished;
+ }
+ /* Setup wait handles
+ */
+ if (IS_VALID_HANDLE(pipes[PIPE_STDOUT_RDS])) {
+ overlap[0].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ waithandle[waitn++] = overlap[0].o.hEvent;
+ }
+ if (IS_VALID_HANDLE(pipes[PIPE_STDERR_RDS]) && (out != err)) {
+ overlap[1].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ waithandle[waitn++] = overlap[1].o.hEvent;
+ }
+ if (IS_VALID_HANDLE(pipes[PIPE_STDINP_WRS])) {
+ overlap[2].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ waithandle[waitn++] = overlap[2].o.hEvent;
+ }
+
+ /* We have created a process with the suspended main thread.
+ * Resume the main process thread.
+ */
+ ResumeThread(pi.hThread);
+ rc = 0;
+
+ /* Sink the console pipes and wait until the child terminates.
+ */
+ do {
+ DWORD ws;
+ DWORD rd, wr;
+ BOOL iostat;
+ if (IS_INVALID_HANDLE(pipes[PIPE_STDINP_WRS]) &&
+ IS_INVALID_HANDLE(pipes[PIPE_STDOUT_RDS]) &&
+ IS_INVALID_HANDLE(pipes[PIPE_STDERR_RDS])) {
+ /* All child pipes are closed.
+ * Bail out
+ */
+ rc = 0;
+ break;
+ }
+ /* Wait for some event.
+ * Note that overlapped Read and Write will be fired immediately
+ * because their events are set on signaled. This usualy means that
+ * the first ReadFile/WriteFile will fail with ERROR_IO_PENDING.
+ */
+ ws = WaitForMultipleObjects(waitn, waithandle, FALSE, polltime);
+ switch (ws) {
+ case WAIT_OBJECT_0:
+ /* Signal on stdout stream
+ */
+ if (IS_VALID_HANDLE(pipes[PIPE_STDOUT_RDS])) {
+ if (overlap[0].stat == ERROR_IO_PENDING) {
+ if (!GetOverlappedResult(pipes[PIPE_STDOUT_RDS],
+ (LPOVERLAPPED)&overlap[0],
+ &rd,
+ FALSE)) {
+ overlap[0].stat = GetLastError();
+ }
+ else {
+ overlap[0].stat = 0;
+ rd = AcrSbCatb(obuf, overlap[0].buff, rd);
+ }
+ rc = ACR_EINTR;
+ break;
+ }
+ iostat = ReadFile(pipes[PIPE_STDOUT_RDS],
+ overlap[0].buff, sizeof(overlap[0].buff),
+ &rd, (LPOVERLAPPED)&overlap[0]);
+ if (iostat && rd != 0) {
+ overlap[0].stat = 0;
+ rd = AcrSbCatb(obuf, overlap[0].buff, rd);
+ /* Issue another read */
+ SetEvent(overlap[0].o.hEvent);
+ }
+ else {
+ overlap[0].stat = GetLastError();
+ if (overlap[0].stat != ERROR_IO_PENDING) {
+ SAFE_CLOSE_HANDLE(pipes[PIPE_STDOUT_RDS]);
+ ResetEvent(overlap[0].o.hEvent);
+ }
+ }
+ }
+ if (out != 0) {
+ rc = ACR_EINTR;
+ break;
+ }
+ case WAIT_OBJECT_1:
+ /* Signal on stderr stream
+ */
+ if (IS_VALID_HANDLE(pipes[PIPE_STDERR_RDS])) {
+ if (overlap[1].stat == ERROR_IO_PENDING) {
+ if (!GetOverlappedResult(pipes[PIPE_STDERR_RDS],
+ (LPOVERLAPPED)&overlap[1],
+ &rd,
+ FALSE)) {
+ overlap[1].stat = GetLastError();
+ }
+ else {
+ overlap[1].stat = 0;
+ rd = AcrSbCatb(ebuf, overlap[1].buff, rd);
+ }
+ rc = ACR_EINTR;
+ break;
+ }
+ iostat = ReadFile(pipes[PIPE_STDERR_RDS],
+ overlap[1].buff, sizeof(overlap[1].buff),
+ &rd, (LPOVERLAPPED)&overlap[1]);
+ if (iostat && rd != 0) {
+ overlap[1].stat = 0;
+ rd = AcrSbCatb(ebuf, overlap[1].buff, rd);
+ /* Issue another read */
+ SetEvent(overlap[1].o.hEvent);
+ }
+ else {
+ overlap[1].stat = GetLastError();
+ if (overlap[1].stat != ERROR_IO_PENDING) {
+ SAFE_CLOSE_HANDLE(pipes[PIPE_STDERR_RDS]);
+ ResetEvent(overlap[1].o.hEvent);
+ }
+ }
+ }
+ if (err != 0 && err != out) {
+ rc = ACR_EINTR;
+ break;
+ }
+ case WAIT_OBJECT_2:
+ /* Signal on stdin stream
+ */
+ if (IS_VALID_HANDLE(pipes[PIPE_STDINP_WRS]) &&
+ ibuf.len > ibuf.use) {
+ if (overlap[2].stat == ERROR_IO_PENDING) {
+ if (!GetOverlappedResult(pipes[PIPE_STDINP_WRS],
+ (LPOVERLAPPED)&overlap[2],
+ &wr,
+ FALSE)) {
+ overlap[2].stat = GetLastError();
+ }
+ else {
+ overlap[2].stat = 0;
+ ibuf.use += wr;
+ }
+ rc = ACR_EINTR;
+ break;
+ }
+ iostat = WriteFile(pipes[PIPE_STDINP_WRS],
+ ibuf.buf + ibuf.use,
+ ibuf.len - ibuf.use, &wr,
+ (LPOVERLAPPED)&overlap[2]);
+ if (iostat && wr != 0) {
+ ibuf.use += wr;
+ }
+ else {
+ overlap[2].stat = GetLastError();
+ if (overlap[2].stat != ERROR_IO_PENDING) {
+ FlushFileBuffers(pipes[PIPE_STDINP_WRS]);
+ SAFE_CLOSE_HANDLE(pipes[PIPE_STDINP_WRS]);
+ ResetEvent(overlap[1].o.hEvent);
+ }
+ }
+ }
+ rc = ACR_EINTR;
+ break;
+ case WAIT_TIMEOUT:
+ if (AcrTimeNow() >= endat)
+ rc = ACR_TIMEUP;
+ break;
+ default:
+ /* Unexpected result from Wait
+ */
+ rc = ACR_GET_OS_ERROR();
+ break;
+ }
+ } while (rc == ACR_EINTR);
+
+ do {
+ DWORD ws;
+ /* Wait until child ends
+ */
+ ws = WaitForSingleObject(pi.hProcess, polltime);
+ switch (ws) {
+ case WAIT_OBJECT_0:
+ /* Operation success */
+ GetExitCodeProcess(pi.hProcess, &exitval);
+ rc = 0;
+ rs = FALSE;
+ break;
+ case WAIT_TIMEOUT:
+ if (AcrTimeNow() >= endat)
+ rc = ACR_TIMEUP;
+ else
+ rc = ACR_EINTR;
+ break;
+ default:
+ /* We got the error while waiting
+ */
+ rc = ACR_GET_OS_ERROR();
+ break;
+ }
+ } while (rc == ACR_EINTR);
+
+ if (rs) {
+ /* Still running.
+ * Time to kill the bugger
+ */
+ TerminateProcess(pi.hProcess, SIGKILL);
+ exitwhy = ACR_CHILD_SIGNAL;
+ exitval = SIGKILL;
+ }
+ else {
+ exitwhy = ACR_CHILD_DONE;
+ }
+
+finished:
+ SAFE_CLOSE_HANDLE(pipes[PIPE_STDINP_WRS]);
+ SAFE_CLOSE_HANDLE(pipes[PIPE_STDOUT_RDS]);
+ SAFE_CLOSE_HANDLE(pipes[PIPE_STDERR_RDS]);
+ SAFE_CLOSE_HANDLE(pi.hThread);
+ SAFE_CLOSE_HANDLE(pi.hProcess);
+ for (i = 0; i < 3; i++) {
+ SAFE_CLOSE_HANDLE(overlap[i].o.hEvent);
+ }
+ if (obuf != 0) {
+ out->len = AcrSbLen(obuf);
+ out->buf = AcrSbDetach(obuf);
+ }
+ if (ebuf != 0) {
+ err->len = AcrSbLen(ebuf);
+ err->buf = AcrSbDetach(ebuf);
+ }
+ if (ibuf.buf != 0)
+ inp->use = ibuf.use;
+ *retval = exitval;
+ return exitwhy;
+
+cleanup:
+ SAFE_CLOSE_HANDLE(pi.hThread);
+ SAFE_CLOSE_HANDLE(pi.hProcess);
+ AcrSbFree(obuf);
+ AcrSbFree(ebuf);
+ if (pipes[PIPE_STDERR_RDS] == pipes[PIPE_STDOUT_RDS])
+ pipes[PIPE_STDERR_RDS] = 0;
+ for (i = 0; i < PIPE_COUNT; i++)
+ SAFE_CLOSE_HANDLE(pipes[i]);
+ for (i = 0; i < 3; i++) {
+ SAFE_CLOSE_HANDLE(overlap[i].o.hEvent);
+ }
+ *retval = rc;
return ACR_PARENT_ERROR;
}
@@ -80,14 +522,15 @@ ACR_JNI_EXPORT(jobject, ExecImpl, init0)
return 0;
R_LOAD_METHOD(0000, 0);
_clazzn.u = 1;
+ _procmgr_init();
return (*env)->NewObject(env, _clazzn.i, J4MID(0000));
}
-ACR_UNX_EXPORT(jlong, PosixExec, run0)(JNI_STDARGS, jstring executable,
- jstring args, jstring envb,
- jstring cwd, jbyteArray inp,
- jobject out, jobject err,
- jint timeout)
+ACR_WIN_EXPORT(jlong, WindowsExec, run0)(JNI_STDARGS, jstring executable,
+ jstring args, jcharArray envs,
+ jstring cwd, jbyteArray inp,
+ jobject out, jobject err,
+ jint timeout)
{
int rv = 0;
int rc = 0;
@@ -95,8 +538,10 @@ ACR_UNX_EXPORT(jlong, PosixExec, run0)(J
acr_buf_t *ib = 0;
acr_buf_t *ob = 0;
acr_buf_t *eb = 0;
-
+ wchar_t *envb = 0;
+
WITH_WSTR(executable) {
+ WITH_WSTR(args) {
WITH_WSTR(cwd) {
if (inp != 0) {
ib = &bb[0];
@@ -107,12 +552,16 @@ ACR_UNX_EXPORT(jlong, PosixExec, run0)(J
ob = &bb[1];
if (err != 0 && err != out)
eb = &bb[2];
+ if (envs != 0)
+ envb = (*env)->GetPrimitiveArrayCritical(env, envs, 0);
/* Call actual execute
*/
- rv = _run_exec(J2S(executable), 0, 0, J2S(cwd),
+ rv = _run_exec(J2S(executable), J2S(args), 0, J2S(cwd),
ob, eb, ib, timeout, &rc);
if (ib != 0 && inp != 0)
(*env)->ReleasePrimitiveArrayCritical(env, inp, ib->buf, 0);
+ if (envs != 0)
+ (*env)->ReleasePrimitiveArrayCritical(env, envs, envb, 0);
if (rv != ACR_PARENT_ERROR) {
if (out != 0) {
/* Write to the output stream */
@@ -136,8 +585,9 @@ cleanup:
if (ob != 0)
AcrFree(ob->buf);
if (eb != 0)
- AcrFree(ob->buf);
+ AcrFree(eb->buf);
} DONE_WITH_STR(cwd);
+ } DONE_WITH_STR(args);
} DONE_WITH_STR(executable);
return ((jlong)rv << 32) | ((jlong)rc & ACR_I64_C(0xFFFFFFFF));
Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/util.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/util.c?rev=1097447&r1=1097446&r2=1097447&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/util.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/util.c Thu Apr 28 13:22:14 2011
@@ -16,9 +16,12 @@
#include "acr/error.h"
#include "acr/memory.h"
+#include "acr/iodefs.h"
#include "acr/port.h"
#include "arch_opts.h"
+#define PIPE_FMT "\\\\.\\pipe\\00000000-0000-0000-0000-000000000000"
+static volatile LONG _pipe_id = 23;
/* This is the helper code to resolve late bound entry points
* missing from one or more releases of the Win32 API
*/
@@ -118,3 +121,201 @@ AcrLoadLateDLLs()
}
return 0;
}
+
+/* Similar to posix dup3 but it only actually works for
+ * stdio handles. If newfd is not stdio handle this
+ * behaves like DuplicateHandle favoring ACR_FOPEN_NOINHERIT
+ * flag.
+ */
+HANDLE dup4(HANDLE hproc, HANDLE oldfd, int flags)
+{
+ HANDLE duph = INVALID_HANDLE_VALUE;
+ DWORD inherit = TRUE;
+
+ if (IS_INVALID_HANDLE(oldfd)) {
+ ACR_SET_OS_ERROR(ACR_EINVAL);
+ return INVALID_HANDLE_VALUE;
+ }
+ if (flags & ACR_FOPEN_NOINHERIT)
+ inherit = FALSE;
+ if (!DuplicateHandle(hproc,
+ oldfd,
+ hproc,
+ &duph,
+ 0,
+ inherit,
+ DUPLICATE_SAME_ACCESS))
+ duph = INVALID_HANDLE_VALUE;
+ return duph;
+}
+
+/* Similar to posix dup3 but it only actually works for
+ * stdio handles. If newfd is not stdio handle this
+ * behaves like DuplicateHandle favoring ACR_FOPEN_NOINHERIT
+ * flag.
+ */
+HANDLE dup3(HANDLE oldfd, int newfd, int flags)
+{
+ int osfd;
+ DWORD saved_errno = 0;
+ HANDLE duph = INVALID_HANDLE_VALUE;
+ DWORD inherit = TRUE;
+ int oflags = 0;
+ FILE *stream = 0;
+
+ if (IS_INVALID_HANDLE(oldfd)) {
+ ACR_SET_OS_ERROR(ACR_EINVAL);
+ return INVALID_HANDLE_VALUE;
+ }
+ if (flags & ACR_FOPEN_NOINHERIT)
+ inherit = FALSE;
+ switch (newfd) {
+ case STDIN_FILENO:
+ oflags = _O_RDONLY;
+ break;
+ case STDOUT_FILENO:
+ stream = stdout;
+ oflags = _O_WRONLY;
+ break;
+ case STDERR_FILENO:
+ stream = stderr;
+ oflags = _O_WRONLY;
+ break;
+ default:
+ return dup4(GetCurrentProcess(), oldfd, flags);
+ break;
+ }
+ if (stream != 0) {
+ fflush(stream);
+ setvbuf(stream, NULL, _IONBF, 0);
+ }
+ osfd = _open_osfhandle((INT_PTR)oldfd, oflags | _O_BINARY);
+ if (osfd == -1) {
+ return INVALID_HANDLE_VALUE;
+ }
+ if (_dup2(osfd, newfd) == -1) {
+ return INVALID_HANDLE_VALUE;
+ }
+ _setmode(newfd, _O_BINARY);
+ duph = (HANDLE)_get_osfhandle(newfd);
+ if (IS_VALID_HANDLE(duph)) {
+ if (!inherit)
+ SetHandleInformation(duph, HANDLE_FLAG_INHERIT, 0);
+ /* _dup2 will not set sdh handles for GUI apps */
+ switch (newfd) {
+ case STDIN_FILENO:
+ SetStdHandle(STD_INPUT_HANDLE, duph);
+ break;
+ case STDOUT_FILENO:
+ SetStdHandle(STD_OUTPUT_HANDLE, duph);
+ break;
+ case STDERR_FILENO:
+ SetStdHandle(STD_ERROR_HANDLE, duph);
+ break;
+ }
+ }
+ return duph;
+}
+
+HANDLE
+AcrNullPipe(int flags, int fd)
+{
+ SECURITY_ATTRIBUTES sa;
+ HANDLE nd;
+ HANDLE dh;
+ DWORD saved_errno = 0;
+
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL;
+
+ nd = CreateFileW(L"NUL",
+ flags,
+ 0,
+ &sa,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (IS_INVALID_HANDLE(nd))
+ return NULL;
+ if (fd == -1)
+ return nd;
+ dh = dup3(nd, fd, flags);
+ if (IS_INVALID_HANDLE(dh))
+ saved_errno = GetLastError();
+ CloseHandle(nd);
+ if (saved_errno)
+ SetLastError(saved_errno);
+ return dh;
+}
+
+int
+AcrPipeNameFromIdA(DWORD dwPid, DWORD dwId, LPSTR lpszName, DWORD dwNameLength)
+{
+ if (lpszName == 0 || dwNameLength == 0)
+ return ISIZEOF(PIPE_FMT);
+ return _snprintf(lpszName, dwNameLength,
+ "\\\\.\\pipe\\%08x-0000-%04x-0000-000000000000",
+ dwPid, dwId & 0xffff);
+}
+
+int
+AcrPipePair(HANDLE *rd, HANDLE *wr, int flags, char *name)
+{
+ int rc = 0;
+ SECURITY_ATTRIBUTES sa;
+ DWORD dwOpenMode;
+ DWORD dwPipeMode;
+ char rname[RESOURCE_NAME_LEN];
+
+ if (name == 0)
+ name = rname;
+ AcrPipeNameFromIdA(GetCurrentProcessId(),
+ (DWORD)InterlockedIncrement(&_pipe_id),
+ name, RESOURCE_NAME_LEN);
+
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = FALSE;
+ sa.lpSecurityDescriptor = 0;
+
+ if (rd != 0) {
+ dwOpenMode = PIPE_ACCESS_INBOUND;
+ dwPipeMode = 0;
+ if (flags == ACR_PIPE_WRITE_BLOCK ||
+ flags == ACR_PIPE_FULL_NONBLOCK)
+ dwOpenMode |= FILE_FLAG_OVERLAPPED;
+
+ *rd = CreateNamedPipeA(name,
+ dwOpenMode,
+ dwPipeMode,
+ 1,
+ 0,
+ 65536,
+ 1,
+ &sa);
+ if (IS_INVALID_HANDLE(*rd))
+ return ACR_GET_OS_ERROR();
+ }
+ if (wr != 0) {
+ dwOpenMode = FILE_ATTRIBUTE_NORMAL;
+ if (flags == ACR_PIPE_READ_BLOCK ||
+ flags == ACR_PIPE_FULL_NONBLOCK)
+ dwOpenMode |= FILE_FLAG_OVERLAPPED;
+ *wr = CreateFileA(name,
+ GENERIC_WRITE,
+ 0,
+ &sa,
+ OPEN_EXISTING,
+ dwOpenMode,
+ 0);
+ if (IS_INVALID_HANDLE(*wr)) {
+ rc = ACR_GET_OS_ERROR();
+ if (rd != 0) {
+ SAFE_CLOSE_HANDLE(*rd);
+ }
+ return rc;
+ }
+ }
+ return 0;
+}
+
Modified: commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestExec.java
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestExec.java?rev=1097447&r1=1097446&r2=1097447&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestExec.java (original)
+++ commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestExec.java Thu Apr 28 13:22:14 2011
@@ -40,7 +40,8 @@ public class TestExec extends Assert
args.add("-al");
}
else {
-
+ args.add("C:\\Windows\\System32\\cmd.exe");
+ args.add("/V");
}
e.redirectOutputStream(true);
e.redirectErrorStream(true);