commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mt...@apache.org
Subject svn commit: r898878 - in /commons/sandbox/runtime/trunk/src/main/native/os/win32: subproc.c wutil.c
Date Wed, 13 Jan 2010 18:51:52 GMT
Author: mturk
Date: Wed Jan 13 18:51:52 2010
New Revision: 898878

URL: http://svn.apache.org/viewvc?rev=898878&view=rev
Log:
Implement child side of SubProc

Modified:
    commons/sandbox/runtime/trunk/src/main/native/os/win32/subproc.c
    commons/sandbox/runtime/trunk/src/main/native/os/win32/wutil.c

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/subproc.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/subproc.c?rev=898878&r1=898877&r2=898878&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/subproc.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/subproc.c Wed Jan 13 18:51:52 2010
@@ -22,8 +22,13 @@
 #include "acr_memory.h"
 #include "acr_port.h"
 #include "acr_string.h"
+#include "acr_file.h"
+#include "acr_pipe.h"
+#include "acr_time.h"
 #include "acr_tlsd.h"
 #include "acr_args.h"
+#include "acr_sbuf.h"
+#include "acr_exec.h"
 #include "acr_vm.h"
 
 #if !defined(ACR_DECLARE_EXPORT)
@@ -38,10 +43,6 @@
  * we launch rundll32.exe in a separate process and reopen the handles
  * instead duplicating them.
  *
- * Our SubprocMain is invoked by Rundll32. The first argument is
- * the hex encoded shared memory HANDLE which we duplicate and use in
- * our new intermediate stub process. Shared memory contains all the
- * IPC data we need.
  */
 
 /* Rundll32 Subproc exports.
@@ -57,6 +58,23 @@
  * Usage: Rundll32.exe <ShortPath\[lib]acr.dll>,SubprocMainW ...
  */
 
+typedef struct OVERLAPPED_BUFFER {
+    char    buff[512];
+    DWORD   stat;
+    OVERLAPPED o;
+} OVERLAPPED_BUFFER;
+
+#define PROC_TIMEOUT_STEP   100
+#define PROC_BUFFER_SIZE    512
+
+#define PIPE_STDINP_RDS     0
+#define PIPE_STDINP_WRS     1
+#define PIPE_STDOUT_RDS     2
+#define PIPE_STDOUT_WRS     3
+#define PIPE_STDERR_RDS     4
+#define PIPE_STDERR_WRS     5
+
+extern wchar_t *SHELL_PATH;
 
  /*
   * Instead in Makefile exports could go here as well
@@ -67,13 +85,38 @@
                                                   LPWSTR lpszCmdLine,
                                                   int nCmdShow)
 {
-    int       i;
-    int       rc = 0;
-    int       argc;
+
+    PROCESS_INFORMATION pi;
+    STARTUPINFOW        si;
+    SECURITY_ATTRIBUTES sa;
+    HANDLE cp = GetCurrentProcess();
+    DWORD  rd, wr;
+    DWORD  rc = 0;
+    BOOL   rs = FALSE;
+    BOOL   iostat;
+    DWORD  exitval;
+    int    i;
+    int    argc;
     wchar_t **args = NULL;
     wchar_t **argv = NULL;
-
-
+    wchar_t  *cmdline = NULL;
+    const char *inpp  = NULL;
+    int pi_have = 0;
+    int po_have = 0;
+    int pe_have = 0;
+    const wchar_t  *pi_name = NULL;
+    const wchar_t  *po_name = NULL;
+    const wchar_t  *pe_name = NULL;
+    HANDLE ppipe[3] = { NULL, NULL, NULL };
+    HANDLE pipes[6] = { NULL, NULL, NULL, NULL,  NULL, NULL };
+    HANDLE waith[6] = { NULL, NULL, NULL, NULL,  NULL, NULL };
+    DWORD  waitn    = 0;
+    OVERLAPPED_BUFFER ob[3];
+    char pstdinb[PROC_BUFFER_SIZE];
+    DWORD dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED;
+    DWORD dwPipeFlags;
+    acr_exec_t child;
+    acr_time_t endat = 0;
 
     if ((rc = ACR_Initialize(NULL))) {
         ACR_DEBUG((THROW_FMARK, "Failed to initialize the ACR error=%d\n", rc));
@@ -99,6 +142,9 @@
         rc = ACR_EINVAL;
         goto cleanup;
     }
+    memset(&child, 0, sizeof(acr_exec_t));
+    child.pid = -1;
+
     for (i = 2; i < argc; i++) {
         if ((argv[i][0] == L'/' && argv[i][1] == L'/') ||
             (argv[i][0] == L'-' && argv[i][1] == L'-')) {
@@ -117,8 +163,36 @@
              */
             if ((opt = wcspbrk(cmd, L":=")))
                 *(opt++) = '\0';
-            printf("internal[%d] : %S=%S\n", i, cmd, opt);
-
+            rc = ACR_EINVAL;
+            switch (*cmd) {
+                case L'T':
+                    if (!opt)
+                        goto cleanup;
+                    child.limit.timeout = _wtoi64(opt);
+                break;
+                case L'I':
+                    /* Where the child stdin should be redirected */
+                    pi_name = opt;
+                    child.flags |= ACR_PROC_HAS_STDIN;
+                break;
+                case L'O':
+                    /* Where the child stdout should be redirected */
+                    po_name = opt;
+                    child.flags |= ACR_PROC_HAS_STDOUT;
+                break;
+                case L'E':
+                    /* Where the child stderr should be redirected */
+                    pe_name = opt;
+                    child.flags |= ACR_PROC_HAS_STDERR;
+                break;
+                case L'D':
+                    /* Detached process */
+                    child.flags |= ACR_PROC_DETACHED;
+                break;
+                default:
+                    /* Unknown argument */
+                break;
+            }
         }
         else
             break;
@@ -129,14 +203,378 @@
         /* We at least need the process name
          */
         rc = ACR_EINVAL;
-        goto cleanup;    
+        goto cleanup;
+    }
+    cmdline = ACR_ArgsToStringW(argv);
+    if (!cmdline) {
+        rc = ACR_ENOMEM;
+        goto cleanup;
     }
 
+    ACR_DEBUG((THROW_FMARK, "CMDLINE='%S'\n", cmdline));
     for (i = 0; i < argc; i++) {
-        printf("ARG[%d] : %S.\n", i, argv[i]);
+        ACR_DEBUG((THROW_FMARK, "ARGV[%d]='%S'\n", i, argv[i]));
+    }
+    memset(&pi, 0, sizeof(pi));
+    memset(&si, 0, sizeof(si));
+    si.cb = sizeof(si);
+
+    for (i = 0; i < 3; i++)
+        memset(&ob[i], 0, sizeof(OVERLAPPED_BUFFER));
+
+    /* Sanity check.
+     * Daemons have no stream pipes
+     */
+    if (child.flags & ACR_PROC_DETACHED) {
+        child.flags &= ~(ACR_PROC_HAS_STDIN  |
+                         ACR_PROC_HAS_STDOUT |
+                         ACR_PROC_HAS_STDERR);
+        dwCreationFlags |= DETACHED_PROCESS;
+        si.dwFlags       = STARTF_USESHOWWINDOW;
+        si.wShowWindow   = SW_HIDE;
+    }
+    sa.nLength              = sizeof(SECURITY_ATTRIBUTES);
+    sa.bInheritHandle       = FALSE;
+    sa.lpSecurityDescriptor = NULL;
+    /* Create standard stream pipes
+     */
+    if (child.flags & ACR_PROC_HAS_STDIN) {
+        if ((rc = pipepair(&pipes[PIPE_STDINP_RDS], &pipes[PIPE_STDINP_WRS],
+                           NULL, ACR_PIPE_READ_BLOCK)))
+            goto cleanup;
+        /* Open the handle to the parent stdin
+         */
+        ppipe[0] = CreateFileW(pi_name,
+                               GENERIC_READ,
+                               0,
+                               &sa,
+                               OPEN_EXISTING,
+                               FILE_ATTRIBUTE_NORMAL,
+                               NULL);
+        if (IS_INVALID_HANDLE(ppipe[0])) {
+            rc = ACR_GET_OS_ERROR();
+            goto cleanup;
+        }
+    }
+    else {
+        /* Use NUL (aka /dev/null) */
+        pipes[PIPE_STDINP_RDS] = nullpipe(GENERIC_READ, NULL);
+    }
+    if (child.flags & ACR_PROC_HAS_STDOUT) {
+        if ((rc = pipepair(&pipes[PIPE_STDOUT_RDS], &pipes[PIPE_STDOUT_WRS],
+                           NULL, ACR_PIPE_WRITE_BLOCK)))
+            goto cleanup;
+        /* Open the handle to the parent stdout
+         */
+        ppipe[1] = CreateFileW(po_name,
+                               GENERIC_WRITE,
+                               0,
+                               &sa,
+                               OPEN_EXISTING,
+                               FILE_ATTRIBUTE_NORMAL,
+                               NULL);
+        if (IS_INVALID_HANDLE(ppipe[1])) {
+            rc = ACR_GET_OS_ERROR();
+            goto cleanup;
+        }
+    }
+    else {
+        /* Use NUL (aka /dev/null) */
+        pipes[PIPE_STDOUT_WRS] = nullpipe(GENERIC_WRITE, NULL);
+    }
+    if (child.flags & ACR_PROC_HAS_STDERR) {
+        if ((rc = pipepair(&pipes[PIPE_STDERR_RDS], &pipes[PIPE_STDERR_WRS],
+                           NULL, ACR_PIPE_WRITE_BLOCK)))
+            goto cleanup;
+        /* Open the handle to the parent stderr
+         */
+        ppipe[2] = CreateFileW(pe_name,
+                               GENERIC_WRITE,
+                               0,
+                               &sa,
+                               OPEN_EXISTING,
+                               FILE_ATTRIBUTE_NORMAL,
+                               NULL);
+        if (IS_INVALID_HANDLE(ppipe[2])) {
+            rc = ACR_GET_OS_ERROR();
+            goto cleanup;
+        }
+    }
+    else {
+        /* Use same pipes for stderr and stdout
+         */
+        pipes[PIPE_STDERR_WRS] = pipes[PIPE_STDOUT_WRS];
+        pipes[PIPE_STDERR_RDS] = pipes[PIPE_STDOUT_RDS];
     }
 
+    /* Always use STDHANDLES
+     * They are either real handles or handles to NUL device
+     */
+    si.dwFlags |= STARTF_USESTDHANDLES;
+    dwPipeFlags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
+    if (!DuplicateHandle(cp, pipes[PIPE_STDINP_RDS], cp, &pipes[PIPE_STDINP_RDS],
+                         0, TRUE, dwPipeFlags)) {
+        rc = ACR_GET_OS_ERROR();
+        goto cleanup;
+    }
+    dwPipeFlags = DUPLICATE_SAME_ACCESS;
+    if (child.flags & ACR_PROC_HAS_STDERR)
+        dwPipeFlags |= DUPLICATE_CLOSE_SOURCE;
+    if (!DuplicateHandle(cp, pipes[PIPE_STDOUT_WRS], cp, &pipes[PIPE_STDOUT_WRS],
+                         0, TRUE, dwPipeFlags)) {
+        rc = ACR_GET_OS_ERROR();
+        goto cleanup;
+    }
+    dwPipeFlags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
+    if (!DuplicateHandle(cp, pipes[PIPE_STDERR_WRS], cp, &pipes[PIPE_STDERR_WRS],
+                         0, TRUE, dwPipeFlags)) {
+        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 (child.limit.timeout > 0)
+        endat = ACR_TimeNow() + child.limit.timeout;
+
+    rs = CreateProcessW(
+            argv[0],            /* Executable */
+            cmdline,            /* Command line */
+            NULL,
+            NULL,               /* Proc & thread security attributes */
+            TRUE,               /* Inherit handles */
+            dwCreationFlags,    /* Creation flags */
+            NULL,               /* Environment block */
+            child.currdir,      /* Current directory name */
+            &si,
+            &pi);
+    if (!rs) {
+        rc = ACR_GET_OS_ERROR();
+        goto cleanup;
+    }
+    child.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 (child.flags & ACR_PROC_DETACHED) {
+        /* We are done in case of detached process
+         */
+        rc = 0;
+        ResumeThread(pi.hThread);
+        goto finally;
+    }
+    /* Setup wait handles
+     */
+    waith[waitn++] = pi.hProcess;
+    if (IS_VALID_HANDLE(pipes[PIPE_STDOUT_RDS])) {
+        ob[0].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        waith[waitn++] = ob[0].o.hEvent;
+    }
+    if (IS_VALID_HANDLE(pipes[PIPE_STDERR_RDS]) &&
+        (child.flags & ACR_PROC_HAS_STDERR)) {
+        ob[1].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        waith[waitn++] = ob[1].o.hEvent;
+    }
+    if (IS_VALID_HANDLE(pipes[PIPE_STDINP_WRS])) {
+        ob[2].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        waith[waitn++] = ob[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 dwTimeout = child.limit.timeout > 0 ? PROC_TIMEOUT_STEP : INFINITE;
+        DWORD ws;
+        /* Do some blocking read from the parent
+         */
+        if (IS_VALID_HANDLE(ppipe[0]) && child.data.iov_len == 0) {
+            iostat = ReadFile(ppipe[PIPE_STDOUT_RDS],
+                              pstdinb, sizeof(pstdinb),
+                              &rd, NULL);
+            if (iostat && rd != 0) {
+                child.data.iov_len = rd;
+                inpp = pstdinb;
+            }
+            else {
+                child.data.iov_len = 0;
+                inpp = NULL;
+                SAFE_CLOSE_HANDLE(ppipe[0]);
+            }
+        }
+        /* 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 = ACR_WaitForMultipleObjectOrSignal(waitn, waith, dwTimeout);
+        switch (ws) {
+            case WAIT_ACRSIGNAL_0:
+                /* Signal event is set.
+                 * Get it's status.
+                 */
+                rc = ACR_DeliverSignals();
+            break;
+            case WAIT_OBJECT_1:
+                /* Signal on hProcess is set.
+                 * This means the process exited
+                 */
+                GetExitCodeProcess(pi.hProcess, &exitval);
+                rc = 0;
+                rs = FALSE;
+            break;
+            case WAIT_OBJECT_2:
+                /* Signal on stdout stream
+                 */
+                if (IS_VALID_HANDLE(pipes[PIPE_STDOUT_RDS])) {
+                    if (ob[0].stat == ERROR_IO_PENDING) {
+                        if (!GetOverlappedResult(pipes[PIPE_STDOUT_RDS],
+                                                 &ob[0].o,
+                                                 &rd,
+                                                 FALSE)) {
+                            ob[0].stat = GetLastError();
+                        }
+                        else {
+                            ob[0].stat = 0;
+                            WriteFile(ppipe[1], ob[0].buff, rd, &wr, NULL);
+                        }
+                        rc = ACR_EINTR;
+                        break;
+                    }
+                    iostat = ReadFile(pipes[PIPE_STDOUT_RDS],
+                                      ob[0].buff, sizeof(ob[0].buff),
+                                      &rd, &ob[0].o);
+                    if (iostat && rd != 0) {
+                        ob[0].stat = 0;
+                        WriteFile(ppipe[1], ob[0].buff, rd, &wr, NULL);
+                    }
+                    else {
+                        ob[0].stat = GetLastError();
+                        if (ob[0].stat != ERROR_IO_PENDING) {
+                            SAFE_CLOSE_HANDLE(pipes[PIPE_STDOUT_RDS]);
+                        }
+                    }
+                }
+                rc = ACR_EINTR;
+            break;
+            case WAIT_OBJECT_3:
+                /* Signal on stderr stream
+                 */
+                if (IS_VALID_HANDLE(pipes[PIPE_STDERR_RDS])) {
+                    if (ob[1].stat == ERROR_IO_PENDING) {
+                        if (!GetOverlappedResult(pipes[PIPE_STDERR_RDS],
+                                                 &ob[1].o,
+                                                 &rd,
+                                                 FALSE)) {
+                            ob[1].stat = GetLastError();
+                        }
+                        else {
+                            ob[1].stat = 0;
+                            WriteFile(ppipe[2], ob[1].buff, rd, &wr, NULL);
+                        }
+                        rc = ACR_EINTR;
+                        break;
+                    }
+                    iostat = ReadFile(pipes[PIPE_STDERR_RDS],
+                                      ob[1].buff, sizeof(ob[1].buff),
+                                      &rd, &ob[1].o);
+                    if (iostat && rd != 0) {
+                        ob[1].stat = 0;
+                        WriteFile(ppipe[2], ob[1].buff, rd, &wr, NULL);
+                    }
+                    else {
+                        ob[1].stat = GetLastError();
+                        if (ob[1].stat != ERROR_IO_PENDING) {
+                            SAFE_CLOSE_HANDLE(pipes[PIPE_STDERR_RDS]);
+                        }
+                    }
+                    rc = ACR_EINTR;
+                    break;
+                }
+            case WAIT_OBJECT_4:
+                /* Signal on stdin stream
+                 */
+                if (IS_VALID_HANDLE(pipes[PIPE_STDINP_WRS]) &&
+                    child.data.iov_len > 0) {
+                    if (ob[2].stat == ERROR_IO_PENDING) {
+                        if (!GetOverlappedResult(pipes[PIPE_STDINP_WRS],
+                                                 &ob[2].o,
+                                                 &wr,
+                                                 FALSE)) {
+                            ob[2].stat = GetLastError();
+                        }
+                        else {
+                            ob[2].stat = 0;
+                            child.data.iov_len -= wr;
+                            inpp               += wr;
+                        }
+                        rc = ACR_EINTR;
+                        break;
+                    }
+                    iostat = WriteFile(pipes[PIPE_STDINP_WRS], inpp,
+                                       child.data.iov_len, &wr, &ob[2].o);
+                    if (iostat && wr != 0) {
+                        child.data.iov_len -= wr;
+                        inpp               += wr;
+                    }
+                    else {
+                        ob[2].stat = GetLastError();
+                        if (ob[2].stat != ERROR_IO_PENDING) {
+                            SAFE_CLOSE_HANDLE(pipes[PIPE_STDINP_WRS]);
+                        }
+                    }
+                }
+                rc = ACR_EINTR;
+            break;
+            case WAIT_TIMEOUT:
+                if (ACR_TimeNow() >= endat)
+                    rc = ACR_TIMEUP;
+            break;
+            default:
+                /* Unexpected result from Wait
+                 */
+                rc = ACR_EINVAL;
+            break;
+        }
+    } while (rc == ACR_EINTR);
+
+
+    if (rs) {
+        /* Still running.
+         * Time to kill the bugger
+         */
+        TerminateProcess(pi.hProcess, 9);
+        rc = 9;
+    }
+    else {
+        rc = exitval;
+    }
+
+finally:
+    SAFE_CLOSE_HANDLE(pi.hThread);
+    SAFE_CLOSE_HANDLE(pi.hProcess);
+
 cleanup:
+    if (pipes[PIPE_STDERR_RDS] == pipes[PIPE_STDOUT_RDS])
+        pipes[PIPE_STDERR_RDS] = NULL;
+    for (i = 0; i < 6; i++)
+        SAFE_CLOSE_HANDLE(pipes[i]);
+    for (i = 0; i < 3; i++)
+        SAFE_CLOSE_HANDLE(ppipe[i]);
+    for (i = 0; i < 3; i++) {
+        SAFE_CLOSE_HANDLE(ob[i].o.hEvent);
+    }
+    x_free(cmdline);
     ACR_ARRAY_FREE(args);
     ExitProcess(rc);
 }

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/wutil.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/wutil.c?rev=898878&r1=898877&r2=898878&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/wutil.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/wutil.c Wed Jan 13 18:51:52 2010
@@ -41,7 +41,8 @@
     va_end(ap);
     if (file) {
         const char *fn = ACR_FilePathNameGet(file);
-        snprintf(fmt, ACR_HBUFF_LEN, "[%-10s %4d] %s", fn, line, buf);
+        snprintf(fmt, ACR_HBUFF_LEN, "[%6d] (%-10s @%4d) %s",
+                      GetCurrentProcessId(), fn, line, buf);
         bp = fmt;
     }
 



Mime
View raw message