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 JNIEXPORT jlong JNICALL 67 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, 68 jstring cmd, 69 jstring envBlock, 70 jstring dir, 71 jlongArray stdHandles, 72 jboolean redirectErrorStream) 73 { 74 HANDLE inRead = INVALID_HANDLE_VALUE; 75 HANDLE inWrite = INVALID_HANDLE_VALUE; 76 HANDLE outRead = INVALID_HANDLE_VALUE; 99 penvBlock = ((*env)->GetStringChars(env, envBlock, NULL)); 100 if (penvBlock == NULL) goto Catch; 101 } 102 assert(stdHandles != NULL); 103 handles = (*env)->GetLongArrayElements(env, stdHandles, NULL); 104 if (handles == NULL) goto Catch; 105 106 memset(&si, 0, sizeof(si)); 107 si.cb = sizeof(si); 108 si.dwFlags = STARTF_USESTDHANDLES; 109 110 sa.nLength = sizeof(sa); 111 sa.lpSecurityDescriptor = 0; 112 sa.bInheritHandle = TRUE; 113 114 if (handles[0] != (jlong) -1) { 115 si.hStdInput = (HANDLE) handles[0]; 116 handles[0] = (jlong) -1; 117 } else { 118 if (! CreatePipe(&inRead, &inWrite, &sa, PIPE_SIZE)) { 119 win32Error(env, "CreatePipe"); 120 goto Catch; 121 } 122 si.hStdInput = inRead; 123 SetHandleInformation(inWrite, HANDLE_FLAG_INHERIT, 0); 124 handles[0] = (jlong) inWrite; 125 } 126 SetHandleInformation(si.hStdInput, 127 HANDLE_FLAG_INHERIT, 128 HANDLE_FLAG_INHERIT); 129 130 if (handles[1] != (jlong) -1) { 131 si.hStdOutput = (HANDLE) handles[1]; 132 handles[1] = (jlong) -1; 133 } else { 134 if (! CreatePipe(&outRead, &outWrite, &sa, PIPE_SIZE)) { 135 win32Error(env, "CreatePipe"); 136 goto Catch; 137 } 138 si.hStdOutput = outWrite; 139 SetHandleInformation(outRead, HANDLE_FLAG_INHERIT, 0); 140 handles[1] = (jlong) outRead; 141 } 142 SetHandleInformation(si.hStdOutput, 143 HANDLE_FLAG_INHERIT, 144 HANDLE_FLAG_INHERIT); 145 146 if (redirectErrorStream) { 147 si.hStdError = si.hStdOutput; 148 handles[2] = (jlong) -1; 149 } else if (handles[2] != (jlong) -1) { 150 si.hStdError = (HANDLE) handles[2]; 151 handles[2] = (jlong) -1; 152 } else { 153 if (! CreatePipe(&errRead, &errWrite, &sa, PIPE_SIZE)) { 154 win32Error(env, "CreatePipe"); 155 goto Catch; 156 } 157 si.hStdError = errWrite; 158 SetHandleInformation(errRead, HANDLE_FLAG_INHERIT, 0); 159 handles[2] = (jlong) errRead; 160 } 161 SetHandleInformation(si.hStdError, 162 HANDLE_FLAG_INHERIT, 163 HANDLE_FLAG_INHERIT); 164 165 processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT; 166 ret = CreateProcessW(0, /* executable name */ 167 (LPWSTR)pcmd, /* command line */ 168 0, /* process security attribute */ 169 0, /* thread security attribute */ 170 TRUE, /* inherits system handles */ 171 processFlag, /* selected based on exe type */ 172 (LPVOID)penvBlock,/* environment block */ 173 (LPCWSTR)pdir, /* change to the new current directory */ 174 &si, /* (in) startup information */ 175 &pi); /* (out) process information */ 176 if (!ret) { 177 win32Error(env, "CreateProcess"); 178 goto Catch; 179 } 180 181 CloseHandle(pi.hThread); 182 ret = (jlong)pi.hProcess; 183 184 Finally: 185 /* Always clean up the child's side of the pipes */ 186 closeSafely(inRead); 187 closeSafely(outWrite); 188 closeSafely(errWrite); 189 190 if (pcmd != NULL) 191 (*env)->ReleaseStringChars(env, cmd, pcmd); 192 if (pdir != NULL) 193 (*env)->ReleaseStringChars(env, dir, pdir); 194 if (penvBlock != NULL) 195 (*env)->ReleaseStringChars(env, envBlock, penvBlock); 196 if (handles != NULL) 197 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0); 198 return ret; 199 200 Catch: 201 /* Clean up the parent's side of the pipes in case of failure only */ 202 closeSafely(inWrite); 203 closeSafely(outRead); 204 closeSafely(errRead); 205 goto Finally; 206 } 207 208 JNIEXPORT jint JNICALL 209 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle) 210 { 211 DWORD exit_code; 212 if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0) 213 win32Error(env, "GetExitCodeProcess"); 214 return exit_code; 215 } 216 217 JNIEXPORT jint JNICALL 218 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored) 219 { 220 return STILL_ACTIVE; 221 } 222 223 JNIEXPORT void JNICALL 224 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle) 225 { 226 HANDLE events[2]; 227 events[0] = (HANDLE) handle; 228 events[1] = JVM_GetThreadInterruptEvent(); 229 230 if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events, 231 FALSE, /* Wait for ANY event */ 232 INFINITE) /* Wait forever */ 233 == WAIT_FAILED) 234 win32Error(env, "WaitForMultipleObjects"); 235 } 236 237 JNIEXPORT void JNICALL 238 Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env, 239 jclass ignored, 240 jlong handle, 241 jlong timeout) 242 { 243 HANDLE events[2]; 244 DWORD dwTimeout = (DWORD)timeout; 245 DWORD result; 246 events[0] = (HANDLE) handle; 247 events[1] = JVM_GetThreadInterruptEvent(); 248 result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events, 249 FALSE, /* Wait for ANY event */ 250 dwTimeout); /* Wait for dwTimeout */ 251 252 if (result == WAIT_FAILED) 253 win32Error(env, "WaitForMultipleObjects"); 254 } 255 256 JNIEXPORT void JNICALL 257 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle) 258 { 259 TerminateProcess((HANDLE) handle, 1); 260 } 261 262 JNIEXPORT jboolean JNICALL 263 Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle) 264 { 265 DWORD dwExitStatus; 266 GetExitCodeProcess(handle, &dwExitStatus); 267 return dwExitStatus == STILL_ACTIVE; 268 } 269 270 JNIEXPORT jboolean JNICALL 271 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle) 272 { 273 return CloseHandle((HANDLE) handle); 274 } 275 276 /** 277 * Returns a copy of the Unicode characters of a string. Fow now this 278 * function doesn't handle long path names and other issues. 279 */ 280 static WCHAR* getPath(JNIEnv *env, jstring ps) { 281 WCHAR *pathbuf = NULL; 282 const jchar *chars = (*(env))->GetStringChars(env, ps, NULL); 283 if (chars != NULL) { 284 size_t pathlen = wcslen(chars); 285 pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR)); 286 if (pathbuf == NULL) { | 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; 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) { |