1 /*
2 * Copyright (c) 1997, 2013, 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 */
os_error_message(int errnum,WCHAR * utf16_OSErrorMsg,size_t maxMsgLength)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
win32Error(JNIEnv * env,const WCHAR * functionName)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 int n = os_error_message(errnum, utf16_OSErrorMsg, ARRAY_SIZE(utf16_OSErrorMsg));
83 n = (n > 0)
84 ? swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s error=%d, %s", functionName, errnum, utf16_OSErrorMsg)
85 : swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s failed, error=%d", functionName, errnum);
86
87 if (n > 0) /*terminate '\0' is not a part of conversion procedure*/
88 n = WideCharToMultiByte(
89 CP_UTF8,
90 0,
91 utf16_javaMessage,
92 n, /*by creation n <= MESSAGE_LENGTH*/
93 utf8_javaMessage,
94 MESSAGE_LENGTH*2,
95 NULL,
96 NULL);
97
98 /*no way to die*/
99 {
100 const char *errorMessage = "Secondary error while OS message extraction";
101 if (n > 0) {
102 utf8_javaMessage[min(MESSAGE_LENGTH*2 - 1, n)] = '\0';
103 errorMessage = utf8_javaMessage;
104 }
105 JNU_ThrowIOException(env, errorMessage);
106 }
107 }
108
109 static void
closeSafely(HANDLE handle)110 closeSafely(HANDLE handle)
111 {
112 if (handle != INVALID_HANDLE_VALUE)
113 CloseHandle(handle);
114 }
115
hasInheritFlag(HANDLE handle)116 static BOOL hasInheritFlag(HANDLE handle)
117 {
118 DWORD mask;
119 if (GetHandleInformation(handle, &mask)) {
120 return mask & HANDLE_FLAG_INHERIT;
121 }
122 return FALSE;
123 }
124
125 #define HANDLE_STORAGE_SIZE 6
126 #define OFFSET_READ 0
127 #define OFFSET_WRITE 1
128 //long signed version of INVALID_HANDLE_VALUE
129 #define JAVA_INVALID_HANDLE_VALUE ((jlong) -1)
130 #define OPPOSITE_END(offset) (offset==OFFSET_READ ? OFFSET_WRITE : OFFSET_READ)
131
132 /* Pipe holder structure */
133 typedef struct _STDHOLDER {
134 HANDLE pipe[2];
135 int offset;
136 } STDHOLDER;
137
138 /* Responsible for correct initialization of the [pHolder] structure
139 (that is used for handles recycling) if needs,
140 and appropriate setup of IOE handle [phStd] for child process based
141 on created pipe or Java handle. */
initHolder(JNIEnv * env,jlong * pjhandles,STDHOLDER * pHolder,HANDLE * phStd)142 static BOOL initHolder(
143 JNIEnv *env,
144 jlong *pjhandles, /* IN OUT - the handle form Java,
145 that can be a file, console or undefined */
146 STDHOLDER *pHolder, /* OUT - initialized structure that holds pipe
147 handles */
148 HANDLE *phStd /* OUT - initialized handle for child process */
149 ) {
150 /* Here we test the value from Java against invalid
151 handle value. We are not using INVALID_HANDLE_VALUE macro
152 due to double signed/unsigned and 32/64bit ambiguity.
153 Otherwise it will be easy to get the wrong
154 value 0x00000000FFFFFFFF
155 instead 0xFFFFFFFFFFFFFFFF. */
156 if (*pjhandles != JAVA_INVALID_HANDLE_VALUE) {
157 /* Java file or console redirection */
158 *phStd = (HANDLE) *pjhandles;
159 /* Here we set the related Java stream (Process.getXXXXStream())
160 to [ProcessBuilder.NullXXXXStream.INSTANCE] value.
161 The initial Java handle [*pjhandles] will be closed in
162 ANY case. It is not a handle leak. */
163 *pjhandles = JAVA_INVALID_HANDLE_VALUE;
164 } else {
165 /* Creation of parent-child pipe */
166 if (!CreatePipe(
167 &pHolder->pipe[OFFSET_READ],
168 &pHolder->pipe[OFFSET_WRITE],
169 NULL, /* we would like to inherit
170 default process access,
171 instead of 'Everybody' access */
172 PIPE_SIZE))
173 {
174 win32Error(env, L"CreatePipe");
175 return FALSE;
176 } else {
177 /* [thisProcessEnd] has no the inherit flag because
178 the [lpPipeAttributes] param of [CreatePipe]
179 had the NULL value. */
180 HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)];
181 *phStd = pHolder->pipe[pHolder->offset];
182 *pjhandles = (jlong) thisProcessEnd;
183 }
184 }
185 /* Pipe handle will be closed in the [releaseHolder] call,
186 file handle will be closed in Java.
187 The long-live handle need to restore the inherit flag,
188 we do it later in the [prepareIOEHandleState] call. */
189 SetHandleInformation(
190 *phStd,
191 HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
192 return TRUE;
193 }
194
195 /* Smart recycling of pipe handles in [pHolder]. For the failed
196 create process attempts, both ends of pipe need to be released.
197 The [complete] has the [TRUE] value in the failed attempt. */
releaseHolder(BOOL complete,STDHOLDER * pHolder)198 static void releaseHolder(BOOL complete, STDHOLDER *pHolder) {
199 closeSafely(pHolder->pipe[pHolder->offset]);
200 if (complete) {
201 /* Error occur, close this process pipe end */
202 closeSafely(pHolder->pipe[OPPOSITE_END(pHolder->offset)]);
203 }
204 }
205
206 /* Stores and drops the inherit flag of handles that should not
207 be shared with the child process by default, but can hold the
208 inherit flag due to MS process birth specific. */
prepareIOEHandleState(HANDLE * stdIOE,BOOL * inherit)209 static void prepareIOEHandleState(
210 HANDLE *stdIOE,
211 BOOL *inherit)
212 {
213 int i;
214 for (i = 0; i < HANDLE_STORAGE_SIZE; ++i) {
215 HANDLE hstd = stdIOE[i];
216 if (INVALID_HANDLE_VALUE != hstd && hasInheritFlag(hstd)) {
217 /* FALSE by default */
218 inherit[i] = TRUE;
219 /* Java does not need implicit inheritance for IOE handles,
220 so we drop inherit flag that probably was installed by
221 previous CreateProcess call that launched current process.
222 We will return the handle state back after CreateProcess call.
223 By clearing inherit flag we prevent "greedy grandchild" birth.
224 The explicit inheritance for child process IOE handles is
225 implemented in the [initHolder] call. */
226 SetHandleInformation(hstd, HANDLE_FLAG_INHERIT, 0);
227 }
228 }
229 }
230
231 /* Restores the inheritance flag of handles from stored values. */
restoreIOEHandleState(const HANDLE * stdIOE,const BOOL * inherit)232 static void restoreIOEHandleState(
233 const HANDLE *stdIOE,
234 const BOOL *inherit)
235 {
236 /* The set of current process standard IOE handles and
237 the set of child process IOE handles can intersect.
238 To restore the inherit flag right, we use backward
239 array iteration. */
240 int i;
241 for (i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i)
242 if (INVALID_HANDLE_VALUE != stdIOE[i]) {
243 /* Restore inherit flag for any case.
244 The handle can be changed by explicit inheritance.*/
245 SetHandleInformation(stdIOE[i],
246 HANDLE_FLAG_INHERIT,
247 inherit[i] ? HANDLE_FLAG_INHERIT : 0);
248 }
249 }
250
251 /* Please, read about the MS inheritance problem
252 http://support.microsoft.com/kb/315939
253 and critical section/synchronized block solution. */
processCreate(JNIEnv * env,const jchar * pcmd,const jchar * penvBlock,const jchar * pdir,jlong * handles,jboolean redirectErrorStream)254 static jlong processCreate(
255 JNIEnv *env,
256 const jchar *pcmd,
257 const jchar *penvBlock,
258 const jchar *pdir,
259 jlong *handles,
260 jboolean redirectErrorStream)
261 {
262 jlong ret = 0L;
263 STARTUPINFOW si = {sizeof(si)};
264
265 /* Handles for which the inheritance flag must be restored. */
266 HANDLE stdIOE[HANDLE_STORAGE_SIZE] = {
267 /* Current process standard IOE handles: JDK-7147084 */
268 INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
269 /* Child process IOE handles: JDK-6921885 */
270 (HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]};
271 BOOL inherit[HANDLE_STORAGE_SIZE] = {
272 FALSE, FALSE, FALSE,
273 FALSE, FALSE, FALSE};
274
275 /* These three should not be closed by CloseHandle! */
276 stdIOE[0] = GetStdHandle(STD_INPUT_HANDLE);
277 stdIOE[1] = GetStdHandle(STD_OUTPUT_HANDLE);
278 stdIOE[2] = GetStdHandle(STD_ERROR_HANDLE);
279
280 prepareIOEHandleState(stdIOE, inherit);
281 {
282 /* Input */
283 STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ};
284 if (initHolder(env, &handles[0], &holderIn, &si.hStdInput)) {
285
286 /* Output */
287 STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
288 if (initHolder(env, &handles[1], &holderOut, &si.hStdOutput)) {
289
290 /* Error */
291 STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
292 BOOL success;
293 if (redirectErrorStream) {
294 si.hStdError = si.hStdOutput;
295 /* Here we set the error stream to [ProcessBuilder.NullInputStream.INSTANCE]
296 value. That is in accordance with Java Doc for the redirection case.
297 The Java file for the [ handles[2] ] will be closed in ANY case. It is not
298 a handle leak. */
299 handles[2] = JAVA_INVALID_HANDLE_VALUE;
300 success = TRUE;
301 } else {
302 success = initHolder(env, &handles[2], &holderErr, &si.hStdError);
303 }
304
305 if (success) {
306 PROCESS_INFORMATION pi;
307 DWORD processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
308
309 /* If the standard I/O is inherited, CREATE_NO_WINDOW must not be used. */
310 if (GetConsoleWindow() != NULL &&
311 (si.hStdInput == stdIOE[0] ||
312 si.hStdOutput == stdIOE[1] ||
313 si.hStdError == (redirectErrorStream ? stdIOE[1] : stdIOE[2])))
314 {
315 processFlag &= ~CREATE_NO_WINDOW;
316 }
317
318 si.dwFlags = STARTF_USESTDHANDLES;
319 if (!CreateProcessW(
320 NULL, /* executable name */
321 (LPWSTR)pcmd, /* command line */
322 NULL, /* process security attribute */
323 NULL, /* thread security attribute */
324 TRUE, /* inherits system handles */
325 processFlag, /* selected based on exe type */
326 (LPVOID)penvBlock,/* environment block */
327 (LPCWSTR)pdir, /* change to the new current directory */
328 &si, /* (in) startup information */
329 &pi)) /* (out) process information */
330 {
331 win32Error(env, L"CreateProcess");
332 } else {
333 closeSafely(pi.hThread);
334 ret = (jlong)pi.hProcess;
335 }
336 }
337 releaseHolder(ret == 0, &holderErr);
338 releaseHolder(ret == 0, &holderOut);
339 }
340 releaseHolder(ret == 0, &holderIn);
341 }
342 }
343 restoreIOEHandleState(stdIOE, inherit);
344
345 return ret;
346 }
347
348 JNIEXPORT jlong JNICALL
Java_java_lang_ProcessImpl_create(JNIEnv * env,jclass ignored,jstring cmd,jstring envBlock,jstring dir,jlongArray stdHandles,jboolean redirectErrorStream)349 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
350 jstring cmd,
351 jstring envBlock,
352 jstring dir,
353 jlongArray stdHandles,
354 jboolean redirectErrorStream)
355 {
356 jlong ret = 0;
357 if (cmd != NULL && stdHandles != NULL) {
358 const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL);
359 if (pcmd != NULL) {
360 const jchar *penvBlock = (envBlock != NULL)
361 ? (*env)->GetStringChars(env, envBlock, NULL)
362 : NULL;
363 if (!(*env)->ExceptionCheck(env)) {
364 const jchar *pdir = (dir != NULL)
365 ? (*env)->GetStringChars(env, dir, NULL)
366 : NULL;
367 if (!(*env)->ExceptionCheck(env)) {
368 jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
369 if (handles != NULL) {
370 ret = processCreate(
371 env,
372 pcmd,
373 penvBlock,
374 pdir,
375 handles,
376 redirectErrorStream);
377 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
378 }
379 if (pdir != NULL)
380 (*env)->ReleaseStringChars(env, dir, pdir);
381 }
382 if (penvBlock != NULL)
383 (*env)->ReleaseStringChars(env, envBlock, penvBlock);
384 }
385 (*env)->ReleaseStringChars(env, cmd, pcmd);
386 }
387 }
388 return ret;
389 }
390
391 JNIEXPORT jint JNICALL
Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv * env,jclass ignored,jlong handle)392 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
393 {
394 DWORD exit_code;
395 if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
396 win32Error(env, L"GetExitCodeProcess");
397 return exit_code;
398 }
399
400 JNIEXPORT jint JNICALL
Java_java_lang_ProcessImpl_getStillActive(JNIEnv * env,jclass ignored)401 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
402 {
403 return STILL_ACTIVE;
404 }
405
406 JNIEXPORT void JNICALL
Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv * env,jclass ignored,jlong handle)407 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
408 {
409 HANDLE events[2];
410 events[0] = (HANDLE) handle;
411 events[1] = JVM_GetThreadInterruptEvent();
412
413 if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
414 FALSE, /* Wait for ANY event */
415 INFINITE) /* Wait forever */
416 == WAIT_FAILED)
417 win32Error(env, L"WaitForMultipleObjects");
418 }
419
420 JNIEXPORT void JNICALL
Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv * env,jclass ignored,jlong handle,jlong timeoutMillis)421 Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env,
422 jclass ignored,
423 jlong handle,
424 jlong timeoutMillis)
425 {
426 HANDLE events[2];
427 DWORD dwTimeout = (DWORD)timeoutMillis;
428 DWORD result;
429 events[0] = (HANDLE) handle;
430 events[1] = JVM_GetThreadInterruptEvent();
431 result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
432 FALSE, /* Wait for ANY event */
433 dwTimeout); /* Wait for dwTimeout */
434
435 if (result == WAIT_FAILED)
436 win32Error(env, L"WaitForMultipleObjects");
437 }
438
439 JNIEXPORT void JNICALL
Java_java_lang_ProcessImpl_terminateProcess(JNIEnv * env,jclass ignored,jlong handle)440 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
441 {
442 TerminateProcess((HANDLE) handle, 1);
443 }
444
445 JNIEXPORT jboolean JNICALL
Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv * env,jclass ignored,jlong handle)446 Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)
447 {
448 DWORD dwExitStatus;
449 GetExitCodeProcess((HANDLE) handle, &dwExitStatus);
450 return dwExitStatus == STILL_ACTIVE;
451 }
452
453 JNIEXPORT jboolean JNICALL
Java_java_lang_ProcessImpl_closeHandle(JNIEnv * env,jclass ignored,jlong handle)454 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
455 {
456 return (jboolean) CloseHandle((HANDLE) handle);
457 }
458
459 /**
460 * Returns a copy of the Unicode characters of a string. Fow now this
461 * function doesn't handle long path names and other issues.
462 */
getPath(JNIEnv * env,jstring ps)463 static WCHAR* getPath(JNIEnv *env, jstring ps) {
464 WCHAR *pathbuf = NULL;
465 const jchar *chars = (*(env))->GetStringChars(env, ps, NULL);
466 if (chars != NULL) {
467 size_t pathlen = wcslen(chars);
468 pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
469 if (pathbuf == NULL) {
470 JNU_ThrowOutOfMemoryError(env, NULL);
471 } else {
472 wcscpy(pathbuf, chars);
473 }
474 (*env)->ReleaseStringChars(env, ps, chars);
475 }
476 return pathbuf;
477 }
478
479 JNIEXPORT jlong JNICALL
Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv * env,jclass ignored,jstring path)480 Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path)
481 {
482 const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA);
483 const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
484 const DWORD disposition = OPEN_ALWAYS;
485 const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
486 HANDLE h;
487 WCHAR *pathbuf = getPath(env, path);
488 if (pathbuf == NULL) {
489 /* Exception already pending */
490 return -1;
491 }
492 h = CreateFileW(
493 pathbuf, /* Wide char path name */
494 access, /* Read and/or write permission */
495 sharing, /* File sharing flags */
496 NULL, /* Security attributes */
497 disposition, /* creation disposition */
498 flagsAndAttributes, /* flags and attributes */
499 NULL);
500 free(pathbuf);
501 if (h == INVALID_HANDLE_VALUE) {
502 JNU_ThrowIOExceptionWithLastError(env, "CreateFileW");
503 }
504 return ptr_to_jlong(h);
505 }
506