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 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; 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) { |