author | chegar |
Sun, 17 Aug 2014 15:54:13 +0100 | |
changeset 25859 | 3317bb8137f4 |
parent 24577 | jdk/src/windows/classes/java/lang/ProcessImpl.java@b3bf9c82a050 |
child 27732 | 31d7da6e79bf |
permissions | -rw-r--r-- |
2 | 1 |
/* |
23010
6dadb192ad81
8029235: Update copyright year to match last edit in jdk8 jdk repository for 2013
lana
parents:
19372
diff
changeset
|
2 |
* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. |
2 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 10 |
* |
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
5506 | 21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
2 | 24 |
*/ |
25 |
||
26 |
package java.lang; |
|
27 |
||
24577 | 28 |
import java.io.BufferedInputStream; |
29 |
import java.io.BufferedOutputStream; |
|
30 |
import java.io.File; |
|
31 |
import java.io.FileDescriptor; |
|
32 |
import java.io.FileInputStream; |
|
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; |
13149
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
41 |
import java.util.concurrent.TimeUnit; |
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
42 |
import java.util.regex.Matcher; |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
43 |
import java.util.regex.Pattern; |
2 | 44 |
|
45 |
/* This class is for the exclusive use of ProcessBuilder.start() to |
|
46 |
* create new processes. |
|
47 |
* |
|
48 |
* @author Martin Buchholz |
|
49 |
* @since 1.5 |
|
50 |
*/ |
|
51 |
||
52 |
final class ProcessImpl extends Process { |
|
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
53 |
private static final sun.misc.JavaIOFileDescriptorAccess fdAccess |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
54 |
= sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess(); |
2 | 55 |
|
7515
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
56 |
/** |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
57 |
* 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
|
58 |
* 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
|
59 |
* 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
|
60 |
* 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
|
61 |
* 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
|
62 |
*/ |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
63 |
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
|
64 |
throws IOException |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
65 |
{ |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
66 |
if (append) { |
10903
dfb253adb28f
7059259: (process) ProcessBuilder.start permission check should be improved when redirecting output to append
alanb
parents:
7668
diff
changeset
|
67 |
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
|
68 |
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
|
69 |
if (sm != null) |
10903
dfb253adb28f
7059259: (process) ProcessBuilder.start permission check should be improved when redirecting output to append
alanb
parents:
7668
diff
changeset
|
70 |
sm.checkWrite(path); |
dfb253adb28f
7059259: (process) ProcessBuilder.start permission check should be improved when redirecting output to append
alanb
parents:
7668
diff
changeset
|
71 |
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
|
72 |
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
|
73 |
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
|
74 |
return AccessController.doPrivileged( |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
75 |
new PrivilegedAction<FileOutputStream>() { |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
76 |
public FileOutputStream run() { |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
77 |
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
|
78 |
} |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
79 |
} |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
80 |
); |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
81 |
} else { |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
82 |
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
|
83 |
} |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
84 |
} |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
85 |
|
2 | 86 |
// System-dependent portion of ProcessBuilder.start() |
87 |
static Process start(String cmdarray[], |
|
88 |
java.util.Map<String,String> environment, |
|
89 |
String dir, |
|
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
90 |
ProcessBuilder.Redirect[] redirects, |
2 | 91 |
boolean redirectErrorStream) |
92 |
throws IOException |
|
93 |
{ |
|
94 |
String envblock = ProcessEnvironment.toEnvironmentBlock(environment); |
|
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
95 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
96 |
FileInputStream f0 = null; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
97 |
FileOutputStream f1 = null; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
98 |
FileOutputStream f2 = null; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
99 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
100 |
try { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
101 |
long[] stdHandles; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
102 |
if (redirects == null) { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
103 |
stdHandles = new long[] { -1L, -1L, -1L }; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
104 |
} else { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
105 |
stdHandles = new long[3]; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
106 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
107 |
if (redirects[0] == Redirect.PIPE) |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
108 |
stdHandles[0] = -1L; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
109 |
else if (redirects[0] == Redirect.INHERIT) |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
110 |
stdHandles[0] = fdAccess.getHandle(FileDescriptor.in); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
111 |
else { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
112 |
f0 = new FileInputStream(redirects[0].file()); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
113 |
stdHandles[0] = fdAccess.getHandle(f0.getFD()); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
114 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
115 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
116 |
if (redirects[1] == Redirect.PIPE) |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
117 |
stdHandles[1] = -1L; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
118 |
else if (redirects[1] == Redirect.INHERIT) |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
119 |
stdHandles[1] = fdAccess.getHandle(FileDescriptor.out); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
120 |
else { |
7515
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
121 |
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
|
122 |
redirects[1].append()); |
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
123 |
stdHandles[1] = fdAccess.getHandle(f1.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 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
126 |
if (redirects[2] == Redirect.PIPE) |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
127 |
stdHandles[2] = -1L; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
128 |
else if (redirects[2] == Redirect.INHERIT) |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
129 |
stdHandles[2] = fdAccess.getHandle(FileDescriptor.err); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
130 |
else { |
7515
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
131 |
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
|
132 |
redirects[2].append()); |
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
133 |
stdHandles[2] = fdAccess.getHandle(f2.getFD()); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
134 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
135 |
} |
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 |
return new ProcessImpl(cmdarray, envblock, dir, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
138 |
stdHandles, redirectErrorStream); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
139 |
} finally { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
140 |
// In theory, close() can throw IOException |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
141 |
// (although it is rather unlikely to happen here) |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
142 |
try { if (f0 != null) f0.close(); } |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
143 |
finally { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
144 |
try { if (f1 != null) f1.close(); } |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
145 |
finally { if (f2 != null) f2.close(); } |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
146 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
147 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
148 |
|
2 | 149 |
} |
150 |
||
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
151 |
private static class LazyPattern { |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
152 |
// Escape-support version: |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
153 |
// "(\")((?:\\\\\\1|.)+?)\\1|([^\\s\"]+)"; |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
154 |
private static final Pattern PATTERN = |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
155 |
Pattern.compile("[^\\s\"]+|\"[^\"]*\""); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
156 |
}; |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
157 |
|
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
158 |
/* 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
|
159 |
* program arguments. |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
160 |
* |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
161 |
* 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
|
162 |
* 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
|
163 |
* There are no escape sequences. |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
164 |
*/ |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
165 |
private static String[] getTokensFromCommand(String command) { |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
166 |
ArrayList<String> matchList = new ArrayList<>(8); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
167 |
Matcher regexMatcher = LazyPattern.PATTERN.matcher(command); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
168 |
while (regexMatcher.find()) |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
169 |
matchList.add(regexMatcher.group()); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
170 |
return matchList.toArray(new String[matchList.size()]); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
171 |
} |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
172 |
|
18183
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
173 |
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
|
174 |
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
|
175 |
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
|
176 |
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
|
177 |
// 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
|
178 |
// 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
|
179 |
{' ', '\t', '<', '>', '&', '|', '^'}, |
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
180 |
|
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
181 |
{' ', '\t', '<', '>'}, |
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
182 |
{' ', '\t'} |
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
183 |
}; |
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
184 |
|
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
185 |
private static String createCommandLine(int verificationType, |
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
186 |
final String executablePath, |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
187 |
final String cmd[]) |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
188 |
{ |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
189 |
StringBuilder cmdbuf = new StringBuilder(80); |
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 |
cmdbuf.append(executablePath); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
192 |
|
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
193 |
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
|
194 |
cmdbuf.append(' '); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
195 |
String s = cmd[i]; |
18183
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
196 |
if (needsEscaping(verificationType, s)) { |
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
197 |
cmdbuf.append('"').append(s); |
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
198 |
|
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
199 |
// 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
|
200 |
// 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
|
201 |
// sequence for the ["] char. |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
202 |
// 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
|
203 |
// |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
204 |
// 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
|
205 |
// 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
|
206 |
// |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
207 |
// 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
|
208 |
// 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
|
209 |
// 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
|
210 |
// procedure. |
18183
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
211 |
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
|
212 |
cmdbuf.append('\\'); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
213 |
} |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
214 |
cmdbuf.append('"'); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
215 |
} else { |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
216 |
cmdbuf.append(s); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
217 |
} |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
218 |
} |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
219 |
return cmdbuf.toString(); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
220 |
} |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
221 |
|
16877 | 222 |
private static boolean isQuoted(boolean noQuotesInside, String arg, |
223 |
String errorMessage) { |
|
224 |
int lastPos = arg.length() - 1; |
|
225 |
if (lastPos >=1 && arg.charAt(0) == '"' && arg.charAt(lastPos) == '"') { |
|
226 |
// The argument has already been quoted. |
|
227 |
if (noQuotesInside) { |
|
228 |
if (arg.indexOf('"', 1) != lastPos) { |
|
229 |
// There is ["] inside. |
|
230 |
throw new IllegalArgumentException(errorMessage); |
|
231 |
} |
|
232 |
} |
|
233 |
return true; |
|
234 |
} |
|
235 |
if (noQuotesInside) { |
|
236 |
if (arg.indexOf('"') >= 0) { |
|
237 |
// There is ["] inside. |
|
238 |
throw new IllegalArgumentException(errorMessage); |
|
239 |
} |
|
240 |
} |
|
241 |
return false; |
|
242 |
} |
|
243 |
||
18183
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
244 |
private static boolean needsEscaping(int verificationType, String arg) { |
16877 | 245 |
// Switch off MS heuristic for internal ["]. |
246 |
// Please, use the explicit [cmd.exe] call |
|
247 |
// if you need the internal ["]. |
|
248 |
// Example: "cmd.exe", "/C", "Extended_MS_Syntax" |
|
249 |
||
250 |
// For [.exe] or [.com] file the unpaired/internal ["] |
|
251 |
// 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
|
252 |
boolean argIsQuoted = isQuoted( |
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
253 |
(verificationType == VERIFICATION_CMD_BAT), |
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
254 |
arg, "Argument has embedded quote, use the explicit CMD.EXE call."); |
16877 | 255 |
|
256 |
if (!argIsQuoted) { |
|
18183
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
257 |
char testEscape[] = ESCAPE_VERIFICATION[verificationType]; |
16877 | 258 |
for (int i = 0; i < testEscape.length; ++i) { |
259 |
if (arg.indexOf(testEscape[i]) >= 0) { |
|
260 |
return true; |
|
261 |
} |
|
262 |
} |
|
263 |
} |
|
264 |
return false; |
|
265 |
} |
|
266 |
||
267 |
private static String getExecutablePath(String path) |
|
268 |
throws IOException |
|
269 |
{ |
|
270 |
boolean pathIsQuoted = isQuoted(true, path, |
|
271 |
"Executable name has embedded quote, split the arguments"); |
|
272 |
||
273 |
// Win32 CreateProcess requires path to be normalized |
|
274 |
File fileToRun = new File(pathIsQuoted |
|
275 |
? path.substring(1, path.length() - 1) |
|
276 |
: path); |
|
277 |
||
278 |
// From the [CreateProcess] function documentation: |
|
279 |
// |
|
280 |
// "If the file name does not contain an extension, .exe is appended. |
|
281 |
// Therefore, if the file name extension is .com, this parameter |
|
282 |
// must include the .com extension. If the file name ends in |
|
283 |
// a period (.) with no extension, or if the file name contains a path, |
|
284 |
// .exe is not appended." |
|
285 |
// |
|
286 |
// "If the file name !does not contain a directory path!, |
|
287 |
// the system searches for the executable file in the following |
|
288 |
// sequence:..." |
|
289 |
// |
|
290 |
// In practice ANY non-existent path is extended by [.exe] extension |
|
291 |
// in the [CreateProcess] funcion with the only exception: |
|
292 |
// the path ends by (.) |
|
293 |
||
294 |
return fileToRun.getPath(); |
|
295 |
} |
|
296 |
||
297 |
||
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
298 |
private boolean isShellFile(String executablePath) { |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
299 |
String upPath = executablePath.toUpperCase(); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
300 |
return (upPath.endsWith(".CMD") || upPath.endsWith(".BAT")); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
301 |
} |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
302 |
|
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
303 |
private String quoteString(String arg) { |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
304 |
StringBuilder argbuf = new StringBuilder(arg.length() + 2); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
305 |
return argbuf.append('"').append(arg).append('"').toString(); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
306 |
} |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
307 |
|
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
308 |
|
2 | 309 |
private long handle = 0; |
310 |
private OutputStream stdin_stream; |
|
311 |
private InputStream stdout_stream; |
|
312 |
private InputStream stderr_stream; |
|
313 |
||
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
314 |
private ProcessImpl(String cmd[], |
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
315 |
final String envblock, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
316 |
final String path, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
317 |
final long[] stdHandles, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
318 |
final boolean redirectErrorStream) |
2 | 319 |
throws IOException |
320 |
{ |
|
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
321 |
String cmdstr; |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
322 |
SecurityManager security = System.getSecurityManager(); |
18183
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
323 |
boolean allowAmbiguousCommands = false; |
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
324 |
if (security == null) { |
18183
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
325 |
allowAmbiguousCommands = true; |
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
326 |
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
|
327 |
if (value != null) |
18183
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
328 |
allowAmbiguousCommands = !"false".equalsIgnoreCase(value); |
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
329 |
} |
18183
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
330 |
if (allowAmbiguousCommands) { |
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
331 |
// Legacy mode. |
16877 | 332 |
|
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
333 |
// Normalize path if possible. |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
334 |
String executablePath = new File(cmd[0]).getPath(); |
2 | 335 |
|
18183
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
336 |
// 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
|
337 |
if (needsEscaping(VERIFICATION_LEGACY, executablePath) ) |
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
338 |
executablePath = quoteString(executablePath); |
16877 | 339 |
|
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
340 |
cmdstr = createCommandLine( |
18183
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
341 |
//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
|
342 |
VERIFICATION_LEGACY, |
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
343 |
executablePath, |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
344 |
cmd); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
345 |
} else { |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
346 |
String executablePath; |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
347 |
try { |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
348 |
executablePath = getExecutablePath(cmd[0]); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
349 |
} catch (IllegalArgumentException e) { |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
350 |
// Workaround for the calls like |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
351 |
// Runtime.getRuntime().exec("\"C:\\Program Files\\foo\" bar") |
16877 | 352 |
|
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
353 |
// 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
|
354 |
// 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
|
355 |
// cases from |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
356 |
// Runtime.getRuntime().exec(String[] cmd [, ...]) |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
357 |
// calls with internal ["] and escape sequences. |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
358 |
|
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
359 |
// Restore original command line. |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
360 |
StringBuilder join = new StringBuilder(); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
361 |
// terminal space in command line is ok |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
362 |
for (String s : cmd) |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
363 |
join.append(s).append(' '); |
16885
d54b22d3b306
8009463: Regression test test\java\lang\Runtime\exec\ArgWithSpaceAndFinalBackslash.java failing.
uta
parents:
16877
diff
changeset
|
364 |
|
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
365 |
// Parse the command line again. |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
366 |
cmd = getTokensFromCommand(join.toString()); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
367 |
executablePath = getExecutablePath(cmd[0]); |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
368 |
|
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
369 |
// Check new executable name once more |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
370 |
if (security != null) |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
371 |
security.checkExec(executablePath); |
2 | 372 |
} |
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
373 |
|
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
374 |
// 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
|
375 |
// 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
|
376 |
// [.exe] extension heuristic. |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
377 |
cmdstr = createCommandLine( |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
378 |
// 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
|
379 |
isShellFile(executablePath) |
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
380 |
? VERIFICATION_CMD_BAT |
9749983601cf
8016046: (process) Strict validation of input should be security manager case only [win].
uta
parents:
17467
diff
changeset
|
381 |
: VERIFICATION_WIN32, |
17467
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
382 |
quoteString(executablePath), |
374c1cceefff
8012453: (process) Runtime.exec(String) fails if command contains spaces [win]
uta
parents:
16901
diff
changeset
|
383 |
cmd); |
2 | 384 |
} |
385 |
||
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
386 |
handle = create(cmdstr, envblock, path, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
387 |
stdHandles, redirectErrorStream); |
2 | 388 |
|
389 |
java.security.AccessController.doPrivileged( |
|
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
390 |
new java.security.PrivilegedAction<Void>() { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
391 |
public Void run() { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
392 |
if (stdHandles[0] == -1L) |
5787
a0af7b8e80ed
6960898: Regression due to src/share/classes/java/lang/ProcessBuilder.java changes
martin
parents:
5506
diff
changeset
|
393 |
stdin_stream = ProcessBuilder.NullOutputStream.INSTANCE; |
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
394 |
else { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
395 |
FileDescriptor stdin_fd = new FileDescriptor(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
396 |
fdAccess.setHandle(stdin_fd, stdHandles[0]); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
397 |
stdin_stream = new BufferedOutputStream( |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
398 |
new FileOutputStream(stdin_fd)); |
2 | 399 |
} |
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
400 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
401 |
if (stdHandles[1] == -1L) |
5787
a0af7b8e80ed
6960898: Regression due to src/share/classes/java/lang/ProcessBuilder.java changes
martin
parents:
5506
diff
changeset
|
402 |
stdout_stream = ProcessBuilder.NullInputStream.INSTANCE; |
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
403 |
else { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
404 |
FileDescriptor stdout_fd = new FileDescriptor(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
405 |
fdAccess.setHandle(stdout_fd, stdHandles[1]); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
406 |
stdout_stream = new BufferedInputStream( |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
407 |
new FileInputStream(stdout_fd)); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
408 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
409 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
410 |
if (stdHandles[2] == -1L) |
5787
a0af7b8e80ed
6960898: Regression due to src/share/classes/java/lang/ProcessBuilder.java changes
martin
parents:
5506
diff
changeset
|
411 |
stderr_stream = ProcessBuilder.NullInputStream.INSTANCE; |
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
412 |
else { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
413 |
FileDescriptor stderr_fd = new FileDescriptor(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
414 |
fdAccess.setHandle(stderr_fd, stdHandles[2]); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
415 |
stderr_stream = new FileInputStream(stderr_fd); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
416 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
417 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
418 |
return null; }}); |
2 | 419 |
} |
420 |
||
421 |
public OutputStream getOutputStream() { |
|
422 |
return stdin_stream; |
|
423 |
} |
|
424 |
||
425 |
public InputStream getInputStream() { |
|
426 |
return stdout_stream; |
|
427 |
} |
|
428 |
||
429 |
public InputStream getErrorStream() { |
|
430 |
return stderr_stream; |
|
431 |
} |
|
432 |
||
16490
43315ae7fa96
8006193: (process) Clean-up java.lang.ProcessImpl.finalize, does not need to be public
uta
parents:
13149
diff
changeset
|
433 |
protected void finalize() { |
2 | 434 |
closeHandle(handle); |
435 |
} |
|
436 |
||
437 |
private static final int STILL_ACTIVE = getStillActive(); |
|
438 |
private static native int getStillActive(); |
|
439 |
||
440 |
public int exitValue() { |
|
441 |
int exitCode = getExitCodeProcess(handle); |
|
442 |
if (exitCode == STILL_ACTIVE) |
|
443 |
throw new IllegalThreadStateException("process has not exited"); |
|
444 |
return exitCode; |
|
445 |
} |
|
446 |
private static native int getExitCodeProcess(long handle); |
|
447 |
||
448 |
public int waitFor() throws InterruptedException { |
|
449 |
waitForInterruptibly(handle); |
|
450 |
if (Thread.interrupted()) |
|
451 |
throw new InterruptedException(); |
|
452 |
return exitValue(); |
|
453 |
} |
|
13149
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
454 |
|
2 | 455 |
private static native void waitForInterruptibly(long handle); |
456 |
||
13149
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
457 |
@Override |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
458 |
public boolean waitFor(long timeout, TimeUnit unit) |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
459 |
throws InterruptedException |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
460 |
{ |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
461 |
if (getExitCodeProcess(handle) != STILL_ACTIVE) return true; |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
462 |
if (timeout <= 0) return false; |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
463 |
|
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
464 |
long msTimeout = unit.toMillis(timeout); |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
465 |
|
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
466 |
waitForTimeoutInterruptibly(handle, msTimeout); |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
467 |
if (Thread.interrupted()) |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
468 |
throw new InterruptedException(); |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
469 |
return (getExitCodeProcess(handle) != STILL_ACTIVE); |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
470 |
} |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
471 |
|
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
472 |
private static native void waitForTimeoutInterruptibly( |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
473 |
long handle, long timeout); |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
474 |
|
2 | 475 |
public void destroy() { terminateProcess(handle); } |
13149
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
476 |
|
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
477 |
@Override |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
478 |
public Process destroyForcibly() { |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
479 |
destroy(); |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
480 |
return this; |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
481 |
} |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
482 |
|
2 | 483 |
private static native void terminateProcess(long handle); |
484 |
||
13149
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
485 |
@Override |
24577 | 486 |
public long getPid() { |
487 |
int pid = getProcessId0(handle); |
|
488 |
return pid; |
|
489 |
} |
|
490 |
||
491 |
private static native int getProcessId0(long handle); |
|
492 |
||
493 |
@Override |
|
13149
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
494 |
public boolean isAlive() { |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
495 |
return isProcessAlive(handle); |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
496 |
} |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
497 |
|
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
498 |
private static native boolean isProcessAlive(long handle); |
27d52f97a5cc
4244896: (process) Provide System.getPid(), System.killProcess(String pid)
robm
parents:
10903
diff
changeset
|
499 |
|
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
500 |
/** |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
501 |
* 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
|
502 |
* 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
|
503 |
* 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
|
504 |
* |
19372
e404c834f1cd
7147084: (process) appA hangs when read output stream of appB which starts appC that runs forever
uta
parents:
18183
diff
changeset
|
505 |
* @param cmdstr the Windows command line |
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
506 |
* @param envblock NUL-separated, double-NUL-terminated list of |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
507 |
* environment strings in VAR=VALUE form |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
508 |
* @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
|
509 |
* inheriting the current directory from the parent process |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
510 |
* @param stdHandles array of windows HANDLEs. Indexes 0, 1, and |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
511 |
* 2 correspond to standard input, standard output and |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
512 |
* standard error, respectively. On input, a value of -1 |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
513 |
* means to create a pipe to connect child and parent |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
514 |
* 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
|
515 |
* parent pipe handle corresponding to the pipe which has |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
516 |
* 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
|
517 |
* 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
|
518 |
* @param redirectErrorStream redirectErrorStream attribute |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
519 |
* @return the native subprocess HANDLE returned by CreateProcess |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
520 |
*/ |
19372
e404c834f1cd
7147084: (process) appA hangs when read output stream of appB which starts appC that runs forever
uta
parents:
18183
diff
changeset
|
521 |
private static synchronized native long create(String cmdstr, |
2 | 522 |
String envblock, |
523 |
String dir, |
|
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
524 |
long[] stdHandles, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
525 |
boolean redirectErrorStream) |
2 | 526 |
throws IOException; |
527 |
||
7515
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
528 |
/** |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
529 |
* 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
|
530 |
* already exist. |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
531 |
* |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
532 |
* @param file the file to open or create |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
533 |
* @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
|
534 |
*/ |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
535 |
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
|
536 |
throws IOException; |
43202796198e
6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
alanb
parents:
5787
diff
changeset
|
537 |
|
2 | 538 |
private static native boolean closeHandle(long handle); |
539 |
} |