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 /* We have THREE locales in action: 
  44  * 1. Thread default locale - dictates UNICODE-to-8bit conversion
  45  * 2. System locale that defines the message localization
  46  * 3. The file name locale
  47  * Each locale could be an extended locale, that means that text cannot be
  48  * mapped to 8bit sequence without multibyte encoding.
  49  * VM is ready for that, if text is UTF-8.
  50  * Here we make the work right from the beginning.
  51  */
  52 size_t os_error_message(int errnum, WCHAR* utf16_OSErrorMsg, size_t maxMsgLength) {
  53     size_t n = (size_t)FormatMessageW(
  54             FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
  55             NULL,
  56             (DWORD)errnum,
  57             0,
  58             utf16_OSErrorMsg,
  59             (DWORD)maxMsgLength,
  60             NULL);
  61     if (n > 3) {
  62         // Drop final '.', CR, LF
  63         if (utf16_OSErrorMsg[n - 1] == L'\n') --n;
  64         if (utf16_OSErrorMsg[n - 1] == L'\r') --n;
  65         if (utf16_OSErrorMsg[n - 1] == L'.') --n;
  66         utf16_OSErrorMsg[n] = L'\0';
  67     }
  68     return n;
  69 }
  70 
  71 #define MESSAGE_LENGTH (256 + 100)
  72 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
  73 
  74 static void
  75 win32Error(JNIEnv *env, const WCHAR *functionName)
  76 {
  77     WCHAR utf16_OSErrorMsg[MESSAGE_LENGTH - 100];
  78     WCHAR utf16_javaMessage[MESSAGE_LENGTH];
  79     /*Good suggestion about 2-bytes-per-symbol in localized error reports*/
  80     char  utf8_javaMessage[MESSAGE_LENGTH*2];
  81     const int errnum = (int)GetLastError();
  82     int n = os_error_message(errnum, utf16_OSErrorMsg, ARRAY_SIZE(utf16_OSErrorMsg));
  83     n = (n > 0)
  84         ? swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s error=%d, %s", functionName, errnum, utf16_OSErrorMsg)
  85         : swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s failed, error=%d", functionName, errnum);
  86 
  87     if (n > 0) /*terminate '\0' is not a part of conversion procedure*/
  88         n = WideCharToMultiByte(
  89             CP_UTF8,
  90             0,
  91             utf16_javaMessage,
  92             n, /*by creation n <= MESSAGE_LENGTH*/
  93             utf8_javaMessage,
  94             MESSAGE_LENGTH*2,
  95             NULL,
  96             NULL);
  97 
  98     /*no way to die*/
  99     {
 100         const char *errorMessage = "Secondary error while OS message extraction";
 101         if (n > 0) {
 102             utf8_javaMessage[min(MESSAGE_LENGTH*2 - 1, n)] = '\0';
 103             errorMessage = utf8_javaMessage;
 104         }
 105         JNU_ThrowIOException(env, errorMessage);
 106     }
 107 }
 108 
 109 static void
 110 closeSafely(HANDLE handle)
 111 {
 112     if (handle != INVALID_HANDLE_VALUE)
 113         CloseHandle(handle);
 114 }
 115 
 116 JNIEXPORT jlong JNICALL
 117 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
 118                                   jstring cmd,
 119                                   jstring envBlock,
 120                                   jstring dir,
 121                                   jlongArray stdHandles,
 122                                   jboolean redirectErrorStream)
 123 {
 124     HANDLE inRead   = INVALID_HANDLE_VALUE;
 125     HANDLE inWrite  = INVALID_HANDLE_VALUE;
 126     HANDLE outRead  = INVALID_HANDLE_VALUE;
 127     HANDLE outWrite = INVALID_HANDLE_VALUE;
 128     HANDLE errRead  = INVALID_HANDLE_VALUE;
 129     HANDLE errWrite = INVALID_HANDLE_VALUE;
 130     SECURITY_ATTRIBUTES sa;
 131     PROCESS_INFORMATION pi;
 132     STARTUPINFOW si;
 133     const jchar*  pcmd = NULL;
 134     const jchar*  pdir = NULL;
 135     const jchar*  penvBlock = NULL;
 136     jlong  *handles = NULL;
 137     jlong ret = 0;
 138     DWORD processFlag;
 139 
 140     assert(cmd != NULL);
 141     pcmd = (*env)->GetStringChars(env, cmd, NULL);
 142     if (pcmd == NULL) goto Catch;
 143 
 144     if (dir != 0) {
 145         pdir = (*env)->GetStringChars(env, dir, NULL);
 146         if (pdir == NULL) goto Catch;
 147     }
 148     if (envBlock != NULL) {
 149         penvBlock = ((*env)->GetStringChars(env, envBlock, NULL));
 150         if (penvBlock == NULL) goto Catch;
 151     }
 152     assert(stdHandles != NULL);
 153     handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
 154     if (handles == NULL) goto Catch;
 155 
 156     memset(&si, 0, sizeof(si));
 157     si.cb = sizeof(si);
 158     si.dwFlags = STARTF_USESTDHANDLES;
 159 
 160     sa.nLength = sizeof(sa);
 161     sa.lpSecurityDescriptor = 0;
 162     sa.bInheritHandle = TRUE;
 163 
 164     if (handles[0] != (jlong) -1) {
 165         si.hStdInput = (HANDLE) handles[0];
 166         handles[0] = (jlong) -1;
 167     } else {
 168         if (! CreatePipe(&inRead,  &inWrite,  &sa, PIPE_SIZE)) {
 169             win32Error(env, L"CreatePipe");
 170             goto Catch;
 171         }
 172         si.hStdInput = inRead;
 173         SetHandleInformation(inWrite, HANDLE_FLAG_INHERIT, 0);
 174         handles[0] = (jlong) inWrite;
 175     }
 176     SetHandleInformation(si.hStdInput,
 177         HANDLE_FLAG_INHERIT,
 178         HANDLE_FLAG_INHERIT);
 179 
 180     if (handles[1] != (jlong) -1) {
 181         si.hStdOutput = (HANDLE) handles[1];
 182         handles[1] = (jlong) -1;
 183     } else {
 184         if (! CreatePipe(&outRead, &outWrite, &sa, PIPE_SIZE)) {
 185             win32Error(env, L"CreatePipe");
 186             goto Catch;
 187         }
 188         si.hStdOutput = outWrite;
 189         SetHandleInformation(outRead, HANDLE_FLAG_INHERIT, 0);
 190         handles[1] = (jlong) outRead;
 191     }
 192     SetHandleInformation(si.hStdOutput,
 193         HANDLE_FLAG_INHERIT,
 194         HANDLE_FLAG_INHERIT);
 195 
 196     if (redirectErrorStream) {
 197         si.hStdError = si.hStdOutput;
 198         handles[2] = (jlong) -1;
 199     } else if (handles[2] != (jlong) -1) {
 200         si.hStdError = (HANDLE) handles[2];
 201         handles[2] = (jlong) -1;
 202     } else {
 203         if (! CreatePipe(&errRead, &errWrite, &sa, PIPE_SIZE)) {
 204             win32Error(env, L"CreatePipe");
 205             goto Catch;
 206         }
 207         si.hStdError = errWrite;
 208         SetHandleInformation(errRead, HANDLE_FLAG_INHERIT, 0);
 209         handles[2] = (jlong) errRead;
 210     }
 211     SetHandleInformation(si.hStdError,
 212         HANDLE_FLAG_INHERIT,
 213         HANDLE_FLAG_INHERIT);
 214 
 215     processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
 216     ret = CreateProcessW(0,                /* executable name */
 217                          (LPWSTR)pcmd,     /* command line */
 218                          0,                /* process security attribute */
 219                          0,                /* thread security attribute */
 220                          TRUE,             /* inherits system handles */
 221                          processFlag,      /* selected based on exe type */
 222                          (LPVOID)penvBlock,/* environment block */
 223                          (LPCWSTR)pdir,    /* change to the new current directory */
 224                          &si,              /* (in)  startup information */
 225                          &pi);             /* (out) process information */
 226     if (!ret) {
 227         win32Error(env, L"CreateProcess");
 228         goto Catch;
 229     }
 230 
 231     CloseHandle(pi.hThread);
 232     ret = (jlong)pi.hProcess;
 233 
 234  Finally:
 235     /* Always clean up the child's side of the pipes */
 236     closeSafely(inRead);
 237     closeSafely(outWrite);
 238     closeSafely(errWrite);
 239 
 240     if (pcmd != NULL)
 241         (*env)->ReleaseStringChars(env, cmd, pcmd);
 242     if (pdir != NULL)
 243         (*env)->ReleaseStringChars(env, dir, pdir);
 244     if (penvBlock != NULL)
 245         (*env)->ReleaseStringChars(env, envBlock, penvBlock);
 246     if (handles != NULL)
 247         (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
 248     return ret;
 249 
 250  Catch:
 251     /* Clean up the parent's side of the pipes in case of failure only */
 252     closeSafely(inWrite);
 253     closeSafely(outRead);
 254     closeSafely(errRead);
 255     goto Finally;
 256 }
 257 
 258 JNIEXPORT jint JNICALL
 259 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
 260 {
 261     DWORD exit_code;
 262     if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
 263         win32Error(env, L"GetExitCodeProcess");
 264     return exit_code;
 265 }
 266 
 267 JNIEXPORT jint JNICALL
 268 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
 269 {
 270     return STILL_ACTIVE;
 271 }
 272 
 273 JNIEXPORT void JNICALL
 274 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
 275 {
 276     HANDLE events[2];
 277     events[0] = (HANDLE) handle;
 278     events[1] = JVM_GetThreadInterruptEvent();
 279 
 280     if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
 281                                FALSE,    /* Wait for ANY event */
 282                                INFINITE)  /* Wait forever */
 283         == WAIT_FAILED)
 284         win32Error(env, L"WaitForMultipleObjects");
 285 }
 286 
 287 JNIEXPORT void JNICALL
 288 Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env,
 289                                                        jclass ignored,
 290                                                        jlong handle,
 291                                                        jlong timeout)
 292 {
 293     HANDLE events[2];
 294     DWORD dwTimeout = (DWORD)timeout;
 295     DWORD result;
 296     events[0] = (HANDLE) handle;
 297     events[1] = JVM_GetThreadInterruptEvent();
 298     result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
 299                                     FALSE,    /* Wait for ANY event */
 300                                     dwTimeout);  /* Wait for dwTimeout */
 301 
 302     if (result == WAIT_FAILED)
 303         win32Error(env, L"WaitForMultipleObjects");
 304 }
 305 
 306 JNIEXPORT void JNICALL
 307 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
 308 {
 309     TerminateProcess((HANDLE) handle, 1);
 310 }
 311 
 312 JNIEXPORT jboolean JNICALL
 313 Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)
 314 {
 315     DWORD dwExitStatus;
 316     GetExitCodeProcess((HANDLE) handle, &dwExitStatus);
 317     return dwExitStatus == STILL_ACTIVE;
 318 }
 319 
 320 JNIEXPORT jboolean JNICALL
 321 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
 322 {
 323     return CloseHandle((HANDLE) handle);
 324 }
 325 
 326 /**
 327  * Returns a copy of the Unicode characters of a string. Fow now this
 328  * function doesn't handle long path names and other issues.
 329  */
 330 static WCHAR* getPath(JNIEnv *env, jstring ps) {
 331     WCHAR *pathbuf = NULL;
 332     const jchar *chars = (*(env))->GetStringChars(env, ps, NULL);
 333     if (chars != NULL) {
 334         size_t pathlen = wcslen(chars);
 335         pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
 336         if (pathbuf == NULL) {
 337             JNU_ThrowOutOfMemoryError(env, NULL);
 338         } else {
 339             wcscpy(pathbuf, chars);
 340         }
 341         (*env)->ReleaseStringChars(env, ps, chars);
 342     }
 343     return pathbuf;
 344 }
 345 
 346 JNIEXPORT jlong JNICALL
 347 Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path)
 348 {
 349     const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA);
 350     const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
 351     const DWORD disposition = OPEN_ALWAYS;
 352     const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
 353     HANDLE h;
 354     WCHAR *pathbuf = getPath(env, path);
 355     if (pathbuf == NULL) {
 356         /* Exception already pending */
 357         return -1;
 358     }
 359     h = CreateFileW(
 360         pathbuf,            /* Wide char path name */
 361         access,             /* Read and/or write permission */
 362         sharing,            /* File sharing flags */
 363         NULL,               /* Security attributes */
 364         disposition,        /* creation disposition */
 365         flagsAndAttributes, /* flags and attributes */
 366         NULL);
 367     free(pathbuf);
 368     if (h == INVALID_HANDLE_VALUE) {
 369         JNU_ThrowIOExceptionWithLastError(env, "CreateFileW");
 370     }
 371     return ptr_to_jlong(h);
 372 }