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 }