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 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 static BOOL hasInheritFlag(HANDLE handle) 67 { 68 DWORD mask; 69 if (GetHandleInformation(handle, &mask)) { 70 return mask & HANDLE_FLAG_INHERIT; 71 } 72 return FALSE; 73 } 74 75 #define HANDLE_STORAGE_SIZE 6 76 #define OFFSET_READ 0 77 #define OFFSET_WRITE 1 78 #define OPPOSITE_END(offset) (offset==OFFSET_READ ? OFFSET_WRITE : OFFSET_READ) 79 80 typedef struct _STDHOLDER { 81 HANDLE pipe[2]; 82 int offset; 83 } STDHOLDER; 84 85 static BOOL initHolder( 86 JNIEnv *env, 87 STDHOLDER *pHolder, 88 jlong *pjhandles, 89 HANDLE *phStd) 90 { 91 if (*pjhandles != (jlong) -1) { 92 *phStd = (HANDLE) *pjhandles; 93 *pjhandles = (jlong) -1; 94 } else { 95 if (!CreatePipe( 96 &pHolder->pipe[OFFSET_READ], 97 &pHolder->pipe[OFFSET_WRITE], 98 NULL, /* we would like to inherit 99 default process access, 100 instead of 'Everybody' access */ 101 PIPE_SIZE)) 102 { 103 win32Error(env, "CreatePipe"); 104 return FALSE; 105 } else { 106 /* [thisProcessEnd] has no the inherit flag. 107 the [lpPipeAttributes] param had the NULL value. */ 108 HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)]; 109 *phStd = pHolder->pipe[pHolder->offset]; 110 *pjhandles = (jlong) thisProcessEnd; 111 } 112 } 113 /* Pipe handle will be closed in the [releaseHolder] call, 114 file handle will be closed in Java. 115 The long-live handle need to restore the inherit flag, 116 we do it later in the [prepareIOEHandleState] call. */ 117 SetHandleInformation( 118 *phStd, 119 HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); 120 return TRUE; 121 } 122 123 static void releaseHolder(BOOL complete, STDHOLDER *pHolder) { 124 closeSafely(pHolder->pipe[pHolder->offset]); 125 if (complete) { 126 /* Error occur, close this process pipe end */ 127 closeSafely(pHolder->pipe[OPPOSITE_END(pHolder->offset)]); 128 } 129 } 130 131 static void prepareIOEHandleState( 132 HANDLE *stdIOE, 133 BOOL *inherit) 134 { 135 int i; 136 for (i = 0; i < HANDLE_STORAGE_SIZE; ++i) { 137 HANDLE hstd = stdIOE[i]; 138 if (INVALID_HANDLE_VALUE != hstd && hasInheritFlag(hstd)) { 139 /* FALSE by default */ 140 inherit[i] = TRUE; 141 /* Java does not need implicit inheritance for IOE handles, 142 so we drop inherit flag that probably was installed by 143 previous CreateProcess call that launched current process. 144 We will return the handle state back after CreateProcess call. 145 By clearing inherit flag we prevent "greedy grandchild" birth. 146 The explicit inheritance for child process IOE handles is 147 supported in the [initHolder] call. */ 148 SetHandleInformation(hstd, HANDLE_FLAG_INHERIT, 0); 149 } 150 } 151 } 152 153 static void restoreIOEHandleState( 154 const HANDLE *stdIOE, 155 const BOOL *inherit) 156 { 157 /* The set of current process standard IOE handles and 158 the set of child process IOE handles can intersect. 159 To restore the inherit flag right, we use backward 160 array iteration. */ 161 int i; 162 for (i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i) 163 if (INVALID_HANDLE_VALUE != stdIOE[i]) { 164 /* Restore inherit flag for any case. 165 The handle can be changed by explicit inheritance.*/ 166 SetHandleInformation(stdIOE[i], 167 HANDLE_FLAG_INHERIT, 168 inherit[i] ? HANDLE_FLAG_INHERIT : 0); 169 } 170 } 171 172 /* Please, read about the MS inheritance problem 173 http://support.microsoft.com/kb/315939 174 and critical section/synchronized block solution. */ 175 static jlong processCreate( 176 JNIEnv *env, 177 const jchar *pcmd, 178 const jchar *penvBlock, 179 const jchar *pdir, 180 jlong *handles, 181 jboolean redirectErrorStream) 182 { 183 jlong ret = 0L; 184 STARTUPINFOW si = {sizeof(si)}; 185 186 /* Handles for which the inheritance flag must be restored. */ 187 HANDLE stdIOE[HANDLE_STORAGE_SIZE] = { 188 /* Current process standard IOE handles: JDK-7147084 */ 189 INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 190 /* Child process IOE handles: JDK-6921885 */ 191 (HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]}; 192 BOOL inherit[HANDLE_STORAGE_SIZE] = { 193 FALSE, FALSE, FALSE, 194 FALSE, FALSE, FALSE}; 195 196 { 197 /* Extraction of current process standard IOE handles */ 198 DWORD idsIOE[3] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE}; 199 int i; 200 for (i = 0; i < 3; ++i) 201 /* Should not be closed by CloseHandle! */ 202 stdIOE[i] = GetStdHandle(idsIOE[i]); 203 } 204 205 prepareIOEHandleState(stdIOE, inherit); 206 { 207 /* Input */ 208 STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ}; 209 if (initHolder(env, &holderIn, &handles[0], &si.hStdInput)) { 210 211 /* Output */ 212 STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE}; 213 if (initHolder(env, &holderOut, &handles[1], &si.hStdOutput)) { 214 215 /* Error */ 216 STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE}; 217 BOOL success; 218 if (redirectErrorStream) { 219 si.hStdError = si.hStdOutput; 220 handles[2] = (jlong) -1; 221 success = TRUE; 222 } else { 223 success = initHolder(env, &holderErr, &handles[2], &si.hStdError); 224 } 225 226 if (success) { 227 PROCESS_INFORMATION pi; 228 DWORD processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT; 229 230 si.dwFlags = STARTF_USESTDHANDLES; 231 if (!CreateProcessW( 232 NULL, /* executable name */ 233 (LPWSTR)pcmd, /* command line */ 234 NULL, /* process security attribute */ 235 NULL, /* thread security attribute */ 236 TRUE, /* inherits system handles */ 237 processFlag, /* selected based on exe type */ 238 (LPVOID)penvBlock,/* environment block */ 239 (LPCWSTR)pdir, /* change to the new current directory */ 240 &si, /* (in) startup information */ 241 &pi)) /* (out) process information */ 242 { 243 win32Error(env, "CreateProcess"); 244 } else { 245 closeSafely(pi.hThread); 246 ret = (jlong)pi.hProcess; 247 } 248 } 249 releaseHolder(ret == 0, &holderErr); 250 releaseHolder(ret == 0, &holderOut); 251 } 252 releaseHolder(ret == 0, &holderIn); 253 } 254 } 255 restoreIOEHandleState(stdIOE, inherit); 256 257 return ret; 258 } 259 260 JNIEXPORT jlong JNICALL 261 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, 262 jstring cmd, 263 jstring envBlock, 264 jstring dir, 265 jlongArray stdHandles, 266 jboolean redirectErrorStream) 267 { 268 jlong ret = 0; 269 if (cmd != NULL 270 && stdHandles != NULL) 271 { 272 const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL); 273 if (pcmd != NULL) { 274 const jchar *penvBlock = (envBlock != NULL) 275 ? (*env)->GetStringChars(env, envBlock, NULL) 276 : NULL; 277 const jchar *pdir = (dir != NULL) 278 ? (*env)->GetStringChars(env, dir, NULL) 279 : NULL; 280 jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL); 281 if (handles != NULL) { 282 ret = processCreate( 283 env, 284 pcmd, 285 penvBlock, 286 pdir, 287 handles, 288 redirectErrorStream); 289 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0); 290 } 291 if (pdir != NULL) 292 (*env)->ReleaseStringChars(env, dir, pdir); 293 if (penvBlock != NULL) 294 (*env)->ReleaseStringChars(env, envBlock, penvBlock); 295 (*env)->ReleaseStringChars(env, cmd, pcmd); 296 } 297 } 298 return ret; 299 } 300 301 JNIEXPORT jint JNICALL 302 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle) 303 { 304 DWORD exit_code; 305 if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0) 306 win32Error(env, "GetExitCodeProcess"); 307 return exit_code; 308 } 309 310 JNIEXPORT jint JNICALL 311 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored) 312 { 313 return STILL_ACTIVE; 314 } 315 316 JNIEXPORT void JNICALL 317 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle) 318 { 319 HANDLE events[2]; 320 events[0] = (HANDLE) handle; 321 events[1] = JVM_GetThreadInterruptEvent(); 322 323 if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events, 324 FALSE, /* Wait for ANY event */ 325 INFINITE) /* Wait forever */ 326 == WAIT_FAILED) 327 win32Error(env, "WaitForMultipleObjects"); 328 } 329 330 JNIEXPORT void JNICALL 331 Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env, 332 jclass ignored, 333 jlong handle, 334 jlong timeout) 335 { 336 HANDLE events[2]; 337 DWORD dwTimeout = (DWORD)timeout; 338 DWORD result; 339 events[0] = (HANDLE) handle; 340 events[1] = JVM_GetThreadInterruptEvent(); 341 result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events, 342 FALSE, /* Wait for ANY event */ 343 dwTimeout); /* Wait for dwTimeout */ 344 345 if (result == WAIT_FAILED) 346 win32Error(env, "WaitForMultipleObjects"); 347 } 348 349 JNIEXPORT void JNICALL 350 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle) 351 { 352 TerminateProcess((HANDLE) handle, 1); 353 } 354 355 JNIEXPORT jboolean JNICALL 356 Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle) 357 { 358 DWORD dwExitStatus; 359 GetExitCodeProcess((HANDLE) handle, &dwExitStatus); 360 return dwExitStatus == STILL_ACTIVE; 361 } 362 363 JNIEXPORT jboolean JNICALL 364 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle) 365 { 366 return CloseHandle((HANDLE) handle); 367 } 368 369 /** 370 * Returns a copy of the Unicode characters of a string. Fow now this 371 * function doesn't handle long path names and other issues. 372 */ 373 static WCHAR* getPath(JNIEnv *env, jstring ps) { 374 WCHAR *pathbuf = NULL; 375 const jchar *chars = (*(env))->GetStringChars(env, ps, NULL); 376 if (chars != NULL) { 377 size_t pathlen = wcslen(chars); 378 pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR)); 379 if (pathbuf == NULL) { 380 JNU_ThrowOutOfMemoryError(env, NULL); 381 } else { 382 wcscpy(pathbuf, chars); 383 } 384 (*env)->ReleaseStringChars(env, ps, chars); 385 } 386 return pathbuf; 387 } 388 389 JNIEXPORT jlong JNICALL 390 Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path) 391 { 392 const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA); 393 const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; 394 const DWORD disposition = OPEN_ALWAYS; 395 const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL; 396 HANDLE h; 397 WCHAR *pathbuf = getPath(env, path); 398 if (pathbuf == NULL) { 399 /* Exception already pending */ 400 return -1; 401 } 402 h = CreateFileW( 403 pathbuf, /* Wide char path name */ 404 access, /* Read and/or write permission */ 405 sharing, /* File sharing flags */ 406 NULL, /* Security attributes */ 407 disposition, /* creation disposition */ 408 flagsAndAttributes, /* flags and attributes */ 409 NULL); 410 free(pathbuf); 411 if (h == INVALID_HANDLE_VALUE) { 412 JNU_ThrowIOExceptionWithLastError(env, "CreateFileW"); 413 } 414 return ptr_to_jlong(h); 415 }