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 }