author | martin |
Fri, 17 Sep 2010 14:35:00 -0700 | |
changeset 6669 | 8f8d4d5768ae |
parent 5786 | f60ef38202e7 |
child 6849 | 02dc13de9152 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
5506 | 2 |
* Copyright (c) 2003, 2008, 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 |
|
7 |
* published by the Free Software Foundation. |
|
8 |
* |
|
9 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
13 |
* accompanied this code). |
|
14 |
* |
|
15 |
* You should have received a copy of the GNU General Public License version |
|
16 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
17 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 |
* |
|
5506 | 19 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 |
* or visit www.oracle.com if you need additional information or have any |
|
21 |
* questions. |
|
2 | 22 |
*/ |
23 |
||
24 |
/* |
|
25 |
* @test |
|
26 |
* @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689 |
|
27 |
* 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313 |
|
3840
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
28 |
* 6464154 6523983 6206031 4960438 6631352 6631966 6850957 6850958 |
5168
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
29 |
* 4947220 |
2 | 30 |
* @summary Basic tests for Process and Environment Variable code |
5600
8ca34998a6b3
6943915: Adjust jdk/test/Makefile to deal with .dll and .so libraries needing execute permissions
ohair
parents:
5168
diff
changeset
|
31 |
* @run main/othervm/timeout=300 Basic |
2 | 32 |
* @author Martin Buchholz |
33 |
*/ |
|
34 |
||
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
35 |
import java.lang.ProcessBuilder.Redirect; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
36 |
import static java.lang.ProcessBuilder.Redirect.*; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
37 |
|
2 | 38 |
import java.io.*; |
39 |
import java.util.*; |
|
5786
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
40 |
import java.util.concurrent.CountDownLatch; |
2 | 41 |
import java.security.*; |
42 |
import java.util.regex.Pattern; |
|
43 |
import static java.lang.System.getenv; |
|
44 |
import static java.lang.System.out; |
|
45 |
import static java.lang.Boolean.TRUE; |
|
46 |
import static java.util.AbstractMap.SimpleImmutableEntry; |
|
47 |
||
48 |
public class Basic { |
|
49 |
||
50 |
private static String commandOutput(Reader r) throws Throwable { |
|
51 |
StringBuilder sb = new StringBuilder(); |
|
52 |
int c; |
|
53 |
while ((c = r.read()) > 0) |
|
54 |
if (c != '\r') |
|
55 |
sb.append((char) c); |
|
56 |
return sb.toString(); |
|
57 |
} |
|
58 |
||
59 |
private static String commandOutput(Process p) throws Throwable { |
|
60 |
check(p.getInputStream() == p.getInputStream()); |
|
61 |
check(p.getOutputStream() == p.getOutputStream()); |
|
62 |
check(p.getErrorStream() == p.getErrorStream()); |
|
63 |
Reader r = new InputStreamReader(p.getInputStream(),"UTF-8"); |
|
64 |
String output = commandOutput(r); |
|
65 |
equal(p.waitFor(), 0); |
|
66 |
equal(p.exitValue(), 0); |
|
67 |
return output; |
|
68 |
} |
|
69 |
||
70 |
private static String commandOutput(ProcessBuilder pb) { |
|
71 |
try { |
|
72 |
return commandOutput(pb.start()); |
|
73 |
} catch (Throwable t) { |
|
74 |
String commandline = ""; |
|
75 |
for (String arg : pb.command()) |
|
76 |
commandline += " " + arg; |
|
77 |
System.out.println("Exception trying to run process: " + commandline); |
|
78 |
unexpected(t); |
|
79 |
return ""; |
|
80 |
} |
|
81 |
} |
|
82 |
||
83 |
private static String commandOutput(String...command) { |
|
84 |
try { |
|
85 |
return commandOutput(Runtime.getRuntime().exec(command)); |
|
86 |
} catch (Throwable t) { |
|
87 |
String commandline = ""; |
|
88 |
for (String arg : command) |
|
89 |
commandline += " " + arg; |
|
90 |
System.out.println("Exception trying to run process: " + commandline); |
|
91 |
unexpected(t); |
|
92 |
return ""; |
|
93 |
} |
|
94 |
} |
|
95 |
||
96 |
private static void checkCommandOutput(ProcessBuilder pb, |
|
97 |
String expected, |
|
98 |
String failureMsg) { |
|
99 |
String got = commandOutput(pb); |
|
100 |
check(got.equals(expected), |
|
101 |
failureMsg + "\n" + |
|
102 |
"Expected: \"" + expected + "\"\n" + |
|
103 |
"Got: \"" + got + "\""); |
|
104 |
} |
|
105 |
||
106 |
private static String absolutifyPath(String path) { |
|
107 |
StringBuilder sb = new StringBuilder(); |
|
108 |
for (String file : path.split(File.pathSeparator)) { |
|
109 |
if (sb.length() != 0) |
|
110 |
sb.append(File.pathSeparator); |
|
111 |
sb.append(new File(file).getAbsolutePath()); |
|
112 |
} |
|
113 |
return sb.toString(); |
|
114 |
} |
|
115 |
||
116 |
// compare windows-style, by canonicalizing to upper case, |
|
117 |
// not lower case as String.compareToIgnoreCase does |
|
118 |
private static class WindowsComparator |
|
119 |
implements Comparator<String> { |
|
120 |
public int compare(String x, String y) { |
|
121 |
return x.toUpperCase(Locale.US) |
|
122 |
.compareTo(y.toUpperCase(Locale.US)); |
|
123 |
} |
|
124 |
} |
|
125 |
||
126 |
private static String sortedLines(String lines) { |
|
127 |
String[] arr = lines.split("\n"); |
|
128 |
List<String> ls = new ArrayList<String>(); |
|
129 |
for (String s : arr) |
|
130 |
ls.add(s); |
|
131 |
Collections.sort(ls, new WindowsComparator()); |
|
132 |
StringBuilder sb = new StringBuilder(); |
|
133 |
for (String s : ls) |
|
134 |
sb.append(s + "\n"); |
|
135 |
return sb.toString(); |
|
136 |
} |
|
137 |
||
138 |
private static void compareLinesIgnoreCase(String lines1, String lines2) { |
|
139 |
if (! (sortedLines(lines1).equalsIgnoreCase(sortedLines(lines2)))) { |
|
140 |
String dashes = |
|
141 |
"-----------------------------------------------------"; |
|
142 |
out.println(dashes); |
|
143 |
out.print(sortedLines(lines1)); |
|
144 |
out.println(dashes); |
|
145 |
out.print(sortedLines(lines2)); |
|
146 |
out.println(dashes); |
|
147 |
out.println("sizes: " + sortedLines(lines1).length() + |
|
148 |
" " + sortedLines(lines2).length()); |
|
149 |
||
150 |
fail("Sorted string contents differ"); |
|
151 |
} |
|
152 |
} |
|
153 |
||
154 |
private static final Runtime runtime = Runtime.getRuntime(); |
|
155 |
||
156 |
private static final String[] winEnvCommand = {"cmd.exe", "/c", "set"}; |
|
157 |
||
158 |
private static String winEnvFilter(String env) { |
|
159 |
return env.replaceAll("\r", "") |
|
160 |
.replaceAll("(?m)^(?:COMSPEC|PROMPT|PATHEXT)=.*\n",""); |
|
161 |
} |
|
162 |
||
163 |
private static String unixEnvProg() { |
|
164 |
return new File("/usr/bin/env").canExecute() ? "/usr/bin/env" |
|
165 |
: "/bin/env"; |
|
166 |
} |
|
167 |
||
168 |
private static String nativeEnv(String[] env) { |
|
169 |
try { |
|
170 |
if (Windows.is()) { |
|
171 |
return winEnvFilter |
|
172 |
(commandOutput(runtime.exec(winEnvCommand, env))); |
|
173 |
} else { |
|
174 |
return commandOutput(runtime.exec(unixEnvProg(), env)); |
|
175 |
} |
|
176 |
} catch (Throwable t) { throw new Error(t); } |
|
177 |
} |
|
178 |
||
179 |
private static String nativeEnv(ProcessBuilder pb) { |
|
180 |
try { |
|
181 |
if (Windows.is()) { |
|
182 |
pb.command(winEnvCommand); |
|
183 |
return winEnvFilter(commandOutput(pb)); |
|
184 |
} else { |
|
185 |
pb.command(new String[]{unixEnvProg()}); |
|
186 |
return commandOutput(pb); |
|
187 |
} |
|
188 |
} catch (Throwable t) { throw new Error(t); } |
|
189 |
} |
|
190 |
||
191 |
private static void checkSizes(Map<String,String> environ, int size) { |
|
192 |
try { |
|
193 |
equal(size, environ.size()); |
|
194 |
equal(size, environ.entrySet().size()); |
|
195 |
equal(size, environ.keySet().size()); |
|
196 |
equal(size, environ.values().size()); |
|
197 |
||
198 |
boolean isEmpty = (size == 0); |
|
199 |
equal(isEmpty, environ.isEmpty()); |
|
200 |
equal(isEmpty, environ.entrySet().isEmpty()); |
|
201 |
equal(isEmpty, environ.keySet().isEmpty()); |
|
202 |
equal(isEmpty, environ.values().isEmpty()); |
|
203 |
} catch (Throwable t) { unexpected(t); } |
|
204 |
} |
|
205 |
||
206 |
private interface EnvironmentFrobber { |
|
207 |
void doIt(Map<String,String> environ); |
|
208 |
} |
|
209 |
||
210 |
private static void testVariableDeleter(EnvironmentFrobber fooDeleter) { |
|
211 |
try { |
|
212 |
Map<String,String> environ = new ProcessBuilder().environment(); |
|
213 |
environ.put("Foo", "BAAR"); |
|
214 |
fooDeleter.doIt(environ); |
|
215 |
equal(environ.get("Foo"), null); |
|
216 |
equal(environ.remove("Foo"), null); |
|
217 |
} catch (Throwable t) { unexpected(t); } |
|
218 |
} |
|
219 |
||
220 |
private static void testVariableAdder(EnvironmentFrobber fooAdder) { |
|
221 |
try { |
|
222 |
Map<String,String> environ = new ProcessBuilder().environment(); |
|
223 |
environ.remove("Foo"); |
|
224 |
fooAdder.doIt(environ); |
|
225 |
equal(environ.get("Foo"), "Bahrein"); |
|
226 |
} catch (Throwable t) { unexpected(t); } |
|
227 |
} |
|
228 |
||
229 |
private static void testVariableModifier(EnvironmentFrobber fooModifier) { |
|
230 |
try { |
|
231 |
Map<String,String> environ = new ProcessBuilder().environment(); |
|
232 |
environ.put("Foo","OldValue"); |
|
233 |
fooModifier.doIt(environ); |
|
234 |
equal(environ.get("Foo"), "NewValue"); |
|
235 |
} catch (Throwable t) { unexpected(t); } |
|
236 |
} |
|
237 |
||
238 |
private static void printUTF8(String s) throws IOException { |
|
239 |
out.write(s.getBytes("UTF-8")); |
|
240 |
} |
|
241 |
||
242 |
private static String getenvAsString(Map<String,String> environment) { |
|
243 |
StringBuilder sb = new StringBuilder(); |
|
244 |
for (Map.Entry<String,String> e : environment.entrySet()) |
|
245 |
// Ignore magic environment variables added by the launcher |
|
246 |
if (! e.getKey().equals("NLSPATH") && |
|
247 |
! e.getKey().equals("XFILESEARCHPATH") && |
|
248 |
! e.getKey().equals("LD_LIBRARY_PATH")) |
|
249 |
sb.append(e.getKey()) |
|
250 |
.append('=') |
|
251 |
.append(e.getValue()) |
|
252 |
.append(','); |
|
253 |
return sb.toString(); |
|
254 |
} |
|
255 |
||
5786
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
256 |
static void print4095(OutputStream s, byte b) throws Throwable { |
2 | 257 |
byte[] bytes = new byte[4095]; |
5786
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
258 |
Arrays.fill(bytes, b); |
2 | 259 |
s.write(bytes); // Might hang! |
260 |
} |
|
261 |
||
2946
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
262 |
static void checkPermissionDenied(ProcessBuilder pb) { |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
263 |
try { |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
264 |
pb.start(); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
265 |
fail("Expected IOException not thrown"); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
266 |
} catch (IOException e) { |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
267 |
String m = e.getMessage(); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
268 |
if (EnglishUnix.is() && |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
269 |
! matches(m, "Permission denied")) |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
270 |
unexpected(e); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
271 |
} catch (Throwable t) { unexpected(t); } |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
272 |
} |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
273 |
|
2 | 274 |
public static class JavaChild { |
275 |
public static void main(String args[]) throws Throwable { |
|
276 |
String action = args[0]; |
|
5786
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
277 |
if (action.equals("sleep")) { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
278 |
Thread.sleep(10 * 60 * 1000L); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
279 |
} else if (action.equals("testIO")) { |
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
280 |
String expected = "standard input"; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
281 |
char[] buf = new char[expected.length()+1]; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
282 |
int n = new InputStreamReader(System.in).read(buf,0,buf.length); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
283 |
if (n != expected.length()) |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
284 |
System.exit(5); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
285 |
if (! new String(buf,0,n).equals(expected)) |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
286 |
System.exit(5); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
287 |
System.err.print("standard error"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
288 |
System.out.print("standard output"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
289 |
} else if (action.equals("testInheritIO")) { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
290 |
List<String> childArgs = new ArrayList<String>(javaChildArgs); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
291 |
childArgs.add("testIO"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
292 |
ProcessBuilder pb = new ProcessBuilder(childArgs); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
293 |
pb.inheritIO(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
294 |
ProcessResults r = run(pb); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
295 |
if (! r.out().equals("")) |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
296 |
System.exit(7); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
297 |
if (! r.err().equals("")) |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
298 |
System.exit(8); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
299 |
if (r.exitValue() != 0) |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
300 |
System.exit(9); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
301 |
} else if (action.equals("System.getenv(String)")) { |
2 | 302 |
String val = System.getenv(args[1]); |
303 |
printUTF8(val == null ? "null" : val); |
|
304 |
} else if (action.equals("System.getenv(\\u1234)")) { |
|
305 |
String val = System.getenv("\u1234"); |
|
306 |
printUTF8(val == null ? "null" : val); |
|
307 |
} else if (action.equals("System.getenv()")) { |
|
308 |
printUTF8(getenvAsString(System.getenv())); |
|
3840
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
309 |
} else if (action.equals("ArrayOOME")) { |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
310 |
Object dummy; |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
311 |
switch(new Random().nextInt(3)) { |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
312 |
case 0: dummy = new Integer[Integer.MAX_VALUE]; break; |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
313 |
case 1: dummy = new double[Integer.MAX_VALUE]; break; |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
314 |
case 2: dummy = new byte[Integer.MAX_VALUE][]; break; |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
315 |
default: throw new InternalError(); |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
316 |
} |
2 | 317 |
} else if (action.equals("pwd")) { |
318 |
printUTF8(new File(System.getProperty("user.dir")) |
|
319 |
.getCanonicalPath()); |
|
320 |
} else if (action.equals("print4095")) { |
|
5786
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
321 |
print4095(System.out, (byte) '!'); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
322 |
print4095(System.err, (byte) 'E'); |
2 | 323 |
System.exit(5); |
324 |
} else if (action.equals("OutErr")) { |
|
325 |
// You might think the system streams would be |
|
326 |
// buffered, and in fact they are implemented using |
|
327 |
// BufferedOutputStream, but each and every print |
|
328 |
// causes immediate operating system I/O. |
|
329 |
System.out.print("out"); |
|
330 |
System.err.print("err"); |
|
331 |
System.out.print("out"); |
|
332 |
System.err.print("err"); |
|
333 |
} else if (action.equals("null PATH")) { |
|
334 |
equal(System.getenv("PATH"), null); |
|
335 |
check(new File("/bin/true").exists()); |
|
336 |
check(new File("/bin/false").exists()); |
|
337 |
ProcessBuilder pb1 = new ProcessBuilder(); |
|
338 |
ProcessBuilder pb2 = new ProcessBuilder(); |
|
339 |
pb2.environment().put("PATH", "anyOldPathIgnoredAnyways"); |
|
340 |
ProcessResults r; |
|
341 |
||
342 |
for (final ProcessBuilder pb : |
|
343 |
new ProcessBuilder[] {pb1, pb2}) { |
|
344 |
pb.command("true"); |
|
2946
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
345 |
equal(run(pb).exitValue(), True.exitValue()); |
2 | 346 |
|
347 |
pb.command("false"); |
|
2946
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
348 |
equal(run(pb).exitValue(), False.exitValue()); |
2 | 349 |
} |
350 |
||
351 |
if (failed != 0) throw new Error("null PATH"); |
|
352 |
} else if (action.equals("PATH search algorithm")) { |
|
353 |
equal(System.getenv("PATH"), "dir1:dir2:"); |
|
354 |
check(new File("/bin/true").exists()); |
|
355 |
check(new File("/bin/false").exists()); |
|
356 |
String[] cmd = {"prog"}; |
|
357 |
ProcessBuilder pb1 = new ProcessBuilder(cmd); |
|
358 |
ProcessBuilder pb2 = new ProcessBuilder(cmd); |
|
359 |
ProcessBuilder pb3 = new ProcessBuilder(cmd); |
|
360 |
pb2.environment().put("PATH", "anyOldPathIgnoredAnyways"); |
|
361 |
pb3.environment().remove("PATH"); |
|
362 |
||
363 |
for (final ProcessBuilder pb : |
|
364 |
new ProcessBuilder[] {pb1, pb2, pb3}) { |
|
365 |
try { |
|
366 |
// Not on PATH at all; directories don't exist |
|
367 |
try { |
|
368 |
pb.start(); |
|
369 |
fail("Expected IOException not thrown"); |
|
370 |
} catch (IOException e) { |
|
371 |
String m = e.getMessage(); |
|
372 |
if (EnglishUnix.is() && |
|
373 |
! matches(m, "No such file")) |
|
374 |
unexpected(e); |
|
375 |
} catch (Throwable t) { unexpected(t); } |
|
376 |
||
377 |
// Not on PATH at all; directories exist |
|
378 |
new File("dir1").mkdirs(); |
|
379 |
new File("dir2").mkdirs(); |
|
380 |
try { |
|
381 |
pb.start(); |
|
382 |
fail("Expected IOException not thrown"); |
|
383 |
} catch (IOException e) { |
|
384 |
String m = e.getMessage(); |
|
385 |
if (EnglishUnix.is() && |
|
386 |
! matches(m, "No such file")) |
|
387 |
unexpected(e); |
|
388 |
} catch (Throwable t) { unexpected(t); } |
|
389 |
||
390 |
// Can't execute a directory -- permission denied |
|
391 |
// Report EACCES errno |
|
392 |
new File("dir1/prog").mkdirs(); |
|
2946
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
393 |
checkPermissionDenied(pb); |
2 | 394 |
|
395 |
// continue searching if EACCES |
|
396 |
copy("/bin/true", "dir2/prog"); |
|
2946
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
397 |
equal(run(pb).exitValue(), True.exitValue()); |
2 | 398 |
new File("dir1/prog").delete(); |
399 |
new File("dir2/prog").delete(); |
|
400 |
||
401 |
new File("dir2/prog").mkdirs(); |
|
402 |
copy("/bin/true", "dir1/prog"); |
|
2946
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
403 |
equal(run(pb).exitValue(), True.exitValue()); |
2 | 404 |
|
2946
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
405 |
// Check empty PATH component means current directory. |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
406 |
// |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
407 |
// While we're here, let's test different kinds of |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
408 |
// Unix executables, and PATH vs explicit searching. |
2 | 409 |
new File("dir1/prog").delete(); |
410 |
new File("dir2/prog").delete(); |
|
2946
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
411 |
for (String[] command : |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
412 |
new String[][] { |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
413 |
new String[] {"./prog"}, |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
414 |
cmd}) { |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
415 |
pb.command(command); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
416 |
File prog = new File("./prog"); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
417 |
// "Normal" binaries |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
418 |
copy("/bin/true", "./prog"); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
419 |
equal(run(pb).exitValue(), |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
420 |
True.exitValue()); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
421 |
copy("/bin/false", "./prog"); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
422 |
equal(run(pb).exitValue(), |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
423 |
False.exitValue()); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
424 |
prog.delete(); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
425 |
// Interpreter scripts with #! |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
426 |
setFileContents(prog, "#!/bin/true\n"); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
427 |
prog.setExecutable(true); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
428 |
equal(run(pb).exitValue(), |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
429 |
True.exitValue()); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
430 |
prog.delete(); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
431 |
setFileContents(prog, "#!/bin/false\n"); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
432 |
prog.setExecutable(true); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
433 |
equal(run(pb).exitValue(), |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
434 |
False.exitValue()); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
435 |
// Traditional shell scripts without #! |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
436 |
setFileContents(prog, "exec /bin/true\n"); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
437 |
prog.setExecutable(true); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
438 |
equal(run(pb).exitValue(), |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
439 |
True.exitValue()); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
440 |
prog.delete(); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
441 |
setFileContents(prog, "exec /bin/false\n"); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
442 |
prog.setExecutable(true); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
443 |
equal(run(pb).exitValue(), |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
444 |
False.exitValue()); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
445 |
prog.delete(); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
446 |
} |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
447 |
|
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
448 |
// Test Unix interpreter scripts |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
449 |
File dir1Prog = new File("dir1/prog"); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
450 |
dir1Prog.delete(); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
451 |
pb.command(new String[] {"prog", "world"}); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
452 |
setFileContents(dir1Prog, "#!/bin/echo hello\n"); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
453 |
checkPermissionDenied(pb); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
454 |
dir1Prog.setExecutable(true); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
455 |
equal(run(pb).out(), "hello dir1/prog world\n"); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
456 |
equal(run(pb).exitValue(), True.exitValue()); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
457 |
dir1Prog.delete(); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
458 |
pb.command(cmd); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
459 |
|
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
460 |
// Test traditional shell scripts without #! |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
461 |
setFileContents(dir1Prog, "/bin/echo \"$@\"\n"); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
462 |
pb.command(new String[] {"prog", "hello", "world"}); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
463 |
checkPermissionDenied(pb); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
464 |
dir1Prog.setExecutable(true); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
465 |
equal(run(pb).out(), "hello world\n"); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
466 |
equal(run(pb).exitValue(), True.exitValue()); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
467 |
dir1Prog.delete(); |
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
468 |
pb.command(cmd); |
2 | 469 |
|
470 |
// If prog found on both parent and child's PATH, |
|
471 |
// parent's is used. |
|
472 |
new File("dir1/prog").delete(); |
|
473 |
new File("dir2/prog").delete(); |
|
474 |
new File("prog").delete(); |
|
475 |
new File("dir3").mkdirs(); |
|
476 |
copy("/bin/true", "dir1/prog"); |
|
477 |
copy("/bin/false", "dir3/prog"); |
|
478 |
pb.environment().put("PATH","dir3"); |
|
2946
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
479 |
equal(run(pb).exitValue(), True.exitValue()); |
2 | 480 |
copy("/bin/true", "dir3/prog"); |
481 |
copy("/bin/false", "dir1/prog"); |
|
2946
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
482 |
equal(run(pb).exitValue(), False.exitValue()); |
2 | 483 |
|
484 |
} finally { |
|
485 |
// cleanup |
|
486 |
new File("dir1/prog").delete(); |
|
487 |
new File("dir2/prog").delete(); |
|
488 |
new File("dir3/prog").delete(); |
|
489 |
new File("dir1").delete(); |
|
490 |
new File("dir2").delete(); |
|
491 |
new File("dir3").delete(); |
|
492 |
new File("prog").delete(); |
|
493 |
} |
|
494 |
} |
|
495 |
||
496 |
if (failed != 0) throw new Error("PATH search algorithm"); |
|
497 |
} |
|
498 |
else throw new Error("JavaChild invocation error"); |
|
499 |
} |
|
500 |
} |
|
501 |
||
502 |
private static void copy(String src, String dst) { |
|
503 |
system("/bin/cp", "-fp", src, dst); |
|
504 |
} |
|
505 |
||
506 |
private static void system(String... command) { |
|
507 |
try { |
|
508 |
ProcessBuilder pb = new ProcessBuilder(command); |
|
509 |
ProcessResults r = run(pb.start()); |
|
510 |
equal(r.exitValue(), 0); |
|
511 |
equal(r.out(), ""); |
|
512 |
equal(r.err(), ""); |
|
513 |
} catch (Throwable t) { unexpected(t); } |
|
514 |
} |
|
515 |
||
516 |
private static String javaChildOutput(ProcessBuilder pb, String...args) { |
|
517 |
List<String> list = new ArrayList<String>(javaChildArgs); |
|
518 |
for (String arg : args) |
|
519 |
list.add(arg); |
|
520 |
pb.command(list); |
|
521 |
return commandOutput(pb); |
|
522 |
} |
|
523 |
||
524 |
private static String getenvInChild(ProcessBuilder pb) { |
|
525 |
return javaChildOutput(pb, "System.getenv()"); |
|
526 |
} |
|
527 |
||
528 |
private static String getenvInChild1234(ProcessBuilder pb) { |
|
529 |
return javaChildOutput(pb, "System.getenv(\\u1234)"); |
|
530 |
} |
|
531 |
||
532 |
private static String getenvInChild(ProcessBuilder pb, String name) { |
|
533 |
return javaChildOutput(pb, "System.getenv(String)", name); |
|
534 |
} |
|
535 |
||
536 |
private static String pwdInChild(ProcessBuilder pb) { |
|
537 |
return javaChildOutput(pb, "pwd"); |
|
538 |
} |
|
539 |
||
540 |
private static final String javaExe = |
|
541 |
System.getProperty("java.home") + |
|
542 |
File.separator + "bin" + File.separator + "java"; |
|
543 |
||
544 |
private static final String classpath = |
|
545 |
System.getProperty("java.class.path"); |
|
546 |
||
547 |
private static final List<String> javaChildArgs = |
|
548 |
Arrays.asList(new String[] |
|
549 |
{ javaExe, "-classpath", absolutifyPath(classpath), |
|
550 |
"Basic$JavaChild"}); |
|
551 |
||
552 |
private static void testEncoding(String encoding, String tested) { |
|
553 |
try { |
|
554 |
// If round trip conversion works, should be able to set env vars |
|
555 |
// correctly in child. |
|
556 |
if (new String(tested.getBytes()).equals(tested)) { |
|
557 |
out.println("Testing " + encoding + " environment values"); |
|
558 |
ProcessBuilder pb = new ProcessBuilder(); |
|
559 |
pb.environment().put("ASCIINAME",tested); |
|
560 |
equal(getenvInChild(pb,"ASCIINAME"), tested); |
|
561 |
} |
|
562 |
} catch (Throwable t) { unexpected(t); } |
|
563 |
} |
|
564 |
||
565 |
static class Windows { |
|
566 |
public static boolean is() { return is; } |
|
567 |
private static final boolean is = |
|
568 |
System.getProperty("os.name").startsWith("Windows"); |
|
569 |
} |
|
570 |
||
571 |
static class Unix { |
|
572 |
public static boolean is() { return is; } |
|
573 |
private static final boolean is = |
|
574 |
(! Windows.is() && |
|
575 |
new File("/bin/sh").exists() && |
|
576 |
new File("/bin/true").exists() && |
|
577 |
new File("/bin/false").exists()); |
|
578 |
} |
|
579 |
||
580 |
static class UnicodeOS { |
|
581 |
public static boolean is() { return is; } |
|
582 |
private static final String osName = System.getProperty("os.name"); |
|
583 |
private static final boolean is = |
|
584 |
// MacOS X would probably also qualify |
|
585 |
osName.startsWith("Windows") && |
|
586 |
! osName.startsWith("Windows 9") && |
|
587 |
! osName.equals("Windows Me"); |
|
588 |
} |
|
589 |
||
590 |
static class True { |
|
591 |
public static int exitValue() { return 0; } |
|
592 |
} |
|
593 |
||
594 |
private static class False { |
|
595 |
public static int exitValue() { return exitValue; } |
|
596 |
private static final int exitValue = exitValue0(); |
|
597 |
private static int exitValue0() { |
|
598 |
// /bin/false returns an *unspecified* non-zero number. |
|
599 |
try { |
|
600 |
if (! Unix.is()) |
|
601 |
return -1; |
|
602 |
else { |
|
603 |
int rc = new ProcessBuilder("/bin/false") |
|
604 |
.start().waitFor(); |
|
605 |
check(rc != 0); |
|
606 |
return rc; |
|
607 |
} |
|
608 |
} catch (Throwable t) { unexpected(t); return -1; } |
|
609 |
} |
|
610 |
} |
|
611 |
||
612 |
static class EnglishUnix { |
|
613 |
private final static Boolean is = |
|
614 |
(! Windows.is() && isEnglish("LANG") && isEnglish("LC_ALL")); |
|
615 |
||
616 |
private static boolean isEnglish(String envvar) { |
|
617 |
String val = getenv(envvar); |
|
618 |
return (val == null) || val.matches("en.*"); |
|
619 |
} |
|
620 |
||
621 |
/** Returns true if we can expect English OS error strings */ |
|
622 |
static boolean is() { return is; } |
|
623 |
} |
|
624 |
||
625 |
private static boolean matches(String str, String regex) { |
|
626 |
return Pattern.compile(regex).matcher(str).find(); |
|
627 |
} |
|
628 |
||
629 |
private static String sortByLinesWindowsly(String text) { |
|
630 |
String[] lines = text.split("\n"); |
|
631 |
Arrays.sort(lines, new WindowsComparator()); |
|
632 |
StringBuilder sb = new StringBuilder(); |
|
633 |
for (String line : lines) |
|
634 |
sb.append(line).append("\n"); |
|
635 |
return sb.toString(); |
|
636 |
} |
|
637 |
||
638 |
private static void checkMapSanity(Map<String,String> map) { |
|
639 |
try { |
|
640 |
Set<String> keySet = map.keySet(); |
|
641 |
Collection<String> values = map.values(); |
|
642 |
Set<Map.Entry<String,String>> entrySet = map.entrySet(); |
|
643 |
||
644 |
equal(entrySet.size(), keySet.size()); |
|
645 |
equal(entrySet.size(), values.size()); |
|
646 |
||
647 |
StringBuilder s1 = new StringBuilder(); |
|
648 |
for (Map.Entry<String,String> e : entrySet) |
|
649 |
s1.append(e.getKey() + "=" + e.getValue() + "\n"); |
|
650 |
||
651 |
StringBuilder s2 = new StringBuilder(); |
|
652 |
for (String var : keySet) |
|
653 |
s2.append(var + "=" + map.get(var) + "\n"); |
|
654 |
||
655 |
equal(s1.toString(), s2.toString()); |
|
656 |
||
657 |
Iterator<String> kIter = keySet.iterator(); |
|
658 |
Iterator<String> vIter = values.iterator(); |
|
659 |
Iterator<Map.Entry<String,String>> eIter = entrySet.iterator(); |
|
660 |
||
661 |
while (eIter.hasNext()) { |
|
662 |
Map.Entry<String,String> entry = eIter.next(); |
|
663 |
String key = kIter.next(); |
|
664 |
String value = vIter.next(); |
|
665 |
check(entrySet.contains(entry)); |
|
666 |
check(keySet.contains(key)); |
|
667 |
check(values.contains(value)); |
|
668 |
check(map.containsKey(key)); |
|
669 |
check(map.containsValue(value)); |
|
670 |
equal(entry.getKey(), key); |
|
671 |
equal(entry.getValue(), value); |
|
672 |
} |
|
673 |
check(! kIter.hasNext() && |
|
674 |
! vIter.hasNext()); |
|
675 |
||
676 |
} catch (Throwable t) { unexpected(t); } |
|
677 |
} |
|
678 |
||
679 |
private static void checkMapEquality(Map<String,String> map1, |
|
680 |
Map<String,String> map2) { |
|
681 |
try { |
|
682 |
equal(map1.size(), map2.size()); |
|
683 |
equal(map1.isEmpty(), map2.isEmpty()); |
|
684 |
for (String key : map1.keySet()) { |
|
685 |
equal(map1.get(key), map2.get(key)); |
|
686 |
check(map2.keySet().contains(key)); |
|
687 |
} |
|
688 |
equal(map1, map2); |
|
689 |
equal(map2, map1); |
|
690 |
equal(map1.entrySet(), map2.entrySet()); |
|
691 |
equal(map2.entrySet(), map1.entrySet()); |
|
692 |
equal(map1.keySet(), map2.keySet()); |
|
693 |
equal(map2.keySet(), map1.keySet()); |
|
694 |
||
695 |
equal(map1.hashCode(), map2.hashCode()); |
|
696 |
equal(map1.entrySet().hashCode(), map2.entrySet().hashCode()); |
|
697 |
equal(map1.keySet().hashCode(), map2.keySet().hashCode()); |
|
698 |
} catch (Throwable t) { unexpected(t); } |
|
699 |
} |
|
700 |
||
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
701 |
static void checkRedirects(ProcessBuilder pb, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
702 |
Redirect in, Redirect out, Redirect err) { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
703 |
equal(pb.redirectInput(), in); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
704 |
equal(pb.redirectOutput(), out); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
705 |
equal(pb.redirectError(), err); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
706 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
707 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
708 |
static void redirectIO(ProcessBuilder pb, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
709 |
Redirect in, Redirect out, Redirect err) { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
710 |
pb.redirectInput(in); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
711 |
pb.redirectOutput(out); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
712 |
pb.redirectError(err); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
713 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
714 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
715 |
static void setFileContents(File file, String contents) { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
716 |
try { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
717 |
Writer w = new FileWriter(file); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
718 |
w.write(contents); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
719 |
w.close(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
720 |
} catch (Throwable t) { unexpected(t); } |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
721 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
722 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
723 |
static String fileContents(File file) { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
724 |
try { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
725 |
Reader r = new FileReader(file); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
726 |
StringBuilder sb = new StringBuilder(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
727 |
char[] buffer = new char[1024]; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
728 |
int n; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
729 |
while ((n = r.read(buffer)) != -1) |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
730 |
sb.append(buffer,0,n); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
731 |
r.close(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
732 |
return new String(sb); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
733 |
} catch (Throwable t) { unexpected(t); return ""; } |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
734 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
735 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
736 |
static void testIORedirection() throws Throwable { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
737 |
final File ifile = new File("ifile"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
738 |
final File ofile = new File("ofile"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
739 |
final File efile = new File("efile"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
740 |
ifile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
741 |
ofile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
742 |
efile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
743 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
744 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
745 |
// Check mutual inequality of different types of Redirect |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
746 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
747 |
Redirect[] redirects = |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
748 |
{ PIPE, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
749 |
INHERIT, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
750 |
Redirect.from(ifile), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
751 |
Redirect.to(ifile), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
752 |
Redirect.appendTo(ifile), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
753 |
Redirect.from(ofile), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
754 |
Redirect.to(ofile), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
755 |
Redirect.appendTo(ofile), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
756 |
}; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
757 |
for (int i = 0; i < redirects.length; i++) |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
758 |
for (int j = 0; j < redirects.length; j++) |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
759 |
equal(redirects[i].equals(redirects[j]), (i == j)); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
760 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
761 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
762 |
// Check basic properties of different types of Redirect |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
763 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
764 |
equal(PIPE.type(), Redirect.Type.PIPE); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
765 |
equal(PIPE.toString(), "PIPE"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
766 |
equal(PIPE.file(), null); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
767 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
768 |
equal(INHERIT.type(), Redirect.Type.INHERIT); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
769 |
equal(INHERIT.toString(), "INHERIT"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
770 |
equal(INHERIT.file(), null); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
771 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
772 |
equal(Redirect.from(ifile).type(), Redirect.Type.READ); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
773 |
equal(Redirect.from(ifile).toString(), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
774 |
"redirect to read from file \"ifile\""); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
775 |
equal(Redirect.from(ifile).file(), ifile); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
776 |
equal(Redirect.from(ifile), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
777 |
Redirect.from(ifile)); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
778 |
equal(Redirect.from(ifile).hashCode(), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
779 |
Redirect.from(ifile).hashCode()); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
780 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
781 |
equal(Redirect.to(ofile).type(), Redirect.Type.WRITE); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
782 |
equal(Redirect.to(ofile).toString(), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
783 |
"redirect to write to file \"ofile\""); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
784 |
equal(Redirect.to(ofile).file(), ofile); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
785 |
equal(Redirect.to(ofile), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
786 |
Redirect.to(ofile)); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
787 |
equal(Redirect.to(ofile).hashCode(), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
788 |
Redirect.to(ofile).hashCode()); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
789 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
790 |
equal(Redirect.appendTo(ofile).type(), Redirect.Type.APPEND); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
791 |
equal(Redirect.appendTo(efile).toString(), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
792 |
"redirect to append to file \"efile\""); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
793 |
equal(Redirect.appendTo(efile).file(), efile); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
794 |
equal(Redirect.appendTo(efile), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
795 |
Redirect.appendTo(efile)); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
796 |
equal(Redirect.appendTo(efile).hashCode(), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
797 |
Redirect.appendTo(efile).hashCode()); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
798 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
799 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
800 |
// Check initial values of redirects |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
801 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
802 |
List<String> childArgs = new ArrayList<String>(javaChildArgs); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
803 |
childArgs.add("testIO"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
804 |
final ProcessBuilder pb = new ProcessBuilder(childArgs); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
805 |
checkRedirects(pb, PIPE, PIPE, PIPE); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
806 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
807 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
808 |
// Check inheritIO |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
809 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
810 |
pb.inheritIO(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
811 |
checkRedirects(pb, INHERIT, INHERIT, INHERIT); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
812 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
813 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
814 |
// Check setters and getters agree |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
815 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
816 |
pb.redirectInput(ifile); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
817 |
equal(pb.redirectInput().file(), ifile); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
818 |
equal(pb.redirectInput(), Redirect.from(ifile)); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
819 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
820 |
pb.redirectOutput(ofile); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
821 |
equal(pb.redirectOutput().file(), ofile); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
822 |
equal(pb.redirectOutput(), Redirect.to(ofile)); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
823 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
824 |
pb.redirectError(efile); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
825 |
equal(pb.redirectError().file(), efile); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
826 |
equal(pb.redirectError(), Redirect.to(efile)); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
827 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
828 |
THROWS(IllegalArgumentException.class, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
829 |
new Fun(){void f() { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
830 |
pb.redirectInput(Redirect.to(ofile)); }}, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
831 |
new Fun(){void f() { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
832 |
pb.redirectInput(Redirect.appendTo(ofile)); }}, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
833 |
new Fun(){void f() { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
834 |
pb.redirectOutput(Redirect.from(ifile)); }}, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
835 |
new Fun(){void f() { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
836 |
pb.redirectError(Redirect.from(ifile)); }}); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
837 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
838 |
THROWS(IOException.class, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
839 |
// Input file does not exist |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
840 |
new Fun(){void f() throws Throwable { pb.start(); }}); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
841 |
setFileContents(ifile, "standard input"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
842 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
843 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
844 |
// Writing to non-existent files |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
845 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
846 |
{ |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
847 |
ProcessResults r = run(pb); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
848 |
equal(r.exitValue(), 0); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
849 |
equal(fileContents(ofile), "standard output"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
850 |
equal(fileContents(efile), "standard error"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
851 |
equal(r.out(), ""); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
852 |
equal(r.err(), ""); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
853 |
ofile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
854 |
efile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
855 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
856 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
857 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
858 |
// Both redirectErrorStream + redirectError |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
859 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
860 |
{ |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
861 |
pb.redirectErrorStream(true); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
862 |
ProcessResults r = run(pb); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
863 |
equal(r.exitValue(), 0); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
864 |
equal(fileContents(ofile), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
865 |
"standard error" + "standard output"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
866 |
equal(fileContents(efile), ""); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
867 |
equal(r.out(), ""); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
868 |
equal(r.err(), ""); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
869 |
ofile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
870 |
efile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
871 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
872 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
873 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
874 |
// Appending to existing files |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
875 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
876 |
{ |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
877 |
setFileContents(ofile, "ofile-contents"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
878 |
setFileContents(efile, "efile-contents"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
879 |
pb.redirectOutput(Redirect.appendTo(ofile)); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
880 |
pb.redirectError(Redirect.appendTo(efile)); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
881 |
pb.redirectErrorStream(false); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
882 |
ProcessResults r = run(pb); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
883 |
equal(r.exitValue(), 0); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
884 |
equal(fileContents(ofile), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
885 |
"ofile-contents" + "standard output"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
886 |
equal(fileContents(efile), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
887 |
"efile-contents" + "standard error"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
888 |
equal(r.out(), ""); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
889 |
equal(r.err(), ""); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
890 |
ofile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
891 |
efile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
892 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
893 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
894 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
895 |
// Replacing existing files |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
896 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
897 |
{ |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
898 |
setFileContents(ofile, "ofile-contents"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
899 |
setFileContents(efile, "efile-contents"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
900 |
pb.redirectOutput(ofile); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
901 |
pb.redirectError(Redirect.to(efile)); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
902 |
ProcessResults r = run(pb); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
903 |
equal(r.exitValue(), 0); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
904 |
equal(fileContents(ofile), "standard output"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
905 |
equal(fileContents(efile), "standard error"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
906 |
equal(r.out(), ""); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
907 |
equal(r.err(), ""); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
908 |
ofile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
909 |
efile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
910 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
911 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
912 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
913 |
// Appending twice to the same file? |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
914 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
915 |
{ |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
916 |
setFileContents(ofile, "ofile-contents"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
917 |
setFileContents(efile, "efile-contents"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
918 |
Redirect appender = Redirect.appendTo(ofile); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
919 |
pb.redirectOutput(appender); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
920 |
pb.redirectError(appender); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
921 |
ProcessResults r = run(pb); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
922 |
equal(r.exitValue(), 0); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
923 |
equal(fileContents(ofile), |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
924 |
"ofile-contents" + |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
925 |
"standard error" + |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
926 |
"standard output"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
927 |
equal(fileContents(efile), "efile-contents"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
928 |
equal(r.out(), ""); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
929 |
equal(r.err(), ""); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
930 |
ifile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
931 |
ofile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
932 |
efile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
933 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
934 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
935 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
936 |
// Testing INHERIT is harder. |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
937 |
// Note that this requires __FOUR__ nested JVMs involved in one test, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
938 |
// if you count the harness JVM. |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
939 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
940 |
{ |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
941 |
redirectIO(pb, PIPE, PIPE, PIPE); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
942 |
List<String> command = pb.command(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
943 |
command.set(command.size() - 1, "testInheritIO"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
944 |
Process p = pb.start(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
945 |
new PrintStream(p.getOutputStream()).print("standard input"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
946 |
p.getOutputStream().close(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
947 |
ProcessResults r = run(p); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
948 |
equal(r.exitValue(), 0); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
949 |
equal(r.out(), "standard output"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
950 |
equal(r.err(), "standard error"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
951 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
952 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
953 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
954 |
// Test security implications of I/O redirection |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
955 |
//---------------------------------------------------------------- |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
956 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
957 |
// Read access to current directory is always granted; |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
958 |
// So create a tmpfile for input instead. |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
959 |
final File tmpFile = File.createTempFile("Basic", "tmp"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
960 |
setFileContents(tmpFile, "standard input"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
961 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
962 |
final Policy policy = new Policy(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
963 |
Policy.setPolicy(policy); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
964 |
System.setSecurityManager(new SecurityManager()); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
965 |
try { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
966 |
final Permission xPermission |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
967 |
= new FilePermission("<<ALL FILES>>", "execute"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
968 |
final Permission rxPermission |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
969 |
= new FilePermission("<<ALL FILES>>", "read,execute"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
970 |
final Permission wxPermission |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
971 |
= new FilePermission("<<ALL FILES>>", "write,execute"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
972 |
final Permission rwxPermission |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
973 |
= new FilePermission("<<ALL FILES>>", "read,write,execute"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
974 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
975 |
THROWS(SecurityException.class, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
976 |
new Fun() { void f() throws IOException { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
977 |
policy.setPermissions(xPermission); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
978 |
redirectIO(pb, from(tmpFile), PIPE, PIPE); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
979 |
pb.start();}}, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
980 |
new Fun() { void f() throws IOException { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
981 |
policy.setPermissions(rxPermission); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
982 |
redirectIO(pb, PIPE, to(ofile), PIPE); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
983 |
pb.start();}}, |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
984 |
new Fun() { void f() throws IOException { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
985 |
policy.setPermissions(rxPermission); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
986 |
redirectIO(pb, PIPE, PIPE, to(efile)); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
987 |
pb.start();}}); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
988 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
989 |
{ |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
990 |
policy.setPermissions(rxPermission); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
991 |
redirectIO(pb, from(tmpFile), PIPE, PIPE); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
992 |
ProcessResults r = run(pb); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
993 |
equal(r.out(), "standard output"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
994 |
equal(r.err(), "standard error"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
995 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
996 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
997 |
{ |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
998 |
policy.setPermissions(wxPermission); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
999 |
redirectIO(pb, PIPE, to(ofile), to(efile)); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1000 |
Process p = pb.start(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1001 |
new PrintStream(p.getOutputStream()).print("standard input"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1002 |
p.getOutputStream().close(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1003 |
ProcessResults r = run(p); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1004 |
policy.setPermissions(rwxPermission); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1005 |
equal(fileContents(ofile), "standard output"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1006 |
equal(fileContents(efile), "standard error"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1007 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1008 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1009 |
{ |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1010 |
policy.setPermissions(rwxPermission); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1011 |
redirectIO(pb, from(tmpFile), to(ofile), to(efile)); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1012 |
ProcessResults r = run(pb); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1013 |
policy.setPermissions(rwxPermission); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1014 |
equal(fileContents(ofile), "standard output"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1015 |
equal(fileContents(efile), "standard error"); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1016 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1017 |
|
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1018 |
} finally { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1019 |
policy.setPermissions(new RuntimePermission("setSecurityManager")); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1020 |
System.setSecurityManager(null); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1021 |
tmpFile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1022 |
ifile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1023 |
ofile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1024 |
efile.delete(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1025 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1026 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1027 |
|
2 | 1028 |
private static void realMain(String[] args) throws Throwable { |
1029 |
if (Windows.is()) |
|
1030 |
System.out.println("This appears to be a Windows system."); |
|
1031 |
if (Unix.is()) |
|
1032 |
System.out.println("This appears to be a Unix system."); |
|
1033 |
if (UnicodeOS.is()) |
|
1034 |
System.out.println("This appears to be a Unicode-based OS."); |
|
1035 |
||
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1036 |
try { testIORedirection(); } |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1037 |
catch (Throwable t) { unexpected(t); } |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1038 |
|
2 | 1039 |
//---------------------------------------------------------------- |
1040 |
// Basic tests for setting, replacing and deleting envvars |
|
1041 |
//---------------------------------------------------------------- |
|
1042 |
try { |
|
1043 |
ProcessBuilder pb = new ProcessBuilder(); |
|
1044 |
Map<String,String> environ = pb.environment(); |
|
1045 |
||
1046 |
// New env var |
|
1047 |
environ.put("QUUX", "BAR"); |
|
1048 |
equal(environ.get("QUUX"), "BAR"); |
|
1049 |
equal(getenvInChild(pb,"QUUX"), "BAR"); |
|
1050 |
||
1051 |
// Modify env var |
|
1052 |
environ.put("QUUX","bear"); |
|
1053 |
equal(environ.get("QUUX"), "bear"); |
|
1054 |
equal(getenvInChild(pb,"QUUX"), "bear"); |
|
1055 |
checkMapSanity(environ); |
|
1056 |
||
1057 |
// Remove env var |
|
1058 |
environ.remove("QUUX"); |
|
1059 |
equal(environ.get("QUUX"), null); |
|
1060 |
equal(getenvInChild(pb,"QUUX"), "null"); |
|
1061 |
checkMapSanity(environ); |
|
1062 |
||
1063 |
// Remove non-existent env var |
|
1064 |
environ.remove("QUUX"); |
|
1065 |
equal(environ.get("QUUX"), null); |
|
1066 |
equal(getenvInChild(pb,"QUUX"), "null"); |
|
1067 |
checkMapSanity(environ); |
|
1068 |
} catch (Throwable t) { unexpected(t); } |
|
1069 |
||
1070 |
//---------------------------------------------------------------- |
|
1071 |
// Pass Empty environment to child |
|
1072 |
//---------------------------------------------------------------- |
|
1073 |
try { |
|
1074 |
ProcessBuilder pb = new ProcessBuilder(); |
|
1075 |
pb.environment().clear(); |
|
1076 |
equal(getenvInChild(pb), ""); |
|
1077 |
} catch (Throwable t) { unexpected(t); } |
|
1078 |
||
1079 |
//---------------------------------------------------------------- |
|
1080 |
// System.getenv() is read-only. |
|
1081 |
//---------------------------------------------------------------- |
|
1082 |
THROWS(UnsupportedOperationException.class, |
|
1083 |
new Fun(){void f(){ getenv().put("FOO","BAR");}}, |
|
1084 |
new Fun(){void f(){ getenv().remove("PATH");}}, |
|
1085 |
new Fun(){void f(){ getenv().keySet().remove("PATH");}}, |
|
1086 |
new Fun(){void f(){ getenv().values().remove("someValue");}}); |
|
1087 |
||
1088 |
try { |
|
1089 |
Collection<Map.Entry<String,String>> c = getenv().entrySet(); |
|
1090 |
if (! c.isEmpty()) |
|
1091 |
try { |
|
1092 |
c.iterator().next().setValue("foo"); |
|
1093 |
fail("Expected UnsupportedOperationException not thrown"); |
|
1094 |
} catch (UnsupportedOperationException e) {} // OK |
|
1095 |
} catch (Throwable t) { unexpected(t); } |
|
1096 |
||
1097 |
//---------------------------------------------------------------- |
|
1098 |
// System.getenv() always returns the same object in our implementation. |
|
1099 |
//---------------------------------------------------------------- |
|
1100 |
try { |
|
1101 |
check(System.getenv() == System.getenv()); |
|
1102 |
} catch (Throwable t) { unexpected(t); } |
|
1103 |
||
1104 |
//---------------------------------------------------------------- |
|
1105 |
// You can't create an env var name containing "=", |
|
1106 |
// or an env var name or value containing NUL. |
|
1107 |
//---------------------------------------------------------------- |
|
1108 |
{ |
|
1109 |
final Map<String,String> m = new ProcessBuilder().environment(); |
|
1110 |
THROWS(IllegalArgumentException.class, |
|
1111 |
new Fun(){void f(){ m.put("FOO=","BAR");}}, |
|
1112 |
new Fun(){void f(){ m.put("FOO\u0000","BAR");}}, |
|
1113 |
new Fun(){void f(){ m.put("FOO","BAR\u0000");}}); |
|
1114 |
} |
|
1115 |
||
1116 |
//---------------------------------------------------------------- |
|
1117 |
// Commands must never be null. |
|
1118 |
//---------------------------------------------------------------- |
|
1119 |
THROWS(NullPointerException.class, |
|
1120 |
new Fun(){void f(){ |
|
1121 |
new ProcessBuilder((List<String>)null);}}, |
|
1122 |
new Fun(){void f(){ |
|
1123 |
new ProcessBuilder().command((List<String>)null);}}); |
|
1124 |
||
1125 |
//---------------------------------------------------------------- |
|
1126 |
// Put in a command; get the same one back out. |
|
1127 |
//---------------------------------------------------------------- |
|
1128 |
try { |
|
1129 |
List<String> command = new ArrayList<String>(); |
|
1130 |
ProcessBuilder pb = new ProcessBuilder(command); |
|
1131 |
check(pb.command() == command); |
|
1132 |
List<String> command2 = new ArrayList<String>(2); |
|
1133 |
command2.add("foo"); |
|
1134 |
command2.add("bar"); |
|
1135 |
pb.command(command2); |
|
1136 |
check(pb.command() == command2); |
|
1137 |
pb.command("foo", "bar"); |
|
1138 |
check(pb.command() != command2 && pb.command().equals(command2)); |
|
1139 |
pb.command(command2); |
|
1140 |
command2.add("baz"); |
|
1141 |
equal(pb.command().get(2), "baz"); |
|
1142 |
} catch (Throwable t) { unexpected(t); } |
|
1143 |
||
1144 |
//---------------------------------------------------------------- |
|
1145 |
// Commands must contain at least one element. |
|
1146 |
//---------------------------------------------------------------- |
|
1147 |
THROWS(IndexOutOfBoundsException.class, |
|
1148 |
new Fun() { void f() throws IOException { |
|
1149 |
new ProcessBuilder().start();}}, |
|
1150 |
new Fun() { void f() throws IOException { |
|
1151 |
new ProcessBuilder(new ArrayList<String>()).start();}}, |
|
1152 |
new Fun() { void f() throws IOException { |
|
1153 |
Runtime.getRuntime().exec(new String[]{});}}); |
|
1154 |
||
1155 |
//---------------------------------------------------------------- |
|
1156 |
// Commands must not contain null elements at start() time. |
|
1157 |
//---------------------------------------------------------------- |
|
1158 |
THROWS(NullPointerException.class, |
|
1159 |
new Fun() { void f() throws IOException { |
|
1160 |
new ProcessBuilder("foo",null,"bar").start();}}, |
|
1161 |
new Fun() { void f() throws IOException { |
|
1162 |
new ProcessBuilder((String)null).start();}}, |
|
1163 |
new Fun() { void f() throws IOException { |
|
1164 |
new ProcessBuilder(new String[]{null}).start();}}, |
|
1165 |
new Fun() { void f() throws IOException { |
|
1166 |
new ProcessBuilder(new String[]{"foo",null,"bar"}).start();}}); |
|
1167 |
||
1168 |
//---------------------------------------------------------------- |
|
1169 |
// Command lists are growable. |
|
1170 |
//---------------------------------------------------------------- |
|
1171 |
try { |
|
1172 |
new ProcessBuilder().command().add("foo"); |
|
1173 |
new ProcessBuilder("bar").command().add("foo"); |
|
1174 |
new ProcessBuilder(new String[]{"1","2"}).command().add("3"); |
|
1175 |
} catch (Throwable t) { unexpected(t); } |
|
1176 |
||
1177 |
//---------------------------------------------------------------- |
|
1178 |
// Nulls in environment updates generate NullPointerException |
|
1179 |
//---------------------------------------------------------------- |
|
1180 |
try { |
|
1181 |
final Map<String,String> env = new ProcessBuilder().environment(); |
|
1182 |
THROWS(NullPointerException.class, |
|
1183 |
new Fun(){void f(){ env.put("foo",null);}}, |
|
1184 |
new Fun(){void f(){ env.put(null,"foo");}}, |
|
1185 |
new Fun(){void f(){ env.remove(null);}}, |
|
1186 |
new Fun(){void f(){ |
|
1187 |
for (Map.Entry<String,String> e : env.entrySet()) |
|
1188 |
e.setValue(null);}}, |
|
1189 |
new Fun() { void f() throws IOException { |
|
1190 |
Runtime.getRuntime().exec(new String[]{"foo"}, |
|
1191 |
new String[]{null});}}); |
|
1192 |
} catch (Throwable t) { unexpected(t); } |
|
1193 |
||
1194 |
//---------------------------------------------------------------- |
|
1195 |
// Non-String types in environment updates generate ClassCastException |
|
1196 |
//---------------------------------------------------------------- |
|
1197 |
try { |
|
1198 |
final Map<String,String> env = new ProcessBuilder().environment(); |
|
1199 |
THROWS(ClassCastException.class, |
|
1200 |
new Fun(){void f(){ env.remove(TRUE);}}, |
|
1201 |
new Fun(){void f(){ env.keySet().remove(TRUE);}}, |
|
1202 |
new Fun(){void f(){ env.values().remove(TRUE);}}, |
|
1203 |
new Fun(){void f(){ env.entrySet().remove(TRUE);}}); |
|
1204 |
} catch (Throwable t) { unexpected(t); } |
|
1205 |
||
1206 |
//---------------------------------------------------------------- |
|
1207 |
// Check query operations on environment maps |
|
1208 |
//---------------------------------------------------------------- |
|
1209 |
try { |
|
1210 |
List<Map<String,String>> envs = |
|
1211 |
new ArrayList<Map<String,String>>(2); |
|
1212 |
envs.add(System.getenv()); |
|
1213 |
envs.add(new ProcessBuilder().environment()); |
|
1214 |
for (final Map<String,String> env : envs) { |
|
1215 |
//---------------------------------------------------------------- |
|
1216 |
// Nulls in environment queries are forbidden. |
|
1217 |
//---------------------------------------------------------------- |
|
1218 |
THROWS(NullPointerException.class, |
|
1219 |
new Fun(){void f(){ getenv(null);}}, |
|
1220 |
new Fun(){void f(){ env.get(null);}}, |
|
1221 |
new Fun(){void f(){ env.containsKey(null);}}, |
|
1222 |
new Fun(){void f(){ env.containsValue(null);}}, |
|
1223 |
new Fun(){void f(){ env.keySet().contains(null);}}, |
|
1224 |
new Fun(){void f(){ env.values().contains(null);}}); |
|
1225 |
||
1226 |
//---------------------------------------------------------------- |
|
1227 |
// Non-String types in environment queries are forbidden. |
|
1228 |
//---------------------------------------------------------------- |
|
1229 |
THROWS(ClassCastException.class, |
|
1230 |
new Fun(){void f(){ env.get(TRUE);}}, |
|
1231 |
new Fun(){void f(){ env.containsKey(TRUE);}}, |
|
1232 |
new Fun(){void f(){ env.containsValue(TRUE);}}, |
|
1233 |
new Fun(){void f(){ env.keySet().contains(TRUE);}}, |
|
1234 |
new Fun(){void f(){ env.values().contains(TRUE);}}); |
|
1235 |
||
1236 |
//---------------------------------------------------------------- |
|
1237 |
// Illegal String values in environment queries are (grumble) OK |
|
1238 |
//---------------------------------------------------------------- |
|
1239 |
equal(env.get("\u0000"), null); |
|
1240 |
check(! env.containsKey("\u0000")); |
|
1241 |
check(! env.containsValue("\u0000")); |
|
1242 |
check(! env.keySet().contains("\u0000")); |
|
1243 |
check(! env.values().contains("\u0000")); |
|
1244 |
} |
|
1245 |
||
1246 |
} catch (Throwable t) { unexpected(t); } |
|
1247 |
||
1248 |
try { |
|
1249 |
final Set<Map.Entry<String,String>> entrySet = |
|
1250 |
new ProcessBuilder().environment().entrySet(); |
|
1251 |
THROWS(NullPointerException.class, |
|
1252 |
new Fun(){void f(){ entrySet.contains(null);}}); |
|
1253 |
THROWS(ClassCastException.class, |
|
1254 |
new Fun(){void f(){ entrySet.contains(TRUE);}}, |
|
1255 |
new Fun(){void f(){ |
|
1256 |
entrySet.contains( |
|
1257 |
new SimpleImmutableEntry<Boolean,String>(TRUE,""));}}); |
|
1258 |
||
1259 |
check(! entrySet.contains |
|
1260 |
(new SimpleImmutableEntry<String,String>("", ""))); |
|
1261 |
} catch (Throwable t) { unexpected(t); } |
|
1262 |
||
1263 |
//---------------------------------------------------------------- |
|
1264 |
// Put in a directory; get the same one back out. |
|
1265 |
//---------------------------------------------------------------- |
|
1266 |
try { |
|
1267 |
ProcessBuilder pb = new ProcessBuilder(); |
|
1268 |
File foo = new File("foo"); |
|
1269 |
equal(pb.directory(), null); |
|
1270 |
equal(pb.directory(foo).directory(), foo); |
|
1271 |
equal(pb.directory(null).directory(), null); |
|
1272 |
} catch (Throwable t) { unexpected(t); } |
|
1273 |
||
1274 |
//---------------------------------------------------------------- |
|
1275 |
// If round-trip conversion works, check envvar pass-through to child |
|
1276 |
//---------------------------------------------------------------- |
|
1277 |
try { |
|
1278 |
testEncoding("ASCII", "xyzzy"); |
|
1279 |
testEncoding("Latin1", "\u00f1\u00e1"); |
|
1280 |
testEncoding("Unicode", "\u22f1\u11e1"); |
|
1281 |
} catch (Throwable t) { unexpected(t); } |
|
1282 |
||
1283 |
//---------------------------------------------------------------- |
|
1284 |
// A surprisingly large number of ways to delete an environment var. |
|
1285 |
//---------------------------------------------------------------- |
|
1286 |
testVariableDeleter(new EnvironmentFrobber() { |
|
1287 |
public void doIt(Map<String,String> environ) { |
|
1288 |
environ.remove("Foo");}}); |
|
1289 |
||
1290 |
testVariableDeleter(new EnvironmentFrobber() { |
|
1291 |
public void doIt(Map<String,String> environ) { |
|
1292 |
environ.keySet().remove("Foo");}}); |
|
1293 |
||
1294 |
testVariableDeleter(new EnvironmentFrobber() { |
|
1295 |
public void doIt(Map<String,String> environ) { |
|
1296 |
environ.values().remove("BAAR");}}); |
|
1297 |
||
1298 |
testVariableDeleter(new EnvironmentFrobber() { |
|
1299 |
public void doIt(Map<String,String> environ) { |
|
1300 |
// Legally fabricate a ProcessEnvironment.StringEntry, |
|
1301 |
// even though it's private. |
|
1302 |
Map<String,String> environ2 |
|
1303 |
= new ProcessBuilder().environment(); |
|
1304 |
environ2.clear(); |
|
1305 |
environ2.put("Foo","BAAR"); |
|
1306 |
// Subtlety alert. |
|
1307 |
Map.Entry<String,String> e |
|
1308 |
= environ2.entrySet().iterator().next(); |
|
1309 |
environ.entrySet().remove(e);}}); |
|
1310 |
||
1311 |
testVariableDeleter(new EnvironmentFrobber() { |
|
1312 |
public void doIt(Map<String,String> environ) { |
|
1313 |
Map.Entry<String,String> victim = null; |
|
1314 |
for (Map.Entry<String,String> e : environ.entrySet()) |
|
1315 |
if (e.getKey().equals("Foo")) |
|
1316 |
victim = e; |
|
1317 |
if (victim != null) |
|
1318 |
environ.entrySet().remove(victim);}}); |
|
1319 |
||
1320 |
testVariableDeleter(new EnvironmentFrobber() { |
|
1321 |
public void doIt(Map<String,String> environ) { |
|
1322 |
Iterator<String> it = environ.keySet().iterator(); |
|
1323 |
while (it.hasNext()) { |
|
1324 |
String val = it.next(); |
|
1325 |
if (val.equals("Foo")) |
|
1326 |
it.remove();}}}); |
|
1327 |
||
1328 |
testVariableDeleter(new EnvironmentFrobber() { |
|
1329 |
public void doIt(Map<String,String> environ) { |
|
1330 |
Iterator<Map.Entry<String,String>> it |
|
1331 |
= environ.entrySet().iterator(); |
|
1332 |
while (it.hasNext()) { |
|
1333 |
Map.Entry<String,String> e = it.next(); |
|
1334 |
if (e.getKey().equals("Foo")) |
|
1335 |
it.remove();}}}); |
|
1336 |
||
1337 |
testVariableDeleter(new EnvironmentFrobber() { |
|
1338 |
public void doIt(Map<String,String> environ) { |
|
1339 |
Iterator<String> it = environ.values().iterator(); |
|
1340 |
while (it.hasNext()) { |
|
1341 |
String val = it.next(); |
|
1342 |
if (val.equals("BAAR")) |
|
1343 |
it.remove();}}}); |
|
1344 |
||
1345 |
//---------------------------------------------------------------- |
|
1346 |
// A surprisingly small number of ways to add an environment var. |
|
1347 |
//---------------------------------------------------------------- |
|
1348 |
testVariableAdder(new EnvironmentFrobber() { |
|
1349 |
public void doIt(Map<String,String> environ) { |
|
1350 |
environ.put("Foo","Bahrein");}}); |
|
1351 |
||
1352 |
//---------------------------------------------------------------- |
|
1353 |
// A few ways to modify an environment var. |
|
1354 |
//---------------------------------------------------------------- |
|
1355 |
testVariableModifier(new EnvironmentFrobber() { |
|
1356 |
public void doIt(Map<String,String> environ) { |
|
1357 |
environ.put("Foo","NewValue");}}); |
|
1358 |
||
1359 |
testVariableModifier(new EnvironmentFrobber() { |
|
1360 |
public void doIt(Map<String,String> environ) { |
|
1361 |
for (Map.Entry<String,String> e : environ.entrySet()) |
|
1362 |
if (e.getKey().equals("Foo")) |
|
1363 |
e.setValue("NewValue");}}); |
|
1364 |
||
1365 |
//---------------------------------------------------------------- |
|
1366 |
// Fiddle with environment sizes |
|
1367 |
//---------------------------------------------------------------- |
|
1368 |
try { |
|
1369 |
Map<String,String> environ = new ProcessBuilder().environment(); |
|
1370 |
int size = environ.size(); |
|
1371 |
checkSizes(environ, size); |
|
1372 |
||
1373 |
environ.put("UnLiKeLYeNVIROmtNam", "someVal"); |
|
1374 |
checkSizes(environ, size+1); |
|
1375 |
||
1376 |
// Check for environment independence |
|
1377 |
new ProcessBuilder().environment().clear(); |
|
1378 |
||
1379 |
environ.put("UnLiKeLYeNVIROmtNam", "someOtherVal"); |
|
1380 |
checkSizes(environ, size+1); |
|
1381 |
||
1382 |
environ.remove("UnLiKeLYeNVIROmtNam"); |
|
1383 |
checkSizes(environ, size); |
|
1384 |
||
1385 |
environ.clear(); |
|
1386 |
checkSizes(environ, 0); |
|
1387 |
||
1388 |
environ.clear(); |
|
1389 |
checkSizes(environ, 0); |
|
1390 |
||
1391 |
environ = new ProcessBuilder().environment(); |
|
1392 |
environ.keySet().clear(); |
|
1393 |
checkSizes(environ, 0); |
|
1394 |
||
1395 |
environ = new ProcessBuilder().environment(); |
|
1396 |
environ.entrySet().clear(); |
|
1397 |
checkSizes(environ, 0); |
|
1398 |
||
1399 |
environ = new ProcessBuilder().environment(); |
|
1400 |
environ.values().clear(); |
|
1401 |
checkSizes(environ, 0); |
|
1402 |
} catch (Throwable t) { unexpected(t); } |
|
1403 |
||
1404 |
//---------------------------------------------------------------- |
|
1405 |
// Check that various map invariants hold |
|
1406 |
//---------------------------------------------------------------- |
|
1407 |
checkMapSanity(new ProcessBuilder().environment()); |
|
1408 |
checkMapSanity(System.getenv()); |
|
1409 |
checkMapEquality(new ProcessBuilder().environment(), |
|
1410 |
new ProcessBuilder().environment()); |
|
1411 |
||
1412 |
||
1413 |
//---------------------------------------------------------------- |
|
1414 |
// Check effects on external "env" command. |
|
1415 |
//---------------------------------------------------------------- |
|
1416 |
try { |
|
1417 |
Set<String> env1 = new HashSet<String> |
|
1418 |
(Arrays.asList(nativeEnv((String[])null).split("\n"))); |
|
1419 |
||
1420 |
ProcessBuilder pb = new ProcessBuilder(); |
|
1421 |
pb.environment().put("QwErTyUiOp","AsDfGhJk"); |
|
1422 |
||
1423 |
Set<String> env2 = new HashSet<String> |
|
1424 |
(Arrays.asList(nativeEnv(pb).split("\n"))); |
|
1425 |
||
1426 |
check(env2.size() == env1.size() + 1); |
|
1427 |
env1.add("QwErTyUiOp=AsDfGhJk"); |
|
1428 |
check(env1.equals(env2)); |
|
1429 |
} catch (Throwable t) { unexpected(t); } |
|
1430 |
||
1431 |
//---------------------------------------------------------------- |
|
1432 |
// Test Runtime.exec(...envp...) |
|
1433 |
// Check for sort order of environment variables on Windows. |
|
1434 |
//---------------------------------------------------------------- |
|
1435 |
try { |
|
1436 |
// '+' < 'A' < 'Z' < '_' < 'a' < 'z' < '~' |
|
1437 |
String[]envp = {"FOO=BAR","BAZ=GORP","QUUX=", |
|
1438 |
"+=+", "_=_", "~=~"}; |
|
1439 |
String output = nativeEnv(envp); |
|
1440 |
String expected = "+=+\nBAZ=GORP\nFOO=BAR\nQUUX=\n_=_\n~=~\n"; |
|
1441 |
// On Windows, Java must keep the environment sorted. |
|
1442 |
// Order is random on Unix, so this test does the sort. |
|
1443 |
if (! Windows.is()) |
|
1444 |
output = sortByLinesWindowsly(output); |
|
1445 |
equal(output, expected); |
|
1446 |
} catch (Throwable t) { unexpected(t); } |
|
1447 |
||
1448 |
//---------------------------------------------------------------- |
|
1449 |
// System.getenv() must be consistent with System.getenv(String) |
|
1450 |
//---------------------------------------------------------------- |
|
1451 |
try { |
|
1452 |
for (Map.Entry<String,String> e : getenv().entrySet()) |
|
1453 |
equal(getenv(e.getKey()), e.getValue()); |
|
1454 |
} catch (Throwable t) { unexpected(t); } |
|
1455 |
||
1456 |
//---------------------------------------------------------------- |
|
1457 |
// Fiddle with working directory in child |
|
1458 |
//---------------------------------------------------------------- |
|
1459 |
try { |
|
1460 |
String canonicalUserDir = |
|
1461 |
new File(System.getProperty("user.dir")).getCanonicalPath(); |
|
1462 |
String[] sdirs = new String[] |
|
1463 |
{".", "..", "/", "/bin", |
|
5168
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1464 |
"C:", "c:", "C:/", "c:\\", "\\", "\\bin", |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1465 |
"c:\\windows ", "c:\\Program Files", "c:\\Program Files\\" }; |
2 | 1466 |
for (String sdir : sdirs) { |
1467 |
File dir = new File(sdir); |
|
1468 |
if (! (dir.isDirectory() && dir.exists())) |
|
1469 |
continue; |
|
1470 |
out.println("Testing directory " + dir); |
|
5168
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1471 |
//dir = new File(dir.getCanonicalPath()); |
2 | 1472 |
|
1473 |
ProcessBuilder pb = new ProcessBuilder(); |
|
1474 |
equal(pb.directory(), null); |
|
1475 |
equal(pwdInChild(pb), canonicalUserDir); |
|
1476 |
||
1477 |
pb.directory(dir); |
|
1478 |
equal(pb.directory(), dir); |
|
5168
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1479 |
equal(pwdInChild(pb), dir.getCanonicalPath()); |
2 | 1480 |
|
1481 |
pb.directory(null); |
|
1482 |
equal(pb.directory(), null); |
|
1483 |
equal(pwdInChild(pb), canonicalUserDir); |
|
1484 |
||
1485 |
pb.directory(dir); |
|
1486 |
} |
|
1487 |
} catch (Throwable t) { unexpected(t); } |
|
1488 |
||
1489 |
//---------------------------------------------------------------- |
|
5168
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1490 |
// Working directory with Unicode in child |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1491 |
//---------------------------------------------------------------- |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1492 |
try { |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1493 |
if (UnicodeOS.is()) { |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1494 |
File dir = new File(System.getProperty("test.dir", "."), |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1495 |
"ProcessBuilderDir\u4e00\u4e02"); |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1496 |
try { |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1497 |
if (!dir.exists()) |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1498 |
dir.mkdir(); |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1499 |
out.println("Testing Unicode directory:" + dir); |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1500 |
ProcessBuilder pb = new ProcessBuilder(); |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1501 |
pb.directory(dir); |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1502 |
equal(pwdInChild(pb), dir.getCanonicalPath()); |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1503 |
} finally { |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1504 |
if (dir.exists()) |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1505 |
dir.delete(); |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1506 |
} |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1507 |
} |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1508 |
} catch (Throwable t) { unexpected(t); } |
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1509 |
|
41e46b5d9b15
4947220: (process)Runtime.exec() cannot invoke applications with unicode parameters(win)
sherman
parents:
3840
diff
changeset
|
1510 |
//---------------------------------------------------------------- |
3840
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1511 |
// OOME in child allocating maximally sized array |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1512 |
// Test for hotspot/jvmti bug 6850957 |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1513 |
//---------------------------------------------------------------- |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1514 |
try { |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1515 |
List<String> list = new ArrayList<String>(javaChildArgs); |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1516 |
list.add(1, String.format("-XX:OnOutOfMemoryError=%s -version", |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1517 |
javaExe)); |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1518 |
list.add("ArrayOOME"); |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1519 |
ProcessResults r = run(new ProcessBuilder(list)); |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1520 |
check(r.out().contains("java.lang.OutOfMemoryError:")); |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1521 |
check(r.out().contains(javaExe)); |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1522 |
check(r.err().contains(System.getProperty("java.version"))); |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1523 |
equal(r.exitValue(), 1); |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1524 |
} catch (Throwable t) { unexpected(t); } |
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1525 |
|
37fca95e51fd
6850958: Honor -XX:OnOutOfMemoryError when array size exceeds VM limit
martin
parents:
2946
diff
changeset
|
1526 |
//---------------------------------------------------------------- |
2 | 1527 |
// Windows has tricky semi-case-insensitive semantics |
1528 |
//---------------------------------------------------------------- |
|
1529 |
if (Windows.is()) |
|
1530 |
try { |
|
1531 |
out.println("Running case insensitve variable tests"); |
|
1532 |
for (String[] namePair : |
|
1533 |
new String[][] |
|
1534 |
{ new String[]{"PATH","PaTh"}, |
|
1535 |
new String[]{"home","HOME"}, |
|
1536 |
new String[]{"SYSTEMROOT","SystemRoot"}}) { |
|
1537 |
check((getenv(namePair[0]) == null && |
|
1538 |
getenv(namePair[1]) == null) |
|
1539 |
|| |
|
1540 |
getenv(namePair[0]).equals(getenv(namePair[1])), |
|
1541 |
"Windows environment variables are not case insensitive"); |
|
1542 |
} |
|
1543 |
} catch (Throwable t) { unexpected(t); } |
|
1544 |
||
1545 |
//---------------------------------------------------------------- |
|
1546 |
// Test proper Unicode child environment transfer |
|
1547 |
//---------------------------------------------------------------- |
|
1548 |
if (UnicodeOS.is()) |
|
1549 |
try { |
|
1550 |
ProcessBuilder pb = new ProcessBuilder(); |
|
1551 |
pb.environment().put("\u1234","\u5678"); |
|
1552 |
pb.environment().remove("PATH"); |
|
1553 |
equal(getenvInChild1234(pb), "\u5678"); |
|
1554 |
} catch (Throwable t) { unexpected(t); } |
|
1555 |
||
1556 |
||
1557 |
//---------------------------------------------------------------- |
|
1558 |
// Test Runtime.exec(...envp...) with envstrings with initial `=' |
|
1559 |
//---------------------------------------------------------------- |
|
1560 |
try { |
|
1561 |
List<String> childArgs = new ArrayList<String>(javaChildArgs); |
|
1562 |
childArgs.add("System.getenv()"); |
|
1563 |
String[] cmdp = childArgs.toArray(new String[childArgs.size()]); |
|
1564 |
String[] envp = {"=ExitValue=3", "=C:=\\"}; |
|
1565 |
Process p = Runtime.getRuntime().exec(cmdp, envp); |
|
1566 |
String expected = Windows.is() ? "=C:=\\,=ExitValue=3," : "=C:=\\,"; |
|
1567 |
equal(commandOutput(p), expected); |
|
1568 |
if (Windows.is()) { |
|
1569 |
ProcessBuilder pb = new ProcessBuilder(childArgs); |
|
1570 |
pb.environment().clear(); |
|
1571 |
pb.environment().put("=ExitValue", "3"); |
|
1572 |
pb.environment().put("=C:", "\\"); |
|
1573 |
equal(commandOutput(pb), expected); |
|
1574 |
} |
|
1575 |
} catch (Throwable t) { unexpected(t); } |
|
1576 |
||
1577 |
//---------------------------------------------------------------- |
|
1578 |
// Test Runtime.exec(...envp...) with envstrings without any `=' |
|
1579 |
//---------------------------------------------------------------- |
|
1580 |
try { |
|
1581 |
String[] cmdp = {"echo"}; |
|
1582 |
String[] envp = {"Hello", "World"}; // Yuck! |
|
1583 |
Process p = Runtime.getRuntime().exec(cmdp, envp); |
|
1584 |
equal(commandOutput(p), "\n"); |
|
1585 |
} catch (Throwable t) { unexpected(t); } |
|
1586 |
||
1587 |
//---------------------------------------------------------------- |
|
1588 |
// Test Runtime.exec(...envp...) with envstrings containing NULs |
|
1589 |
//---------------------------------------------------------------- |
|
1590 |
try { |
|
1591 |
List<String> childArgs = new ArrayList<String>(javaChildArgs); |
|
1592 |
childArgs.add("System.getenv()"); |
|
1593 |
String[] cmdp = childArgs.toArray(new String[childArgs.size()]); |
|
1594 |
String[] envp = {"LC_ALL=C\u0000\u0000", // Yuck! |
|
1595 |
"FO\u0000=B\u0000R"}; |
|
1596 |
Process p = Runtime.getRuntime().exec(cmdp, envp); |
|
1597 |
check(commandOutput(p).equals("LC_ALL=C,"), |
|
1598 |
"Incorrect handling of envstrings containing NULs"); |
|
1599 |
} catch (Throwable t) { unexpected(t); } |
|
1600 |
||
1601 |
//---------------------------------------------------------------- |
|
1602 |
// Test the redirectErrorStream property |
|
1603 |
//---------------------------------------------------------------- |
|
1604 |
try { |
|
1605 |
ProcessBuilder pb = new ProcessBuilder(); |
|
1606 |
equal(pb.redirectErrorStream(), false); |
|
1607 |
equal(pb.redirectErrorStream(true), pb); |
|
1608 |
equal(pb.redirectErrorStream(), true); |
|
1609 |
equal(pb.redirectErrorStream(false), pb); |
|
1610 |
equal(pb.redirectErrorStream(), false); |
|
1611 |
} catch (Throwable t) { unexpected(t); } |
|
1612 |
||
1613 |
try { |
|
1614 |
List<String> childArgs = new ArrayList<String>(javaChildArgs); |
|
1615 |
childArgs.add("OutErr"); |
|
1616 |
ProcessBuilder pb = new ProcessBuilder(childArgs); |
|
1617 |
{ |
|
2946
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
1618 |
ProcessResults r = run(pb); |
2 | 1619 |
equal(r.out(), "outout"); |
1620 |
equal(r.err(), "errerr"); |
|
1621 |
} |
|
1622 |
{ |
|
1623 |
pb.redirectErrorStream(true); |
|
2946
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
1624 |
ProcessResults r = run(pb); |
2 | 1625 |
equal(r.out(), "outerrouterr"); |
1626 |
equal(r.err(), ""); |
|
1627 |
} |
|
1628 |
} catch (Throwable t) { unexpected(t); } |
|
1629 |
||
2946
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
1630 |
if (Unix.is()) { |
2 | 1631 |
//---------------------------------------------------------------- |
1632 |
// We can find true and false when PATH is null |
|
1633 |
//---------------------------------------------------------------- |
|
1634 |
try { |
|
1635 |
List<String> childArgs = new ArrayList<String>(javaChildArgs); |
|
1636 |
childArgs.add("null PATH"); |
|
1637 |
ProcessBuilder pb = new ProcessBuilder(childArgs); |
|
1638 |
pb.environment().remove("PATH"); |
|
2946
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
1639 |
ProcessResults r = run(pb); |
2 | 1640 |
equal(r.out(), ""); |
1641 |
equal(r.err(), ""); |
|
1642 |
equal(r.exitValue(), 0); |
|
1643 |
} catch (Throwable t) { unexpected(t); } |
|
1644 |
||
1645 |
//---------------------------------------------------------------- |
|
1646 |
// PATH search algorithm on Unix |
|
1647 |
//---------------------------------------------------------------- |
|
1648 |
try { |
|
1649 |
List<String> childArgs = new ArrayList<String>(javaChildArgs); |
|
1650 |
childArgs.add("PATH search algorithm"); |
|
1651 |
ProcessBuilder pb = new ProcessBuilder(childArgs); |
|
1652 |
pb.environment().put("PATH", "dir1:dir2:"); |
|
2946
f95752c3204a
6850720: (process) Use clone(CLONE_VM), not fork, on Linux to avoid swap exhaustion
martin
parents:
715
diff
changeset
|
1653 |
ProcessResults r = run(pb); |
2 | 1654 |
equal(r.out(), ""); |
1655 |
equal(r.err(), ""); |
|
1656 |
equal(r.exitValue(), True.exitValue()); |
|
1657 |
} catch (Throwable t) { unexpected(t); } |
|
1658 |
||
1659 |
//---------------------------------------------------------------- |
|
1660 |
// Parent's, not child's PATH is used |
|
1661 |
//---------------------------------------------------------------- |
|
1662 |
try { |
|
1663 |
new File("suBdiR").mkdirs(); |
|
1664 |
copy("/bin/true", "suBdiR/unliKely"); |
|
1665 |
final ProcessBuilder pb = |
|
1666 |
new ProcessBuilder(new String[]{"unliKely"}); |
|
1667 |
pb.environment().put("PATH", "suBdiR"); |
|
1668 |
THROWS(IOException.class, |
|
1669 |
new Fun() {void f() throws Throwable {pb.start();}}); |
|
1670 |
} catch (Throwable t) { unexpected(t); |
|
1671 |
} finally { |
|
1672 |
new File("suBdiR/unliKely").delete(); |
|
1673 |
new File("suBdiR").delete(); |
|
1674 |
} |
|
1675 |
} |
|
1676 |
||
1677 |
//---------------------------------------------------------------- |
|
1678 |
// Attempt to start bogus program "" |
|
1679 |
//---------------------------------------------------------------- |
|
1680 |
try { |
|
1681 |
new ProcessBuilder("").start(); |
|
1682 |
fail("Expected IOException not thrown"); |
|
1683 |
} catch (IOException e) { |
|
1684 |
String m = e.getMessage(); |
|
1685 |
if (EnglishUnix.is() && |
|
1686 |
! matches(m, "No such file or directory")) |
|
1687 |
unexpected(e); |
|
1688 |
} catch (Throwable t) { unexpected(t); } |
|
1689 |
||
1690 |
//---------------------------------------------------------------- |
|
1691 |
// Check that attempt to execute program name with funny |
|
1692 |
// characters throws an exception containing those characters. |
|
1693 |
//---------------------------------------------------------------- |
|
1694 |
for (String programName : new String[] {"\u00f0", "\u01f0"}) |
|
1695 |
try { |
|
1696 |
new ProcessBuilder(programName).start(); |
|
1697 |
fail("Expected IOException not thrown"); |
|
1698 |
} catch (IOException e) { |
|
1699 |
String m = e.getMessage(); |
|
1700 |
Pattern p = Pattern.compile(programName); |
|
1701 |
if (! matches(m, programName) |
|
1702 |
|| (EnglishUnix.is() |
|
1703 |
&& ! matches(m, "No such file or directory"))) |
|
1704 |
unexpected(e); |
|
1705 |
} catch (Throwable t) { unexpected(t); } |
|
1706 |
||
1707 |
//---------------------------------------------------------------- |
|
1708 |
// Attempt to start process in nonexistent directory fails. |
|
1709 |
//---------------------------------------------------------------- |
|
1710 |
try { |
|
1711 |
new ProcessBuilder("echo") |
|
1712 |
.directory(new File("UnLiKeLY")) |
|
1713 |
.start(); |
|
1714 |
fail("Expected IOException not thrown"); |
|
1715 |
} catch (IOException e) { |
|
1716 |
String m = e.getMessage(); |
|
1717 |
if (! matches(m, "in directory") |
|
1718 |
|| (EnglishUnix.is() && |
|
1719 |
! matches(m, "No such file or directory"))) |
|
1720 |
unexpected(e); |
|
1721 |
} catch (Throwable t) { unexpected(t); } |
|
1722 |
||
1723 |
//---------------------------------------------------------------- |
|
5786
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1724 |
// Attempt to write 4095 bytes to the pipe buffer without a |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1725 |
// reader to drain it would deadlock, if not for the fact that |
2 | 1726 |
// interprocess pipe buffers are at least 4096 bytes. |
5786
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1727 |
// |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1728 |
// Also, check that available reports all the bytes expected |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1729 |
// in the pipe buffer, and that I/O operations do the expected |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1730 |
// things. |
2 | 1731 |
//---------------------------------------------------------------- |
1732 |
try { |
|
1733 |
List<String> childArgs = new ArrayList<String>(javaChildArgs); |
|
1734 |
childArgs.add("print4095"); |
|
5786
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1735 |
final int SIZE = 4095; |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1736 |
final Process p = new ProcessBuilder(childArgs).start(); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1737 |
print4095(p.getOutputStream(), (byte) '!'); // Might hang! |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1738 |
p.waitFor(); // Might hang! |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1739 |
equal(SIZE, p.getInputStream().available()); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1740 |
equal(SIZE, p.getErrorStream().available()); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1741 |
THROWS(IOException.class, |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1742 |
new Fun(){void f() throws IOException { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1743 |
p.getOutputStream().write((byte) '!'); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1744 |
p.getOutputStream().flush(); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1745 |
}}); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1746 |
|
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1747 |
final byte[] bytes = new byte[SIZE + 1]; |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1748 |
equal(SIZE, p.getInputStream().read(bytes)); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1749 |
for (int i = 0; i < SIZE; i++) |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1750 |
equal((byte) '!', bytes[i]); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1751 |
equal((byte) 0, bytes[SIZE]); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1752 |
|
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1753 |
equal(SIZE, p.getErrorStream().read(bytes)); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1754 |
for (int i = 0; i < SIZE; i++) |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1755 |
equal((byte) 'E', bytes[i]); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1756 |
equal((byte) 0, bytes[SIZE]); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1757 |
|
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1758 |
equal(0, p.getInputStream().available()); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1759 |
equal(0, p.getErrorStream().available()); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1760 |
equal(-1, p.getErrorStream().read()); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1761 |
equal(-1, p.getInputStream().read()); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1762 |
|
2 | 1763 |
equal(p.exitValue(), 5); |
5786
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1764 |
|
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1765 |
p.getInputStream().close(); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1766 |
p.getErrorStream().close(); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1767 |
p.getOutputStream().close(); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1768 |
|
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1769 |
InputStream[] streams = { p.getInputStream(), p.getErrorStream() }; |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1770 |
for (final InputStream in : streams) { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1771 |
Fun[] ops = { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1772 |
new Fun(){void f() throws IOException { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1773 |
in.read(); }}, |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1774 |
new Fun(){void f() throws IOException { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1775 |
in.read(bytes); }}, |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1776 |
new Fun(){void f() throws IOException { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1777 |
in.available(); }} |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1778 |
}; |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1779 |
for (Fun op : ops) { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1780 |
try { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1781 |
op.f(); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1782 |
fail(); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1783 |
} catch (IOException expected) { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1784 |
check(expected.getMessage() |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1785 |
.matches("[Ss]tream [Cc]losed")); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1786 |
} |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1787 |
} |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1788 |
} |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1789 |
} catch (Throwable t) { unexpected(t); } |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1790 |
|
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1791 |
//---------------------------------------------------------------- |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1792 |
// Check that reads which are pending when Process.destroy is |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1793 |
// called, get EOF, not IOException("Stream closed"). |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1794 |
//---------------------------------------------------------------- |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1795 |
try { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1796 |
final int cases = 4; |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1797 |
for (int i = 0; i < cases; i++) { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1798 |
final int action = i; |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1799 |
List<String> childArgs = new ArrayList<String>(javaChildArgs); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1800 |
childArgs.add("sleep"); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1801 |
final byte[] bytes = new byte[10]; |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1802 |
final Process p = new ProcessBuilder(childArgs).start(); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1803 |
final CountDownLatch latch = new CountDownLatch(1); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1804 |
final Thread thread = new Thread() { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1805 |
public void run() { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1806 |
try { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1807 |
latch.countDown(); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1808 |
int r; |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1809 |
switch (action) { |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1810 |
case 0: r = p.getInputStream().read(); break; |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1811 |
case 1: r = p.getErrorStream().read(); break; |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1812 |
case 2: r = p.getInputStream().read(bytes); break; |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1813 |
case 3: r = p.getErrorStream().read(bytes); break; |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1814 |
default: throw new Error(); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1815 |
} |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1816 |
equal(-1, r); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1817 |
} catch (Throwable t) { unexpected(t); }}}; |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1818 |
|
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1819 |
thread.start(); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1820 |
latch.await(); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1821 |
Thread.sleep(10); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1822 |
p.destroy(); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1823 |
thread.join(); |
f60ef38202e7
6944584: Improvements to subprocess handling on Unix
martin
parents:
5627
diff
changeset
|
1824 |
} |
2 | 1825 |
} catch (Throwable t) { unexpected(t); } |
1826 |
||
1827 |
//---------------------------------------------------------------- |
|
6669
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1828 |
// Check that subprocesses which create subprocesses of their |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1829 |
// own do not cause parent to hang waiting for file |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1830 |
// descriptors to be closed. |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1831 |
//---------------------------------------------------------------- |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1832 |
try { |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1833 |
if (Unix.is() |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1834 |
&& new File("/bin/bash").exists() |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1835 |
&& new File("/bin/sleep").exists()) { |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1836 |
final String[] cmd = { "/bin/bash", "-c", "(/bin/sleep 6666)" }; |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1837 |
final ProcessBuilder pb = new ProcessBuilder(cmd); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1838 |
final Process p = pb.start(); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1839 |
final InputStream stdout = p.getInputStream(); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1840 |
final InputStream stderr = p.getErrorStream(); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1841 |
final OutputStream stdin = p.getOutputStream(); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1842 |
final Thread reader = new Thread() { |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1843 |
public void run() { |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1844 |
try { stdout.read(); } |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1845 |
catch (IOException e) { |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1846 |
// e.printStackTrace(); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1847 |
if (EnglishUnix.is() && |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1848 |
! (e.getMessage().matches(".*Bad file descriptor.*"))) |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1849 |
unexpected(e); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1850 |
} |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1851 |
catch (Throwable t) { unexpected(t); }}}; |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1852 |
reader.setDaemon(true); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1853 |
reader.start(); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1854 |
Thread.sleep(100); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1855 |
p.destroy(); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1856 |
// Subprocess is now dead, but file descriptors remain open. |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1857 |
check(p.waitFor() != 0); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1858 |
check(p.exitValue() != 0); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1859 |
stdout.close(); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1860 |
stderr.close(); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1861 |
stdin.close(); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1862 |
//---------------------------------------------------------- |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1863 |
// There remain unsolved issues with asynchronous close. |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1864 |
// Here's a highly non-portable experiment to demonstrate: |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1865 |
//---------------------------------------------------------- |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1866 |
if (Boolean.getBoolean("wakeupJeff!")) { |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1867 |
System.out.println("wakeupJeff!"); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1868 |
// Initialize signal handler for INTERRUPT_SIGNAL. |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1869 |
new FileInputStream("/bin/sleep").getChannel().close(); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1870 |
// Send INTERRUPT_SIGNAL to every thread in this java. |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1871 |
String[] wakeupJeff = { |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1872 |
"/bin/bash", "-c", |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1873 |
"/bin/ps --noheaders -Lfp $PPID | " + |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1874 |
"/usr/bin/perl -nale 'print $F[3]' | " + |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1875 |
// INTERRUPT_SIGNAL == 62 on my machine du jour. |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1876 |
"/usr/bin/xargs kill -62" |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1877 |
}; |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1878 |
new ProcessBuilder(wakeupJeff).start().waitFor(); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1879 |
// If wakeupJeff worked, reader probably got EBADF. |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1880 |
reader.join(); |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1881 |
} |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1882 |
} |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1883 |
} catch (Throwable t) { unexpected(t); } |
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1884 |
|
8f8d4d5768ae
6981138: (process) Process.waitFor() may hang if subprocess has live descendants (lnx)
martin
parents:
5786
diff
changeset
|
1885 |
//---------------------------------------------------------------- |
2 | 1886 |
// Attempt to start process with insufficient permissions fails. |
1887 |
//---------------------------------------------------------------- |
|
1888 |
try { |
|
1889 |
new File("emptyCommand").delete(); |
|
1890 |
new FileOutputStream("emptyCommand").close(); |
|
1891 |
new File("emptyCommand").setExecutable(false); |
|
1892 |
new ProcessBuilder("./emptyCommand").start(); |
|
1893 |
fail("Expected IOException not thrown"); |
|
1894 |
} catch (IOException e) { |
|
1895 |
new File("./emptyCommand").delete(); |
|
1896 |
String m = e.getMessage(); |
|
1897 |
if (EnglishUnix.is() && |
|
1898 |
! matches(m, "Permission denied")) |
|
1899 |
unexpected(e); |
|
1900 |
} catch (Throwable t) { unexpected(t); } |
|
1901 |
||
1902 |
new File("emptyCommand").delete(); |
|
1903 |
||
1904 |
//---------------------------------------------------------------- |
|
1905 |
// Check for correct security permission behavior |
|
1906 |
//---------------------------------------------------------------- |
|
1907 |
final Policy policy = new Policy(); |
|
1908 |
Policy.setPolicy(policy); |
|
1909 |
System.setSecurityManager(new SecurityManager()); |
|
1910 |
||
1911 |
try { |
|
1912 |
// No permissions required to CREATE a ProcessBuilder |
|
1913 |
policy.setPermissions(/* Nothing */); |
|
1914 |
new ProcessBuilder("env").directory(null).directory(); |
|
1915 |
new ProcessBuilder("env").directory(new File("dir")).directory(); |
|
1916 |
new ProcessBuilder("env").command("??").command(); |
|
1917 |
} catch (Throwable t) { unexpected(t); } |
|
1918 |
||
1919 |
THROWS(SecurityException.class, |
|
1920 |
new Fun() { void f() throws IOException { |
|
1921 |
policy.setPermissions(/* Nothing */); |
|
1922 |
System.getenv("foo");}}, |
|
1923 |
new Fun() { void f() throws IOException { |
|
1924 |
policy.setPermissions(/* Nothing */); |
|
1925 |
System.getenv();}}, |
|
1926 |
new Fun() { void f() throws IOException { |
|
1927 |
policy.setPermissions(/* Nothing */); |
|
1928 |
new ProcessBuilder("echo").start();}}, |
|
1929 |
new Fun() { void f() throws IOException { |
|
1930 |
policy.setPermissions(/* Nothing */); |
|
1931 |
Runtime.getRuntime().exec("echo");}}, |
|
1932 |
new Fun() { void f() throws IOException { |
|
1933 |
policy.setPermissions(new RuntimePermission("getenv.bar")); |
|
1934 |
System.getenv("foo");}}); |
|
1935 |
||
1936 |
try { |
|
1937 |
policy.setPermissions(new RuntimePermission("getenv.foo")); |
|
1938 |
System.getenv("foo"); |
|
1939 |
||
1940 |
policy.setPermissions(new RuntimePermission("getenv.*")); |
|
1941 |
System.getenv("foo"); |
|
1942 |
System.getenv(); |
|
1943 |
new ProcessBuilder().environment(); |
|
1944 |
} catch (Throwable t) { unexpected(t); } |
|
1945 |
||
1946 |
||
1947 |
final Permission execPermission |
|
1948 |
= new FilePermission("<<ALL FILES>>", "execute"); |
|
1949 |
||
1950 |
THROWS(SecurityException.class, |
|
1951 |
new Fun() { void f() throws IOException { |
|
1952 |
// environment permission by itself insufficient |
|
1953 |
policy.setPermissions(new RuntimePermission("getenv.*")); |
|
1954 |
ProcessBuilder pb = new ProcessBuilder("env"); |
|
1955 |
pb.environment().put("foo","bar"); |
|
1956 |
pb.start();}}, |
|
1957 |
new Fun() { void f() throws IOException { |
|
1958 |
// exec permission by itself insufficient |
|
1959 |
policy.setPermissions(execPermission); |
|
1960 |
ProcessBuilder pb = new ProcessBuilder("env"); |
|
1961 |
pb.environment().put("foo","bar"); |
|
1962 |
pb.start();}}); |
|
1963 |
||
1964 |
try { |
|
1965 |
// Both permissions? OK. |
|
1966 |
policy.setPermissions(new RuntimePermission("getenv.*"), |
|
1967 |
execPermission); |
|
1968 |
ProcessBuilder pb = new ProcessBuilder("env"); |
|
1969 |
pb.environment().put("foo","bar"); |
|
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1970 |
Process p = pb.start(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1971 |
closeStreams(p); |
2 | 1972 |
} catch (IOException e) { // OK |
1973 |
} catch (Throwable t) { unexpected(t); } |
|
1974 |
||
1975 |
try { |
|
1976 |
// Don't need environment permission unless READING environment |
|
1977 |
policy.setPermissions(execPermission); |
|
1978 |
Runtime.getRuntime().exec("env", new String[]{}); |
|
1979 |
} catch (IOException e) { // OK |
|
1980 |
} catch (Throwable t) { unexpected(t); } |
|
1981 |
||
1982 |
try { |
|
1983 |
// Don't need environment permission unless READING environment |
|
1984 |
policy.setPermissions(execPermission); |
|
1985 |
new ProcessBuilder("env").start(); |
|
1986 |
} catch (IOException e) { // OK |
|
1987 |
} catch (Throwable t) { unexpected(t); } |
|
1988 |
||
1989 |
// Restore "normal" state without a security manager |
|
1990 |
policy.setPermissions(new RuntimePermission("setSecurityManager")); |
|
1991 |
System.setSecurityManager(null); |
|
1992 |
||
1993 |
} |
|
1994 |
||
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1995 |
static void closeStreams(Process p) { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1996 |
try { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1997 |
p.getOutputStream().close(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1998 |
p.getInputStream().close(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
1999 |
p.getErrorStream().close(); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
2000 |
} catch (Throwable t) { unexpected(t); } |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
2001 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
2002 |
|
2 | 2003 |
//---------------------------------------------------------------- |
2004 |
// A Policy class designed to make permissions fiddling very easy. |
|
2005 |
//---------------------------------------------------------------- |
|
2006 |
private static class Policy extends java.security.Policy { |
|
2007 |
private Permissions perms; |
|
2008 |
||
2009 |
public void setPermissions(Permission...permissions) { |
|
2010 |
perms = new Permissions(); |
|
2011 |
for (Permission permission : permissions) |
|
2012 |
perms.add(permission); |
|
2013 |
} |
|
2014 |
||
2015 |
public Policy() { setPermissions(/* Nothing */); } |
|
2016 |
||
2017 |
public PermissionCollection getPermissions(CodeSource cs) { |
|
2018 |
return perms; |
|
2019 |
} |
|
2020 |
||
2021 |
public PermissionCollection getPermissions(ProtectionDomain pd) { |
|
2022 |
return perms; |
|
2023 |
} |
|
2024 |
||
2025 |
public boolean implies(ProtectionDomain pd, Permission p) { |
|
2026 |
return perms.implies(p); |
|
2027 |
} |
|
2028 |
||
2029 |
public void refresh() {} |
|
2030 |
} |
|
2031 |
||
2032 |
private static class StreamAccumulator extends Thread { |
|
2033 |
private final InputStream is; |
|
2034 |
private final StringBuilder sb = new StringBuilder(); |
|
2035 |
private Throwable throwable = null; |
|
2036 |
||
2037 |
public String result () throws Throwable { |
|
2038 |
if (throwable != null) |
|
2039 |
throw throwable; |
|
2040 |
return sb.toString(); |
|
2041 |
} |
|
2042 |
||
2043 |
StreamAccumulator (InputStream is) { |
|
2044 |
this.is = is; |
|
2045 |
} |
|
2046 |
||
2047 |
public void run() { |
|
2048 |
try { |
|
2049 |
Reader r = new InputStreamReader(is); |
|
2050 |
char[] buf = new char[4096]; |
|
2051 |
int n; |
|
2052 |
while ((n = r.read(buf)) > 0) { |
|
2053 |
sb.append(buf,0,n); |
|
2054 |
} |
|
2055 |
} catch (Throwable t) { |
|
2056 |
throwable = t; |
|
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
2057 |
} finally { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
2058 |
try { is.close(); } |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
2059 |
catch (Throwable t) { throwable = t; } |
2 | 2060 |
} |
2061 |
} |
|
2062 |
} |
|
2063 |
||
48
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
2064 |
static ProcessResults run(ProcessBuilder pb) { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
2065 |
try { |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
2066 |
return run(pb.start()); |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
2067 |
} catch (Throwable t) { unexpected(t); return null; } |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
2068 |
} |
dc5744ca15ea
4960438: (process) Need IO redirection API for subprocesses
martin
parents:
2
diff
changeset
|
2069 |
|
2 | 2070 |
private static ProcessResults run(Process p) { |
2071 |
Throwable throwable = null; |
|
2072 |
int exitValue = -1; |
|
2073 |
String out = ""; |
|
2074 |
String err = ""; |
|
2075 |
||
2076 |
StreamAccumulator outAccumulator = |
|
2077 |
new StreamAccumulator(p.getInputStream()); |
|
2078 |
StreamAccumulator errAccumulator = |
|
2079 |
new StreamAccumulator(p.getErrorStream()); |
|
2080 |
||
2081 |
try { |
|
2082 |
outAccumulator.start(); |
|
2083 |
errAccumulator.start(); |
|
2084 |
||
2085 |
exitValue = p.waitFor(); |
|
2086 |
||
2087 |
outAccumulator.join(); |
|
2088 |
errAccumulator.join(); |
|
2089 |
||
2090 |
out = outAccumulator.result(); |
|
2091 |
err = errAccumulator.result(); |
|
2092 |
} catch (Throwable t) { |
|
2093 |
throwable = t; |
|
2094 |
} |
|
2095 |
||
2096 |
return new ProcessResults(out, err, exitValue, throwable); |
|
2097 |
} |
|
2098 |
||
2099 |
//---------------------------------------------------------------- |
|
2100 |
// Results of a command |
|
2101 |
//---------------------------------------------------------------- |
|
2102 |
private static class ProcessResults { |
|
2103 |
private final String out; |
|
2104 |
private final String err; |
|
2105 |
private final int exitValue; |
|
2106 |
private final Throwable throwable; |
|
2107 |
||
2108 |
public ProcessResults(String out, |
|
2109 |
String err, |
|
2110 |
int exitValue, |
|
2111 |
Throwable throwable) { |
|
2112 |
this.out = out; |
|
2113 |
this.err = err; |
|
2114 |
this.exitValue = exitValue; |
|
2115 |
this.throwable = throwable; |
|
2116 |
} |
|
2117 |
||
2118 |
public String out() { return out; } |
|
2119 |
public String err() { return err; } |
|
2120 |
public int exitValue() { return exitValue; } |
|
2121 |
public Throwable throwable() { return throwable; } |
|
2122 |
||
2123 |
public String toString() { |
|
2124 |
StringBuilder sb = new StringBuilder(); |
|
2125 |
sb.append("<STDOUT>\n" + out() + "</STDOUT>\n") |
|
2126 |
.append("<STDERR>\n" + err() + "</STDERR>\n") |
|
2127 |
.append("exitValue = " + exitValue + "\n"); |
|
2128 |
if (throwable != null) |
|
2129 |
sb.append(throwable.getStackTrace()); |
|
2130 |
return sb.toString(); |
|
2131 |
} |
|
2132 |
} |
|
2133 |
||
2134 |
//--------------------- Infrastructure --------------------------- |
|
2135 |
static volatile int passed = 0, failed = 0; |
|
2136 |
static void pass() {passed++;} |
|
2137 |
static void fail() {failed++; Thread.dumpStack();} |
|
2138 |
static void fail(String msg) {System.out.println(msg); fail();} |
|
2139 |
static void unexpected(Throwable t) {failed++; t.printStackTrace();} |
|
2140 |
static void check(boolean cond) {if (cond) pass(); else fail();} |
|
2141 |
static void check(boolean cond, String m) {if (cond) pass(); else fail(m);} |
|
2142 |
static void equal(Object x, Object y) { |
|
2143 |
if (x == null ? y == null : x.equals(y)) pass(); |
|
2144 |
else fail(x + " not equal to " + y);} |
|
2145 |
public static void main(String[] args) throws Throwable { |
|
2146 |
try {realMain(args);} catch (Throwable t) {unexpected(t);} |
|
2147 |
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); |
|
2148 |
if (failed > 0) throw new AssertionError("Some tests failed");} |
|
2149 |
private static abstract class Fun {abstract void f() throws Throwable;} |
|
2150 |
static void THROWS(Class<? extends Throwable> k, Fun... fs) { |
|
2151 |
for (Fun f : fs) |
|
2152 |
try { f.f(); fail("Expected " + k.getName() + " not thrown"); } |
|
2153 |
catch (Throwable t) { |
|
2154 |
if (k.isAssignableFrom(t.getClass())) pass(); |
|
2155 |
else unexpected(t);}} |
|
2156 |
} |