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