jdk/src/java.base/windows/classes/java/lang/ProcessImpl.java
author rriggs
Fri, 02 Sep 2016 12:30:46 -0400
changeset 40738 86952e676976
parent 39061 0a7abfc4f4b0
child 44640 590dec7cadb4
permissions -rw-r--r--
8155102: (Process) Process.toString could include pid, isAlive, exitStatus Reviewed-by: rriggs Contributed-by: andrey.dyachkov@gmail.com
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
30899
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
     2
 * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 715
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 715
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 *
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 715
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 715
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 715
diff changeset
    23
 * questions.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
package java.lang;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
24577
b3bf9c82a050 8003488: (process) Provide Process.getPid()
rriggs
parents: 23010
diff changeset
    28
import java.io.BufferedInputStream;
b3bf9c82a050 8003488: (process) Provide Process.getPid()
rriggs
parents: 23010
diff changeset
    29
import java.io.BufferedOutputStream;
b3bf9c82a050 8003488: (process) Provide Process.getPid()
rriggs
parents: 23010
diff changeset
    30
import java.io.File;
b3bf9c82a050 8003488: (process) Provide Process.getPid()
rriggs
parents: 23010
diff changeset
    31
import java.io.FileDescriptor;
b3bf9c82a050 8003488: (process) Provide Process.getPid()
rriggs
parents: 23010
diff changeset
    32
import java.io.FileInputStream;
b3bf9c82a050 8003488: (process) Provide Process.getPid()
rriggs
parents: 23010
diff changeset
    33
import java.io.FileOutputStream;
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
    34
import java.io.IOException;
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
    35
import java.io.InputStream;
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
    36
import java.io.OutputStream;
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
    37
import java.lang.ProcessBuilder.Redirect;
7515
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    38
import java.security.AccessController;
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    39
import java.security.PrivilegedAction;
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
    40
import java.util.ArrayList;
30899
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
    41
import java.util.concurrent.CompletableFuture;
13149
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
    42
import java.util.concurrent.TimeUnit;
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
    43
import java.util.regex.Matcher;
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
    44
import java.util.regex.Pattern;
34942
4b462ee18ed9 8146028: Common Cleaner for finalization replacements in OpenJDK
rriggs
parents: 33826
diff changeset
    45
32834
e1dca5fe4de3 8137056: Move SharedSecrets and interface friends out of sun.misc
chegar
parents: 31682
diff changeset
    46
import jdk.internal.misc.JavaIOFileDescriptorAccess;
e1dca5fe4de3 8137056: Move SharedSecrets and interface friends out of sun.misc
chegar
parents: 31682
diff changeset
    47
import jdk.internal.misc.SharedSecrets;
34942
4b462ee18ed9 8146028: Common Cleaner for finalization replacements in OpenJDK
rriggs
parents: 33826
diff changeset
    48
import jdk.internal.ref.CleanerFactory;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
/* This class is for the exclusive use of ProcessBuilder.start() to
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
 * create new processes.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
 * @author Martin Buchholz
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
 * @since   1.5
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
final class ProcessImpl extends Process {
32834
e1dca5fe4de3 8137056: Move SharedSecrets and interface friends out of sun.misc
chegar
parents: 31682
diff changeset
    58
    private static final JavaIOFileDescriptorAccess fdAccess
e1dca5fe4de3 8137056: Move SharedSecrets and interface friends out of sun.misc
chegar
parents: 31682
diff changeset
    59
        = SharedSecrets.getJavaIOFileDescriptorAccess();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
30899
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
    61
    // Windows platforms support a forcible kill signal.
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
    62
    static final boolean SUPPORTS_NORMAL_TERMINATION = false;
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
    63
7515
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    64
    /**
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    65
     * Open a file for writing. If {@code append} is {@code true} then the file
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    66
     * is opened for atomic append directly and a FileOutputStream constructed
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    67
     * with the resulting handle. This is because a FileOutputStream created
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    68
     * to append to a file does not open the file in a manner that guarantees
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    69
     * that writes by the child process will be atomic.
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    70
     */
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    71
    private static FileOutputStream newFileOutputStream(File f, boolean append)
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    72
        throws IOException
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    73
    {
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    74
        if (append) {
10903
dfb253adb28f 7059259: (process) ProcessBuilder.start permission check should be improved when redirecting output to append
alanb
parents: 7668
diff changeset
    75
            String path = f.getPath();
7515
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    76
            SecurityManager sm = System.getSecurityManager();
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    77
            if (sm != null)
10903
dfb253adb28f 7059259: (process) ProcessBuilder.start permission check should be improved when redirecting output to append
alanb
parents: 7668
diff changeset
    78
                sm.checkWrite(path);
dfb253adb28f 7059259: (process) ProcessBuilder.start permission check should be improved when redirecting output to append
alanb
parents: 7668
diff changeset
    79
            long handle = openForAtomicAppend(path);
7515
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    80
            final FileDescriptor fd = new FileDescriptor();
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    81
            fdAccess.setHandle(fd, handle);
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    82
            return AccessController.doPrivileged(
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    83
                new PrivilegedAction<FileOutputStream>() {
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    84
                    public FileOutputStream run() {
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    85
                        return new FileOutputStream(fd);
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    86
                    }
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    87
                }
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    88
            );
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    89
        } else {
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    90
            return new FileOutputStream(f);
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    91
        }
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    92
    }
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
    93
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
    // System-dependent portion of ProcessBuilder.start()
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
    static Process start(String cmdarray[],
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
                         java.util.Map<String,String> environment,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
                         String dir,
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
    98
                         ProcessBuilder.Redirect[] redirects,
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
                         boolean redirectErrorStream)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
        throws IOException
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
    {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
        String envblock = ProcessEnvironment.toEnvironmentBlock(environment);
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   103
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   104
        FileInputStream  f0 = null;
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   105
        FileOutputStream f1 = null;
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   106
        FileOutputStream f2 = null;
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   107
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   108
        try {
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   109
            long[] stdHandles;
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   110
            if (redirects == null) {
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   111
                stdHandles = new long[] { -1L, -1L, -1L };
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   112
            } else {
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   113
                stdHandles = new long[3];
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   114
33826
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   115
                if (redirects[0] == Redirect.PIPE) {
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   116
                    stdHandles[0] = -1L;
33826
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   117
                } else if (redirects[0] == Redirect.INHERIT) {
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   118
                    stdHandles[0] = fdAccess.getHandle(FileDescriptor.in);
33826
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   119
                } else if (redirects[0] instanceof ProcessBuilder.RedirectPipeImpl) {
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   120
                    stdHandles[0] = fdAccess.getHandle(((ProcessBuilder.RedirectPipeImpl) redirects[0]).getFd());
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   121
                } else {
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   122
                    f0 = new FileInputStream(redirects[0].file());
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   123
                    stdHandles[0] = fdAccess.getHandle(f0.getFD());
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   124
                }
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   125
33826
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   126
                if (redirects[1] == Redirect.PIPE) {
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   127
                    stdHandles[1] = -1L;
33826
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   128
                } else if (redirects[1] == Redirect.INHERIT) {
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   129
                    stdHandles[1] = fdAccess.getHandle(FileDescriptor.out);
33826
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   130
                } else if (redirects[1] instanceof ProcessBuilder.RedirectPipeImpl) {
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   131
                    stdHandles[1] = fdAccess.getHandle(((ProcessBuilder.RedirectPipeImpl) redirects[1]).getFd());
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   132
                } else {
7515
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
   133
                    f1 = newFileOutputStream(redirects[1].file(),
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
   134
                                             redirects[1].append());
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   135
                    stdHandles[1] = fdAccess.getHandle(f1.getFD());
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   136
                }
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   137
33826
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   138
                if (redirects[2] == Redirect.PIPE) {
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   139
                    stdHandles[2] = -1L;
33826
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   140
                } else if (redirects[2] == Redirect.INHERIT) {
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   141
                    stdHandles[2] = fdAccess.getHandle(FileDescriptor.err);
33826
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   142
                } else if (redirects[2] instanceof ProcessBuilder.RedirectPipeImpl) {
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   143
                    stdHandles[2] = fdAccess.getHandle(((ProcessBuilder.RedirectPipeImpl) redirects[2]).getFd());
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   144
                } else {
7515
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
   145
                    f2 = newFileOutputStream(redirects[2].file(),
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
   146
                                             redirects[2].append());
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   147
                    stdHandles[2] = fdAccess.getHandle(f2.getFD());
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   148
                }
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   149
            }
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   150
33826
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   151
            Process p = new ProcessImpl(cmdarray, envblock, dir,
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   152
                                   stdHandles, redirectErrorStream);
33826
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   153
            if (redirects != null) {
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   154
                // Copy the handles's if they are to be redirected to another process
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   155
                if (stdHandles[0] >= 0
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   156
                        && redirects[0] instanceof ProcessBuilder.RedirectPipeImpl) {
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   157
                    fdAccess.setHandle(((ProcessBuilder.RedirectPipeImpl) redirects[0]).getFd(),
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   158
                            stdHandles[0]);
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   159
                }
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   160
                if (stdHandles[1] >= 0
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   161
                        && redirects[1] instanceof ProcessBuilder.RedirectPipeImpl) {
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   162
                    fdAccess.setHandle(((ProcessBuilder.RedirectPipeImpl) redirects[1]).getFd(),
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   163
                            stdHandles[1]);
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   164
                }
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   165
                if (stdHandles[2] >= 0
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   166
                        && redirects[2] instanceof ProcessBuilder.RedirectPipeImpl) {
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   167
                    fdAccess.setHandle(((ProcessBuilder.RedirectPipeImpl) redirects[2]).getFd(),
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   168
                            stdHandles[2]);
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   169
                }
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   170
            }
a9e5f1b8ea57 8132394: (process) ProcessBuilder support for a pipeline of processes
rriggs
parents: 32834
diff changeset
   171
            return p;
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   172
        } finally {
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   173
            // In theory, close() can throw IOException
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   174
            // (although it is rather unlikely to happen here)
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   175
            try { if (f0 != null) f0.close(); }
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   176
            finally {
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   177
                try { if (f1 != null) f1.close(); }
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   178
                finally { if (f2 != null) f2.close(); }
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   179
            }
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   180
        }
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   181
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   183
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   184
    private static class LazyPattern {
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   185
        // Escape-support version:
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   186
        //    "(\")((?:\\\\\\1|.)+?)\\1|([^\\s\"]+)";
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   187
        private static final Pattern PATTERN =
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   188
            Pattern.compile("[^\\s\"]+|\"[^\"]*\"");
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   189
    };
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   190
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   191
    /* Parses the command string parameter into the executable name and
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   192
     * program arguments.
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   193
     *
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   194
     * The command string is broken into tokens. The token separator is a space
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   195
     * or quota character. The space inside quotation is not a token separator.
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   196
     * There are no escape sequences.
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   197
     */
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   198
    private static String[] getTokensFromCommand(String command) {
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   199
        ArrayList<String> matchList = new ArrayList<>(8);
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   200
        Matcher regexMatcher = LazyPattern.PATTERN.matcher(command);
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   201
        while (regexMatcher.find())
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   202
            matchList.add(regexMatcher.group());
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   203
        return matchList.toArray(new String[matchList.size()]);
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   204
    }
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   205
18183
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   206
    private static final int VERIFICATION_CMD_BAT = 0;
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   207
    private static final int VERIFICATION_WIN32 = 1;
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   208
    private static final int VERIFICATION_LEGACY = 2;
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   209
    private static final char ESCAPE_VERIFICATION[][] = {
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   210
        // We guarantee the only command file execution for implicit [cmd.exe] run.
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   211
        //    http://technet.microsoft.com/en-us/library/bb490954.aspx
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   212
        {' ', '\t', '<', '>', '&', '|', '^'},
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   213
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   214
        {' ', '\t', '<', '>'},
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   215
        {' ', '\t'}
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   216
    };
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   217
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   218
    private static String createCommandLine(int verificationType,
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   219
                                     final String executablePath,
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   220
                                     final String cmd[])
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   221
    {
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   222
        StringBuilder cmdbuf = new StringBuilder(80);
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   223
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   224
        cmdbuf.append(executablePath);
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   225
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   226
        for (int i = 1; i < cmd.length; ++i) {
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   227
            cmdbuf.append(' ');
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   228
            String s = cmd[i];
18183
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   229
            if (needsEscaping(verificationType, s)) {
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   230
                cmdbuf.append('"').append(s);
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   231
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   232
                // The code protects the [java.exe] and console command line
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   233
                // parser, that interprets the [\"] combination as an escape
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   234
                // sequence for the ["] char.
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   235
                //     http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   236
                //
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   237
                // If the argument is an FS path, doubling of the tail [\]
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   238
                // char is not a problem for non-console applications.
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   239
                //
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   240
                // The [\"] sequence is not an escape sequence for the [cmd.exe]
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   241
                // command line parser. The case of the [""] tail escape
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   242
                // sequence could not be realized due to the argument validation
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   243
                // procedure.
18183
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   244
                if ((verificationType != VERIFICATION_CMD_BAT) && s.endsWith("\\")) {
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   245
                    cmdbuf.append('\\');
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   246
                }
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   247
                cmdbuf.append('"');
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   248
            } else {
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   249
                cmdbuf.append(s);
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   250
            }
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   251
        }
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   252
        return cmdbuf.toString();
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   253
    }
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   254
16877
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   255
    private static boolean isQuoted(boolean noQuotesInside, String arg,
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   256
            String errorMessage) {
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   257
        int lastPos = arg.length() - 1;
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   258
        if (lastPos >=1 && arg.charAt(0) == '"' && arg.charAt(lastPos) == '"') {
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   259
            // The argument has already been quoted.
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   260
            if (noQuotesInside) {
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   261
                if (arg.indexOf('"', 1) != lastPos) {
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   262
                    // There is ["] inside.
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   263
                    throw new IllegalArgumentException(errorMessage);
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   264
                }
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   265
            }
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   266
            return true;
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   267
        }
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   268
        if (noQuotesInside) {
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   269
            if (arg.indexOf('"') >= 0) {
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   270
                // There is ["] inside.
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   271
                throw new IllegalArgumentException(errorMessage);
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   272
            }
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   273
        }
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   274
        return false;
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   275
    }
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   276
18183
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   277
    private static boolean needsEscaping(int verificationType, String arg) {
16877
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   278
        // Switch off MS heuristic for internal ["].
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   279
        // Please, use the explicit [cmd.exe] call
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   280
        // if you need the internal ["].
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   281
        //    Example: "cmd.exe", "/C", "Extended_MS_Syntax"
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   282
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   283
        // For [.exe] or [.com] file the unpaired/internal ["]
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   284
        // in the argument is not a problem.
18183
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   285
        boolean argIsQuoted = isQuoted(
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   286
            (verificationType == VERIFICATION_CMD_BAT),
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   287
            arg, "Argument has embedded quote, use the explicit CMD.EXE call.");
16877
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   288
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   289
        if (!argIsQuoted) {
18183
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   290
            char testEscape[] = ESCAPE_VERIFICATION[verificationType];
16877
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   291
            for (int i = 0; i < testEscape.length; ++i) {
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   292
                if (arg.indexOf(testEscape[i]) >= 0) {
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   293
                    return true;
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   294
                }
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   295
            }
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   296
        }
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   297
        return false;
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   298
    }
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   299
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   300
    private static String getExecutablePath(String path)
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   301
        throws IOException
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   302
    {
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   303
        boolean pathIsQuoted = isQuoted(true, path,
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   304
                "Executable name has embedded quote, split the arguments");
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   305
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   306
        // Win32 CreateProcess requires path to be normalized
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   307
        File fileToRun = new File(pathIsQuoted
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   308
            ? path.substring(1, path.length() - 1)
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   309
            : path);
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   310
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   311
        // From the [CreateProcess] function documentation:
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   312
        //
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   313
        // "If the file name does not contain an extension, .exe is appended.
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   314
        // Therefore, if the file name extension is .com, this parameter
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   315
        // must include the .com extension. If the file name ends in
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   316
        // a period (.) with no extension, or if the file name contains a path,
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   317
        // .exe is not appended."
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   318
        //
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   319
        // "If the file name !does not contain a directory path!,
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   320
        // the system searches for the executable file in the following
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   321
        // sequence:..."
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   322
        //
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   323
        // In practice ANY non-existent path is extended by [.exe] extension
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   324
        // in the [CreateProcess] funcion with the only exception:
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   325
        // the path ends by (.)
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   326
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   327
        return fileToRun.getPath();
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   328
    }
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   329
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   330
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   331
    private boolean isShellFile(String executablePath) {
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   332
        String upPath = executablePath.toUpperCase();
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   333
        return (upPath.endsWith(".CMD") || upPath.endsWith(".BAT"));
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   334
    }
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   335
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   336
    private String quoteString(String arg) {
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   337
        StringBuilder argbuf = new StringBuilder(arg.length() + 2);
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   338
        return argbuf.append('"').append(arg).append('"').toString();
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   339
    }
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   340
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   341
30899
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   342
    private final long handle;
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   343
    private final ProcessHandle processHandle;
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   344
    private OutputStream stdin_stream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   345
    private InputStream stdout_stream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   346
    private InputStream stderr_stream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   347
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   348
    private ProcessImpl(String cmd[],
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   349
                        final String envblock,
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   350
                        final String path,
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   351
                        final long[] stdHandles,
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   352
                        final boolean redirectErrorStream)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   353
        throws IOException
90ce3da70b43 Initial load
duke
parents:
diff changeset
   354
    {
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   355
        String cmdstr;
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   356
        SecurityManager security = System.getSecurityManager();
18183
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   357
        boolean allowAmbiguousCommands = false;
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   358
        if (security == null) {
18183
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   359
            allowAmbiguousCommands = true;
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   360
            String value = System.getProperty("jdk.lang.Process.allowAmbiguousCommands");
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   361
            if (value != null)
18183
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   362
                allowAmbiguousCommands = !"false".equalsIgnoreCase(value);
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   363
        }
18183
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   364
        if (allowAmbiguousCommands) {
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   365
            // Legacy mode.
16877
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   366
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   367
            // Normalize path if possible.
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   368
            String executablePath = new File(cmd[0]).getPath();
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   369
18183
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   370
            // No worry about internal, unpaired ["], and redirection/piping.
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   371
            if (needsEscaping(VERIFICATION_LEGACY, executablePath) )
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   372
                executablePath = quoteString(executablePath);
16877
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   373
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   374
            cmdstr = createCommandLine(
18183
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   375
                //legacy mode doesn't worry about extended verification
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   376
                VERIFICATION_LEGACY,
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   377
                executablePath,
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   378
                cmd);
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   379
        } else {
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   380
            String executablePath;
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   381
            try {
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   382
                executablePath = getExecutablePath(cmd[0]);
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   383
            } catch (IllegalArgumentException e) {
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   384
                // Workaround for the calls like
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   385
                // Runtime.getRuntime().exec("\"C:\\Program Files\\foo\" bar")
16877
d12c06e6e2ba 8005942: (process) Improved Runtime.exec
uta
parents: 13149
diff changeset
   386
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   387
                // No chance to avoid CMD/BAT injection, except to do the work
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   388
                // right from the beginning. Otherwise we have too many corner
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   389
                // cases from
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   390
                //    Runtime.getRuntime().exec(String[] cmd [, ...])
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   391
                // calls with internal ["] and escape sequences.
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   392
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   393
                // Restore original command line.
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   394
                StringBuilder join = new StringBuilder();
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   395
                // terminal space in command line is ok
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   396
                for (String s : cmd)
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   397
                    join.append(s).append(' ');
16885
d54b22d3b306 8009463: Regression test test\java\lang\Runtime\exec\ArgWithSpaceAndFinalBackslash.java failing.
uta
parents: 16877
diff changeset
   398
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   399
                // Parse the command line again.
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   400
                cmd = getTokensFromCommand(join.toString());
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   401
                executablePath = getExecutablePath(cmd[0]);
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   402
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   403
                // Check new executable name once more
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   404
                if (security != null)
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   405
                    security.checkExec(executablePath);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   406
            }
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   407
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   408
            // Quotation protects from interpretation of the [path] argument as
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   409
            // start of longer path with spaces. Quotation has no influence to
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   410
            // [.exe] extension heuristic.
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   411
            cmdstr = createCommandLine(
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   412
                    // We need the extended verification procedure for CMD files.
18183
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   413
                    isShellFile(executablePath)
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   414
                        ? VERIFICATION_CMD_BAT
9749983601cf 8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents: 17467
diff changeset
   415
                        : VERIFICATION_WIN32,
17467
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   416
                    quoteString(executablePath),
374c1cceefff 8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents: 16901
diff changeset
   417
                    cmd);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   418
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   419
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   420
        handle = create(cmdstr, envblock, path,
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   421
                        stdHandles, redirectErrorStream);
34942
4b462ee18ed9 8146028: Common Cleaner for finalization replacements in OpenJDK
rriggs
parents: 33826
diff changeset
   422
        // Register a cleaning function to close the handle
4b462ee18ed9 8146028: Common Cleaner for finalization replacements in OpenJDK
rriggs
parents: 33826
diff changeset
   423
        final long local_handle = handle;    // local to prevent capture of this
4b462ee18ed9 8146028: Common Cleaner for finalization replacements in OpenJDK
rriggs
parents: 33826
diff changeset
   424
        CleanerFactory.cleaner().register(this, () -> closeHandle(local_handle));
4b462ee18ed9 8146028: Common Cleaner for finalization replacements in OpenJDK
rriggs
parents: 33826
diff changeset
   425
31682
c19dcf5e0b6d 8078099: (process) ProcessHandle should uniquely identify processes
rriggs
parents: 30899
diff changeset
   426
        processHandle = ProcessHandleImpl.getInternal(getProcessId0(handle));
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   427
90ce3da70b43 Initial load
duke
parents:
diff changeset
   428
        java.security.AccessController.doPrivileged(
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   429
        new java.security.PrivilegedAction<Void>() {
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   430
        public Void run() {
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   431
            if (stdHandles[0] == -1L)
5787
a0af7b8e80ed 6960898: Regression due to src/share/classes/java/lang/ProcessBuilder.java changes
martin
parents: 5506
diff changeset
   432
                stdin_stream = ProcessBuilder.NullOutputStream.INSTANCE;
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   433
            else {
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   434
                FileDescriptor stdin_fd = new FileDescriptor();
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   435
                fdAccess.setHandle(stdin_fd, stdHandles[0]);
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   436
                stdin_stream = new BufferedOutputStream(
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   437
                    new FileOutputStream(stdin_fd));
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   438
            }
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   439
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   440
            if (stdHandles[1] == -1L)
5787
a0af7b8e80ed 6960898: Regression due to src/share/classes/java/lang/ProcessBuilder.java changes
martin
parents: 5506
diff changeset
   441
                stdout_stream = ProcessBuilder.NullInputStream.INSTANCE;
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   442
            else {
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   443
                FileDescriptor stdout_fd = new FileDescriptor();
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   444
                fdAccess.setHandle(stdout_fd, stdHandles[1]);
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   445
                stdout_stream = new BufferedInputStream(
39061
0a7abfc4f4b0 8155808: Process.getInputStream().skip() method is faulty
rriggs
parents: 34942
diff changeset
   446
                    new PipeInputStream(stdout_fd));
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   447
            }
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   448
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   449
            if (stdHandles[2] == -1L)
5787
a0af7b8e80ed 6960898: Regression due to src/share/classes/java/lang/ProcessBuilder.java changes
martin
parents: 5506
diff changeset
   450
                stderr_stream = ProcessBuilder.NullInputStream.INSTANCE;
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   451
            else {
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   452
                FileDescriptor stderr_fd = new FileDescriptor();
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   453
                fdAccess.setHandle(stderr_fd, stdHandles[2]);
39061
0a7abfc4f4b0 8155808: Process.getInputStream().skip() method is faulty
rriggs
parents: 34942
diff changeset
   454
                stderr_stream = new PipeInputStream(stderr_fd);
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   455
            }
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   456
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   457
            return null; }});
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   458
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   459
90ce3da70b43 Initial load
duke
parents:
diff changeset
   460
    public OutputStream getOutputStream() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   461
        return stdin_stream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   462
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   463
90ce3da70b43 Initial load
duke
parents:
diff changeset
   464
    public InputStream getInputStream() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   465
        return stdout_stream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   466
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   467
90ce3da70b43 Initial load
duke
parents:
diff changeset
   468
    public InputStream getErrorStream() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   469
        return stderr_stream;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   470
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   471
90ce3da70b43 Initial load
duke
parents:
diff changeset
   472
    private static final int STILL_ACTIVE = getStillActive();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   473
    private static native int getStillActive();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   474
90ce3da70b43 Initial load
duke
parents:
diff changeset
   475
    public int exitValue() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   476
        int exitCode = getExitCodeProcess(handle);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   477
        if (exitCode == STILL_ACTIVE)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   478
            throw new IllegalThreadStateException("process has not exited");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   479
        return exitCode;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   480
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   481
    private static native int getExitCodeProcess(long handle);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   482
90ce3da70b43 Initial load
duke
parents:
diff changeset
   483
    public int waitFor() throws InterruptedException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   484
        waitForInterruptibly(handle);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   485
        if (Thread.interrupted())
90ce3da70b43 Initial load
duke
parents:
diff changeset
   486
            throw new InterruptedException();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   487
        return exitValue();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   488
    }
13149
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   489
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   490
    private static native void waitForInterruptibly(long handle);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   491
13149
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   492
    @Override
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   493
    public boolean waitFor(long timeout, TimeUnit unit)
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   494
        throws InterruptedException
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   495
    {
29604
f3e313c492ba 8067796: (process) Process.waitFor(timeout, unit) doesn't throw NPE if timeout is less than, or equal to zero when unit == null
rriggs
parents: 27732
diff changeset
   496
        long remainingNanos = unit.toNanos(timeout);    // throw NPE before other conditions
13149
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   497
        if (getExitCodeProcess(handle) != STILL_ACTIVE) return true;
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   498
        if (timeout <= 0) return false;
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   499
27732
31d7da6e79bf 8064932: java/lang/ProcessBuilder/Basic.java: waitFor didn't take long enough
rriggs
parents: 25859
diff changeset
   500
        long deadline = System.nanoTime() + remainingNanos ;
31d7da6e79bf 8064932: java/lang/ProcessBuilder/Basic.java: waitFor didn't take long enough
rriggs
parents: 25859
diff changeset
   501
        do {
31d7da6e79bf 8064932: java/lang/ProcessBuilder/Basic.java: waitFor didn't take long enough
rriggs
parents: 25859
diff changeset
   502
            // Round up to next millisecond
31d7da6e79bf 8064932: java/lang/ProcessBuilder/Basic.java: waitFor didn't take long enough
rriggs
parents: 25859
diff changeset
   503
            long msTimeout = TimeUnit.NANOSECONDS.toMillis(remainingNanos + 999_999L);
31d7da6e79bf 8064932: java/lang/ProcessBuilder/Basic.java: waitFor didn't take long enough
rriggs
parents: 25859
diff changeset
   504
            waitForTimeoutInterruptibly(handle, msTimeout);
31d7da6e79bf 8064932: java/lang/ProcessBuilder/Basic.java: waitFor didn't take long enough
rriggs
parents: 25859
diff changeset
   505
            if (Thread.interrupted())
31d7da6e79bf 8064932: java/lang/ProcessBuilder/Basic.java: waitFor didn't take long enough
rriggs
parents: 25859
diff changeset
   506
                throw new InterruptedException();
31d7da6e79bf 8064932: java/lang/ProcessBuilder/Basic.java: waitFor didn't take long enough
rriggs
parents: 25859
diff changeset
   507
            if (getExitCodeProcess(handle) != STILL_ACTIVE) {
31d7da6e79bf 8064932: java/lang/ProcessBuilder/Basic.java: waitFor didn't take long enough
rriggs
parents: 25859
diff changeset
   508
                return true;
31d7da6e79bf 8064932: java/lang/ProcessBuilder/Basic.java: waitFor didn't take long enough
rriggs
parents: 25859
diff changeset
   509
            }
31d7da6e79bf 8064932: java/lang/ProcessBuilder/Basic.java: waitFor didn't take long enough
rriggs
parents: 25859
diff changeset
   510
            remainingNanos = deadline - System.nanoTime();
31d7da6e79bf 8064932: java/lang/ProcessBuilder/Basic.java: waitFor didn't take long enough
rriggs
parents: 25859
diff changeset
   511
        } while (remainingNanos > 0);
31d7da6e79bf 8064932: java/lang/ProcessBuilder/Basic.java: waitFor didn't take long enough
rriggs
parents: 25859
diff changeset
   512
13149
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   513
        return (getExitCodeProcess(handle) != STILL_ACTIVE);
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   514
    }
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   515
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   516
    private static native void waitForTimeoutInterruptibly(
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   517
        long handle, long timeout);
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   518
30899
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   519
    @Override
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   520
    public void destroy() {
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   521
        terminateProcess(handle);
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   522
    }
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   523
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   524
    @Override
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   525
    public CompletableFuture<Process> onExit() {
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   526
        return ProcessHandleImpl.completion(getPid(), false)
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   527
                .handleAsync((exitStatus, unusedThrowable) -> this);
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   528
    }
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   529
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   530
    @Override
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   531
    public ProcessHandle toHandle() {
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   532
        SecurityManager sm = System.getSecurityManager();
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   533
        if (sm != null) {
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   534
            sm.checkPermission(new RuntimePermission("manageProcess"));
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   535
        }
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   536
        return processHandle;
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   537
    }
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   538
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   539
    @Override
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   540
    public boolean supportsNormalTermination() {
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   541
        return ProcessImpl.SUPPORTS_NORMAL_TERMINATION;
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   542
    }
13149
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   543
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   544
    @Override
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   545
    public Process destroyForcibly() {
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   546
        destroy();
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   547
        return this;
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   548
    }
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   549
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   550
    private static native void terminateProcess(long handle);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   551
13149
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   552
    @Override
24577
b3bf9c82a050 8003488: (process) Provide Process.getPid()
rriggs
parents: 23010
diff changeset
   553
    public long getPid() {
30899
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   554
        return processHandle.getPid();
24577
b3bf9c82a050 8003488: (process) Provide Process.getPid()
rriggs
parents: 23010
diff changeset
   555
    }
b3bf9c82a050 8003488: (process) Provide Process.getPid()
rriggs
parents: 23010
diff changeset
   556
b3bf9c82a050 8003488: (process) Provide Process.getPid()
rriggs
parents: 23010
diff changeset
   557
    private static native int getProcessId0(long handle);
b3bf9c82a050 8003488: (process) Provide Process.getPid()
rriggs
parents: 23010
diff changeset
   558
b3bf9c82a050 8003488: (process) Provide Process.getPid()
rriggs
parents: 23010
diff changeset
   559
    @Override
13149
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   560
    public boolean isAlive() {
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   561
        return isProcessAlive(handle);
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   562
    }
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   563
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   564
    private static native boolean isProcessAlive(long handle);
27d52f97a5cc 4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents: 10903
diff changeset
   565
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   566
    /**
40738
86952e676976 8155102: (Process) Process.toString could include pid, isAlive, exitStatus
rriggs
parents: 39061
diff changeset
   567
     * The {@code toString} method returns a string consisting of
86952e676976 8155102: (Process) Process.toString could include pid, isAlive, exitStatus
rriggs
parents: 39061
diff changeset
   568
     * the native process ID of the process and the exit value of the process.
86952e676976 8155102: (Process) Process.toString could include pid, isAlive, exitStatus
rriggs
parents: 39061
diff changeset
   569
     *
86952e676976 8155102: (Process) Process.toString could include pid, isAlive, exitStatus
rriggs
parents: 39061
diff changeset
   570
     * @return a string representation of the object.
86952e676976 8155102: (Process) Process.toString could include pid, isAlive, exitStatus
rriggs
parents: 39061
diff changeset
   571
     */
86952e676976 8155102: (Process) Process.toString could include pid, isAlive, exitStatus
rriggs
parents: 39061
diff changeset
   572
    @Override
86952e676976 8155102: (Process) Process.toString could include pid, isAlive, exitStatus
rriggs
parents: 39061
diff changeset
   573
    public String toString() {
86952e676976 8155102: (Process) Process.toString could include pid, isAlive, exitStatus
rriggs
parents: 39061
diff changeset
   574
        int exitCode = getExitCodeProcess(handle);
86952e676976 8155102: (Process) Process.toString could include pid, isAlive, exitStatus
rriggs
parents: 39061
diff changeset
   575
        return new StringBuilder("Process[pid=").append(getPid())
86952e676976 8155102: (Process) Process.toString could include pid, isAlive, exitStatus
rriggs
parents: 39061
diff changeset
   576
                .append(", exitValue=").append(exitCode == STILL_ACTIVE ? "\"not exited\"" : exitCode)
86952e676976 8155102: (Process) Process.toString could include pid, isAlive, exitStatus
rriggs
parents: 39061
diff changeset
   577
                .append("]").toString();
86952e676976 8155102: (Process) Process.toString could include pid, isAlive, exitStatus
rriggs
parents: 39061
diff changeset
   578
    }
86952e676976 8155102: (Process) Process.toString could include pid, isAlive, exitStatus
rriggs
parents: 39061
diff changeset
   579
86952e676976 8155102: (Process) Process.toString could include pid, isAlive, exitStatus
rriggs
parents: 39061
diff changeset
   580
    /**
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   581
     * Create a process using the win32 function CreateProcess.
19372
e404c834f1cd 7147084: (process) appA hangs when read output stream of appB which starts appC that runs forever
uta
parents: 18183
diff changeset
   582
     * The method is synchronized due to MS kb315939 problem.
e404c834f1cd 7147084: (process) appA hangs when read output stream of appB which starts appC that runs forever
uta
parents: 18183
diff changeset
   583
     * All native handles should restore the inherit flag at the end of call.
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   584
     *
19372
e404c834f1cd 7147084: (process) appA hangs when read output stream of appB which starts appC that runs forever
uta
parents: 18183
diff changeset
   585
     * @param cmdstr the Windows command line
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   586
     * @param envblock NUL-separated, double-NUL-terminated list of
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   587
     *        environment strings in VAR=VALUE form
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   588
     * @param dir the working directory of the process, or null if
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   589
     *        inheriting the current directory from the parent process
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   590
     * @param stdHandles array of windows HANDLEs.  Indexes 0, 1, and
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   591
     *        2 correspond to standard input, standard output and
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   592
     *        standard error, respectively.  On input, a value of -1
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   593
     *        means to create a pipe to connect child and parent
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   594
     *        processes.  On output, a value which is not -1 is the
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   595
     *        parent pipe handle corresponding to the pipe which has
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   596
     *        been created.  An element of this array is -1 on input
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   597
     *        if and only if it is <em>not</em> -1 on output.
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   598
     * @param redirectErrorStream redirectErrorStream attribute
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   599
     * @return the native subprocess HANDLE returned by CreateProcess
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   600
     */
19372
e404c834f1cd 7147084: (process) appA hangs when read output stream of appB which starts appC that runs forever
uta
parents: 18183
diff changeset
   601
    private static synchronized native long create(String cmdstr,
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   602
                                      String envblock,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   603
                                      String dir,
48
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   604
                                      long[] stdHandles,
dc5744ca15ea 4960438: (process) Need IO redirection API for subprocesses
martin
parents: 2
diff changeset
   605
                                      boolean redirectErrorStream)
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   606
        throws IOException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   607
7515
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
   608
    /**
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
   609
     * Opens a file for atomic append. The file is created if it doesn't
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
   610
     * already exist.
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
   611
     *
30899
d2408e757489 8077350: JEP 102 Process API Updates Implementation
rriggs
parents: 29604
diff changeset
   612
     * @param path the file to open or create
7515
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
   613
     * @return the native HANDLE
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
   614
     */
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
   615
    private static native long openForAtomicAppend(String path)
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
   616
        throws IOException;
43202796198e 6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents: 5787
diff changeset
   617
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   618
    private static native boolean closeHandle(long handle);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   619
}