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