1 /*
   2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <assert.h>
  27 #include "java_lang_ProcessImpl.h"
  28 
  29 #include "jni.h"
  30 #include "jvm.h"
  31 #include "jni_util.h"
  32 #include "io_util.h"
  33 #include <windows.h>
  34 #include <io.h>
  35 
  36 /* We try to make sure that we can read and write 4095 bytes (the
  37  * fixed limit on Linux) to the pipe on all operating systems without
  38  * deadlock.  Windows 2000 inexplicably appears to need an extra 24
  39  * bytes of slop to avoid deadlock.
  40  */
  41 #define PIPE_SIZE (4096+24)
  42 
  43 static void
  44 win32Error(JNIEnv *env, const char *functionName)
  45 {
  46     static const char * const format = "%s error=%d, %s";
  47     static const char * const fallbackFormat = "%s failed, error=%d";
  48     char buf[256];
  49     char errmsg[sizeof(buf) + 100];
  50     const int errnum = GetLastError();
  51     const int n = JVM_GetLastErrorString(buf, sizeof(buf));
  52     if (n > 0)
  53         sprintf(errmsg, format, functionName, errnum, buf);
  54     else
  55         sprintf(errmsg, fallbackFormat, functionName, errnum);
  56     JNU_ThrowIOException(env, errmsg);
  57 }
  58 
  59 static void
  60 closeSafely(HANDLE handle)
  61 {
  62     if (handle != INVALID_HANDLE_VALUE)
  63         CloseHandle(handle);
  64 }
  65 
  66 static BOOL hasInheritFlag(HANDLE handle)
  67 {
  68     DWORD mask;
  69     if (GetHandleInformation(handle, &mask)) {
  70         return mask & HANDLE_FLAG_INHERIT;
  71     }
  72     return FALSE;
  73 }
  74 
  75 #define HANDLE_STORAGE_SIZE 6
  76 #define OFFSET_READ  0
  77 #define OFFSET_WRITE 1
  78 #define OPPOSITE_END(offset) (offset==OFFSET_READ ? OFFSET_WRITE : OFFSET_READ)
  79 
  80 typedef struct _STDHOLDER {
  81     HANDLE  pipe[2];
  82     int     offset;
  83 } STDHOLDER;
  84 
  85 static BOOL initHolder(
  86     JNIEnv *env,
  87     STDHOLDER *pHolder,
  88     jlong *pjhandles,
  89     HANDLE *phStd)
  90 {
  91     if (*pjhandles != (jlong) -1) {
  92         *phStd = (HANDLE) *pjhandles;
  93         *pjhandles = (jlong) -1;
  94     } else {
  95         if (!CreatePipe(
  96             &pHolder->pipe[OFFSET_READ],
  97             &pHolder->pipe[OFFSET_WRITE],
  98             NULL, /* we would like to inherit
  99                      default process access,
 100                      instead of 'Everybody' access */
 101             PIPE_SIZE))
 102         {
 103             win32Error(env, "CreatePipe");
 104             return FALSE;
 105         } else {
 106             /* [thisProcessEnd] has no the inherit flag.
 107                the [lpPipeAttributes] param had the NULL value. */
 108             HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)];
 109             *phStd = pHolder->pipe[pHolder->offset];
 110             *pjhandles = (jlong) thisProcessEnd;
 111         }
 112     }
 113     /* Pipe handle will be closed in the [releaseHolder] call,
 114        file handle will be closed in Java.
 115        The long-live handle need to restore the inherit flag,
 116        we do it later in the [prepareIOEHandleState] call. */
 117     SetHandleInformation(
 118         *phStd,
 119         HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
 120     return TRUE;
 121 }
 122 
 123 static void releaseHolder(BOOL complete, STDHOLDER *pHolder) {
 124     closeSafely(pHolder->pipe[pHolder->offset]);
 125     if (complete) {
 126         /* Error occur, close this process pipe end */
 127         closeSafely(pHolder->pipe[OPPOSITE_END(pHolder->offset)]);
 128     }
 129 }
 130 
 131 static void prepareIOEHandleState(
 132     HANDLE *stdIOE,
 133     BOOL *inherit)
 134 {
 135     int i;
 136     for (i = 0; i < HANDLE_STORAGE_SIZE; ++i) {
 137         HANDLE hstd = stdIOE[i];
 138         if (INVALID_HANDLE_VALUE != hstd && hasInheritFlag(hstd)) {
 139             /* FALSE by default */
 140             inherit[i] = TRUE;
 141             /* Java does not need implicit inheritance for IOE handles,
 142                so we drop inherit flag that probably was installed by
 143                previous CreateProcess call that launched current process.
 144                We will return the handle state back after CreateProcess call.
 145                By clearing inherit flag we prevent "greedy grandchild" birth.
 146                The explicit inheritance for child process IOE handles is
 147                supported in the [initHolder] call. */
 148             SetHandleInformation(hstd, HANDLE_FLAG_INHERIT, 0);
 149         }
 150     }
 151 }
 152 
 153 static void restoreIOEHandleState(
 154     const HANDLE *stdIOE,
 155     const BOOL *inherit)
 156 {
 157     /* The set of current process standard IOE handles and
 158        the set of child process IOE handles can intersect.
 159        To restore the inherit flag right, we use backward
 160        array iteration. */
 161     int i;
 162     for (i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i)
 163         if (INVALID_HANDLE_VALUE != stdIOE[i]) {
 164            /* Restore inherit flag for any case.
 165               The handle can be changed by explicit inheritance.*/
 166             SetHandleInformation(stdIOE[i],
 167                 HANDLE_FLAG_INHERIT,
 168                 inherit[i] ? HANDLE_FLAG_INHERIT : 0);
 169         }
 170 }
 171 
 172 /* Please, read about the MS inheritance problem
 173    http://support.microsoft.com/kb/315939
 174    and critical section/synchronized block solution. */
 175 static jlong processCreate(
 176     JNIEnv *env,
 177     const jchar *pcmd,
 178     const jchar *penvBlock,
 179     const jchar *pdir,
 180     jlong *handles,
 181     jboolean redirectErrorStream)
 182 {
 183     jlong ret = 0L;
 184     STARTUPINFOW si = {sizeof(si)};
 185 
 186     /* Handles for which the inheritance flag must be restored. */
 187     HANDLE stdIOE[HANDLE_STORAGE_SIZE] = {
 188         /* Current process standard IOE handles: JDK-7147084 */
 189         INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
 190         /* Child process IOE handles: JDK-6921885 */
 191         (HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]};
 192     BOOL inherit[HANDLE_STORAGE_SIZE] = {
 193         FALSE, FALSE, FALSE,
 194         FALSE, FALSE, FALSE};
 195 
 196     {
 197         /* Extraction of current process standard IOE handles */
 198         DWORD idsIOE[3] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE};
 199         int i;
 200         for (i = 0; i < 3; ++i)
 201             /* Should not be closed by CloseHandle! */
 202             stdIOE[i] = GetStdHandle(idsIOE[i]);
 203     }
 204 
 205     prepareIOEHandleState(stdIOE, inherit);
 206     {
 207         /* Input */
 208         STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ};
 209         if (initHolder(env, &holderIn, &handles[0], &si.hStdInput)) {
 210 
 211             /* Output */
 212             STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
 213             if (initHolder(env, &holderOut, &handles[1], &si.hStdOutput)) {
 214 
 215                 /* Error */
 216                 STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
 217                 BOOL success;
 218                 if (redirectErrorStream) {
 219                     si.hStdError = si.hStdOutput;
 220                     handles[2] = (jlong) -1;
 221                     success = TRUE;
 222                 } else {
 223                     success = initHolder(env, &holderErr, &handles[2], &si.hStdError);
 224                 }
 225 
 226                 if (success) {
 227                     PROCESS_INFORMATION pi;
 228                     DWORD processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
 229 
 230                     si.dwFlags = STARTF_USESTDHANDLES;
 231                     if (!CreateProcessW(
 232                         NULL,             /* executable name */
 233                         (LPWSTR)pcmd,     /* command line */
 234                         NULL,             /* process security attribute */
 235                         NULL,             /* thread security attribute */
 236                         TRUE,             /* inherits system handles */
 237                         processFlag,      /* selected based on exe type */
 238                         (LPVOID)penvBlock,/* environment block */
 239                         (LPCWSTR)pdir,    /* change to the new current directory */
 240                         &si,              /* (in)  startup information */
 241                         &pi))             /* (out) process information */
 242                     {
 243                         win32Error(env, "CreateProcess");
 244                     } else {
 245                         closeSafely(pi.hThread);
 246                         ret = (jlong)pi.hProcess;
 247                     }
 248                 }
 249                 releaseHolder(ret == 0, &holderErr);
 250                 releaseHolder(ret == 0, &holderOut);
 251             }
 252             releaseHolder(ret == 0, &holderIn);
 253         }
 254     }
 255     restoreIOEHandleState(stdIOE, inherit);
 256 
 257     return ret;
 258 }
 259 
 260 JNIEXPORT jlong JNICALL
 261 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
 262                                   jstring cmd,
 263                                   jstring envBlock,
 264                                   jstring dir,
 265                                   jlongArray stdHandles,
 266                                   jboolean redirectErrorStream)
 267 {
 268     jlong ret = 0;
 269     if (cmd != NULL
 270      && stdHandles != NULL)
 271     {
 272         const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL);
 273         if (pcmd != NULL) {
 274             const jchar *penvBlock = (envBlock != NULL)
 275                 ? (*env)->GetStringChars(env, envBlock, NULL)
 276                 : NULL;
 277             const jchar *pdir = (dir != NULL)
 278                 ? (*env)->GetStringChars(env, dir, NULL)
 279                 : NULL;
 280             jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
 281             if (handles != NULL) {
 282                 ret = processCreate(
 283                     env,
 284                     pcmd,
 285                     penvBlock,
 286                     pdir,
 287                     handles,
 288                     redirectErrorStream);
 289                 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
 290             }
 291             if (pdir != NULL)
 292                 (*env)->ReleaseStringChars(env, dir, pdir);
 293             if (penvBlock != NULL)
 294                 (*env)->ReleaseStringChars(env, envBlock, penvBlock);
 295             (*env)->ReleaseStringChars(env, cmd, pcmd);
 296         }
 297     }
 298     return ret;
 299 }
 300 
 301 JNIEXPORT jint JNICALL
 302 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
 303 {
 304     DWORD exit_code;
 305     if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
 306         win32Error(env, "GetExitCodeProcess");
 307     return exit_code;
 308 }
 309 
 310 JNIEXPORT jint JNICALL
 311 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
 312 {
 313     return STILL_ACTIVE;
 314 }
 315 
 316 JNIEXPORT void JNICALL
 317 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
 318 {
 319     HANDLE events[2];
 320     events[0] = (HANDLE) handle;
 321     events[1] = JVM_GetThreadInterruptEvent();
 322 
 323     if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
 324                                FALSE,    /* Wait for ANY event */
 325                                INFINITE)  /* Wait forever */
 326         == WAIT_FAILED)
 327         win32Error(env, "WaitForMultipleObjects");
 328 }
 329 
 330 JNIEXPORT void JNICALL
 331 Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env,
 332                                                        jclass ignored,
 333                                                        jlong handle,
 334                                                        jlong timeout)
 335 {
 336     HANDLE events[2];
 337     DWORD dwTimeout = (DWORD)timeout;
 338     DWORD result;
 339     events[0] = (HANDLE) handle;
 340     events[1] = JVM_GetThreadInterruptEvent();
 341     result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
 342                                     FALSE,    /* Wait for ANY event */
 343                                     dwTimeout);  /* Wait for dwTimeout */
 344 
 345     if (result == WAIT_FAILED)
 346         win32Error(env, "WaitForMultipleObjects");
 347 }
 348 
 349 JNIEXPORT void JNICALL
 350 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
 351 {
 352     TerminateProcess((HANDLE) handle, 1);
 353 }
 354 
 355 JNIEXPORT jboolean JNICALL
 356 Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)
 357 {
 358     DWORD dwExitStatus;
 359     GetExitCodeProcess((HANDLE) handle, &dwExitStatus);
 360     return dwExitStatus == STILL_ACTIVE;
 361 }
 362 
 363 JNIEXPORT jboolean JNICALL
 364 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
 365 {
 366     return CloseHandle((HANDLE) handle);
 367 }
 368 
 369 /**
 370  * Returns a copy of the Unicode characters of a string. Fow now this
 371  * function doesn't handle long path names and other issues.
 372  */
 373 static WCHAR* getPath(JNIEnv *env, jstring ps) {
 374     WCHAR *pathbuf = NULL;
 375     const jchar *chars = (*(env))->GetStringChars(env, ps, NULL);
 376     if (chars != NULL) {
 377         size_t pathlen = wcslen(chars);
 378         pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
 379         if (pathbuf == NULL) {
 380             JNU_ThrowOutOfMemoryError(env, NULL);
 381         } else {
 382             wcscpy(pathbuf, chars);
 383         }
 384         (*env)->ReleaseStringChars(env, ps, chars);
 385     }
 386     return pathbuf;
 387 }
 388 
 389 JNIEXPORT jlong JNICALL
 390 Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path)
 391 {
 392     const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA);
 393     const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
 394     const DWORD disposition = OPEN_ALWAYS;
 395     const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
 396     HANDLE h;
 397     WCHAR *pathbuf = getPath(env, path);
 398     if (pathbuf == NULL) {
 399         /* Exception already pending */
 400         return -1;
 401     }
 402     h = CreateFileW(
 403         pathbuf,            /* Wide char path name */
 404         access,             /* Read and/or write permission */
 405         sharing,            /* File sharing flags */
 406         NULL,               /* Security attributes */
 407         disposition,        /* creation disposition */
 408         flagsAndAttributes, /* flags and attributes */
 409         NULL);
 410     free(pathbuf);
 411     if (h == INVALID_HANDLE_VALUE) {
 412         JNU_ThrowIOExceptionWithLastError(env, "CreateFileW");
 413     }
 414     return ptr_to_jlong(h);
 415 }