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