Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/lang/ProcessBuilder/Basic.java
41149 views
1
/*
2
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
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
*
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.
22
*/
23
24
/*
25
* @test
26
* @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689
27
* 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313
28
* 6464154 6523983 6206031 4960438 6631352 6631966 6850957 6850958
29
* 4947220 7018606 7034570 4244896 5049299 8003488 8054494 8058464
30
* 8067796 8224905 8263729 8265173
31
* @key intermittent
32
* @summary Basic tests for Process and Environment Variable code
33
* @modules java.base/java.lang:open
34
* @library /test/lib
35
* @run main/othervm/timeout=300 -Djava.security.manager=allow Basic
36
* @run main/othervm/timeout=300 -Djava.security.manager=allow -Djdk.lang.Process.launchMechanism=fork Basic
37
* @author Martin Buchholz
38
*/
39
40
/*
41
* @test
42
* @modules java.base/java.lang:open
43
* @requires (os.family == "linux")
44
* @library /test/lib
45
* @run main/othervm/timeout=300 -Djava.security.manager=allow -Djdk.lang.Process.launchMechanism=posix_spawn Basic
46
*/
47
48
import java.lang.ProcessBuilder.Redirect;
49
import java.lang.ProcessHandle;
50
import static java.lang.ProcessBuilder.Redirect.*;
51
52
import java.io.*;
53
import java.lang.reflect.Field;
54
import java.nio.file.Files;
55
import java.nio.file.Paths;
56
import java.nio.file.StandardCopyOption;
57
import java.util.*;
58
import java.util.concurrent.CountDownLatch;
59
import java.util.concurrent.TimeUnit;
60
import java.security.*;
61
import java.util.regex.Pattern;
62
import java.util.regex.Matcher;
63
import static java.lang.System.getenv;
64
import static java.lang.System.out;
65
import static java.lang.Boolean.TRUE;
66
import static java.util.AbstractMap.SimpleImmutableEntry;
67
68
import jdk.test.lib.Platform;
69
70
public class Basic {
71
72
/* used for Windows only */
73
static final String systemRoot = System.getenv("SystemRoot");
74
75
/* used for Mac OS X only */
76
static final String cfUserTextEncoding = System.getenv("__CF_USER_TEXT_ENCODING");
77
78
/* used for AIX only */
79
static final String libpath = System.getenv("LIBPATH");
80
81
/* Used for regex String matching for long error messages */
82
static final String PERMISSION_DENIED_ERROR_MSG = "(Permission denied|error=13)";
83
static final String NO_SUCH_FILE_ERROR_MSG = "(No such file|error=2)";
84
85
/**
86
* Returns the number of milliseconds since time given by
87
* startNanoTime, which must have been previously returned from a
88
* call to {@link System.nanoTime()}.
89
*/
90
private static long millisElapsedSince(long startNanoTime) {
91
return TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanoTime);
92
}
93
94
private static String commandOutput(Reader r) throws Throwable {
95
StringBuilder sb = new StringBuilder();
96
int c;
97
while ((c = r.read()) > 0)
98
if (c != '\r')
99
sb.append((char) c);
100
return sb.toString();
101
}
102
103
private static String commandOutput(Process p) throws Throwable {
104
check(p.getInputStream() == p.getInputStream());
105
check(p.getOutputStream() == p.getOutputStream());
106
check(p.getErrorStream() == p.getErrorStream());
107
Reader r = new InputStreamReader(p.getInputStream(),"UTF-8");
108
String output = commandOutput(r);
109
equal(p.waitFor(), 0);
110
equal(p.exitValue(), 0);
111
// The debug/fastdebug versions of the VM may write some warnings to stdout
112
// (i.e. "Warning: Cannot open log file: hotspot.log" if the VM is started
113
// in a directory without write permissions). These warnings will confuse tests
114
// which match the entire output of the child process so better filter them out.
115
return output.replaceAll("Warning:.*\\n", "");
116
}
117
118
private static String commandOutput(ProcessBuilder pb) {
119
try {
120
return commandOutput(pb.start());
121
} catch (Throwable t) {
122
String commandline = "";
123
for (String arg : pb.command())
124
commandline += " " + arg;
125
System.out.println("Exception trying to run process: " + commandline);
126
unexpected(t);
127
return "";
128
}
129
}
130
131
private static String commandOutput(String...command) {
132
try {
133
return commandOutput(Runtime.getRuntime().exec(command));
134
} catch (Throwable t) {
135
String commandline = "";
136
for (String arg : command)
137
commandline += " " + arg;
138
System.out.println("Exception trying to run process: " + commandline);
139
unexpected(t);
140
return "";
141
}
142
}
143
144
private static void checkCommandOutput(ProcessBuilder pb,
145
String expected,
146
String failureMsg) {
147
String got = commandOutput(pb);
148
check(got.equals(expected),
149
failureMsg + "\n" +
150
"Expected: \"" + expected + "\"\n" +
151
"Got: \"" + got + "\"");
152
}
153
154
private static String absolutifyPath(String path) {
155
StringBuilder sb = new StringBuilder();
156
for (String file : path.split(File.pathSeparator)) {
157
if (sb.length() != 0)
158
sb.append(File.pathSeparator);
159
sb.append(new File(file).getAbsolutePath());
160
}
161
return sb.toString();
162
}
163
164
// compare windows-style, by canonicalizing to upper case,
165
// not lower case as String.compareToIgnoreCase does
166
private static class WindowsComparator
167
implements Comparator<String> {
168
public int compare(String x, String y) {
169
return x.toUpperCase(Locale.US)
170
.compareTo(y.toUpperCase(Locale.US));
171
}
172
}
173
174
private static String sortedLines(String lines) {
175
String[] arr = lines.split("\n");
176
List<String> ls = new ArrayList<String>();
177
for (String s : arr)
178
ls.add(s);
179
Collections.sort(ls, new WindowsComparator());
180
StringBuilder sb = new StringBuilder();
181
for (String s : ls)
182
sb.append(s + "\n");
183
return sb.toString();
184
}
185
186
private static void compareLinesIgnoreCase(String lines1, String lines2) {
187
if (! (sortedLines(lines1).equalsIgnoreCase(sortedLines(lines2)))) {
188
String dashes =
189
"-----------------------------------------------------";
190
out.println(dashes);
191
out.print(sortedLines(lines1));
192
out.println(dashes);
193
out.print(sortedLines(lines2));
194
out.println(dashes);
195
out.println("sizes: " + sortedLines(lines1).length() +
196
" " + sortedLines(lines2).length());
197
198
fail("Sorted string contents differ");
199
}
200
}
201
202
private static final Runtime runtime = Runtime.getRuntime();
203
204
private static final String[] winEnvCommand = {"cmd.exe", "/c", "set"};
205
206
private static String winEnvFilter(String env) {
207
return env.replaceAll("\r", "")
208
.replaceAll("(?m)^(?:COMSPEC|PROMPT|PATHEXT)=.*\n","");
209
}
210
211
private static String unixEnvProg() {
212
return new File("/usr/bin/env").canExecute() ? "/usr/bin/env"
213
: "/bin/env";
214
}
215
216
private static String nativeEnv(String[] env) {
217
try {
218
if (Windows.is()) {
219
return winEnvFilter
220
(commandOutput(runtime.exec(winEnvCommand, env)));
221
} else {
222
return commandOutput(runtime.exec(unixEnvProg(), env));
223
}
224
} catch (Throwable t) { throw new Error(t); }
225
}
226
227
private static String nativeEnv(ProcessBuilder pb) {
228
try {
229
if (Windows.is()) {
230
pb.command(winEnvCommand);
231
return winEnvFilter(commandOutput(pb));
232
} else {
233
pb.command(new String[]{unixEnvProg()});
234
return commandOutput(pb);
235
}
236
} catch (Throwable t) { throw new Error(t); }
237
}
238
239
private static void checkSizes(Map<String,String> environ, int size) {
240
try {
241
equal(size, environ.size());
242
equal(size, environ.entrySet().size());
243
equal(size, environ.keySet().size());
244
equal(size, environ.values().size());
245
246
boolean isEmpty = (size == 0);
247
equal(isEmpty, environ.isEmpty());
248
equal(isEmpty, environ.entrySet().isEmpty());
249
equal(isEmpty, environ.keySet().isEmpty());
250
equal(isEmpty, environ.values().isEmpty());
251
} catch (Throwable t) { unexpected(t); }
252
}
253
254
private interface EnvironmentFrobber {
255
void doIt(Map<String,String> environ);
256
}
257
258
private static void testVariableDeleter(EnvironmentFrobber fooDeleter) {
259
try {
260
Map<String,String> environ = new ProcessBuilder().environment();
261
environ.put("Foo", "BAAR");
262
fooDeleter.doIt(environ);
263
equal(environ.get("Foo"), null);
264
equal(environ.remove("Foo"), null);
265
} catch (Throwable t) { unexpected(t); }
266
}
267
268
private static void testVariableAdder(EnvironmentFrobber fooAdder) {
269
try {
270
Map<String,String> environ = new ProcessBuilder().environment();
271
environ.remove("Foo");
272
fooAdder.doIt(environ);
273
equal(environ.get("Foo"), "Bahrein");
274
} catch (Throwable t) { unexpected(t); }
275
}
276
277
private static void testVariableModifier(EnvironmentFrobber fooModifier) {
278
try {
279
Map<String,String> environ = new ProcessBuilder().environment();
280
environ.put("Foo","OldValue");
281
fooModifier.doIt(environ);
282
equal(environ.get("Foo"), "NewValue");
283
} catch (Throwable t) { unexpected(t); }
284
}
285
286
private static void printUTF8(String s) throws IOException {
287
out.write(s.getBytes("UTF-8"));
288
}
289
290
private static String getenvAsString(Map<String,String> environment) {
291
StringBuilder sb = new StringBuilder();
292
environment = new TreeMap<>(environment);
293
for (Map.Entry<String,String> e : environment.entrySet())
294
// Ignore magic environment variables added by the launcher
295
if (! e.getKey().equals("LD_LIBRARY_PATH"))
296
sb.append(e.getKey())
297
.append('=')
298
.append(e.getValue())
299
.append(',');
300
return sb.toString();
301
}
302
303
static void print4095(OutputStream s, byte b) throws Throwable {
304
byte[] bytes = new byte[4095];
305
Arrays.fill(bytes, b);
306
s.write(bytes); // Might hang!
307
}
308
309
static void checkPermissionDenied(ProcessBuilder pb) {
310
try {
311
pb.start();
312
fail("Expected IOException not thrown");
313
} catch (IOException e) {
314
String m = e.getMessage();
315
if (EnglishUnix.is() &&
316
! matches(m, PERMISSION_DENIED_ERROR_MSG))
317
unexpected(e);
318
} catch (Throwable t) { unexpected(t); }
319
}
320
321
public static class JavaChild {
322
public static void main(String args[]) throws Throwable {
323
String action = args[0];
324
if (action.equals("sleep")) {
325
Thread.sleep(10 * 60 * 1000L);
326
} else if (action.equals("pid")) {
327
System.out.println(ProcessHandle.current().pid());
328
} else if (action.equals("testIO")) {
329
String expected = "standard input";
330
char[] buf = new char[expected.length()+1];
331
int n = new InputStreamReader(System.in).read(buf,0,buf.length);
332
if (n != expected.length())
333
System.exit(5);
334
if (! new String(buf,0,n).equals(expected))
335
System.exit(5);
336
System.err.print("standard error");
337
System.out.print("standard output");
338
} else if (action.equals("testInheritIO")
339
|| action.equals("testRedirectInherit")) {
340
List<String> childArgs = new ArrayList<String>(javaChildArgs);
341
childArgs.add("testIO");
342
ProcessBuilder pb = new ProcessBuilder(childArgs);
343
if (action.equals("testInheritIO"))
344
pb.inheritIO();
345
else
346
redirectIO(pb, INHERIT, INHERIT, INHERIT);
347
ProcessResults r = run(pb);
348
if (! r.out().equals(""))
349
System.exit(7);
350
if (! r.err().equals(""))
351
System.exit(8);
352
if (r.exitValue() != 0)
353
System.exit(9);
354
} else if (action.equals("System.getenv(String)")) {
355
String val = System.getenv(args[1]);
356
printUTF8(val == null ? "null" : val);
357
} else if (action.equals("System.getenv(\\u1234)")) {
358
String val = System.getenv("\u1234");
359
printUTF8(val == null ? "null" : val);
360
} else if (action.equals("System.getenv()")) {
361
printUTF8(getenvAsString(System.getenv()));
362
} else if (action.equals("ArrayOOME")) {
363
Object dummy;
364
switch(new Random().nextInt(3)) {
365
case 0: dummy = new Integer[Integer.MAX_VALUE]; break;
366
case 1: dummy = new double[Integer.MAX_VALUE]; break;
367
case 2: dummy = new byte[Integer.MAX_VALUE][]; break;
368
default: throw new InternalError();
369
}
370
} else if (action.equals("pwd")) {
371
printUTF8(new File(System.getProperty("user.dir"))
372
.getCanonicalPath());
373
} else if (action.equals("print4095")) {
374
print4095(System.out, (byte) '!');
375
print4095(System.err, (byte) 'E');
376
System.exit(5);
377
} else if (action.equals("OutErr")) {
378
// You might think the system streams would be
379
// buffered, and in fact they are implemented using
380
// BufferedOutputStream, but each and every print
381
// causes immediate operating system I/O.
382
System.out.print("out");
383
System.err.print("err");
384
System.out.print("out");
385
System.err.print("err");
386
} else if (action.equals("null PATH")) {
387
equal(System.getenv("PATH"), null);
388
check(new File("/bin/true").exists());
389
check(new File("/bin/false").exists());
390
ProcessBuilder pb1 = new ProcessBuilder();
391
ProcessBuilder pb2 = new ProcessBuilder();
392
pb2.environment().put("PATH", "anyOldPathIgnoredAnyways");
393
ProcessResults r;
394
395
for (final ProcessBuilder pb :
396
new ProcessBuilder[] {pb1, pb2}) {
397
pb.command("true");
398
equal(run(pb).exitValue(), True.exitValue());
399
400
pb.command("false");
401
equal(run(pb).exitValue(), False.exitValue());
402
}
403
404
if (failed != 0) throw new Error("null PATH");
405
} else if (action.equals("PATH search algorithm")) {
406
equal(System.getenv("PATH"), "dir1:dir2:");
407
check(new File(TrueExe.path()).exists());
408
check(new File(FalseExe.path()).exists());
409
String[] cmd = {"prog"};
410
ProcessBuilder pb1 = new ProcessBuilder(cmd);
411
ProcessBuilder pb2 = new ProcessBuilder(cmd);
412
ProcessBuilder pb3 = new ProcessBuilder(cmd);
413
pb2.environment().put("PATH", "anyOldPathIgnoredAnyways");
414
pb3.environment().remove("PATH");
415
416
for (final ProcessBuilder pb :
417
new ProcessBuilder[] {pb1, pb2, pb3}) {
418
try {
419
// Not on PATH at all; directories don't exist
420
try {
421
pb.start();
422
fail("Expected IOException not thrown");
423
} catch (IOException e) {
424
String m = e.getMessage();
425
if (EnglishUnix.is() &&
426
! matches(m, NO_SUCH_FILE_ERROR_MSG))
427
unexpected(e);
428
} catch (Throwable t) { unexpected(t); }
429
430
// Not on PATH at all; directories exist
431
new File("dir1").mkdirs();
432
new File("dir2").mkdirs();
433
try {
434
pb.start();
435
fail("Expected IOException not thrown");
436
} catch (IOException e) {
437
String m = e.getMessage();
438
if (EnglishUnix.is() &&
439
! matches(m, NO_SUCH_FILE_ERROR_MSG))
440
unexpected(e);
441
} catch (Throwable t) { unexpected(t); }
442
443
// Can't execute a directory -- permission denied
444
// Report EACCES errno
445
new File("dir1/prog").mkdirs();
446
checkPermissionDenied(pb);
447
448
// continue searching if EACCES
449
copy(TrueExe.path(), "dir2/prog");
450
equal(run(pb).exitValue(), True.exitValue());
451
new File("dir1/prog").delete();
452
new File("dir2/prog").delete();
453
454
new File("dir2/prog").mkdirs();
455
copy(TrueExe.path(), "dir1/prog");
456
equal(run(pb).exitValue(), True.exitValue());
457
458
// Check empty PATH component means current directory.
459
//
460
// While we're here, let's test different kinds of
461
// Unix executables, and PATH vs explicit searching.
462
new File("dir1/prog").delete();
463
new File("dir2/prog").delete();
464
for (String[] command :
465
new String[][] {
466
new String[] {"./prog"},
467
cmd}) {
468
pb.command(command);
469
File prog = new File("./prog");
470
// "Normal" binaries
471
copy(TrueExe.path(), "./prog");
472
equal(run(pb).exitValue(),
473
True.exitValue());
474
copy(FalseExe.path(), "./prog");
475
equal(run(pb).exitValue(),
476
False.exitValue());
477
prog.delete();
478
// Interpreter scripts with #!
479
setFileContents(prog, "#!/bin/true\n");
480
prog.setExecutable(true);
481
equal(run(pb).exitValue(),
482
True.exitValue());
483
prog.delete();
484
setFileContents(prog, "#!/bin/false\n");
485
prog.setExecutable(true);
486
equal(run(pb).exitValue(),
487
False.exitValue());
488
// Traditional shell scripts without #!
489
setFileContents(prog, "exec /bin/true\n");
490
prog.setExecutable(true);
491
equal(run(pb).exitValue(),
492
True.exitValue());
493
prog.delete();
494
setFileContents(prog, "exec /bin/false\n");
495
prog.setExecutable(true);
496
equal(run(pb).exitValue(),
497
False.exitValue());
498
prog.delete();
499
}
500
501
// Test Unix interpreter scripts
502
File dir1Prog = new File("dir1/prog");
503
dir1Prog.delete();
504
pb.command(new String[] {"prog", "world"});
505
setFileContents(dir1Prog, "#!/bin/echo hello\n");
506
checkPermissionDenied(pb);
507
dir1Prog.setExecutable(true);
508
equal(run(pb).out(), "hello dir1/prog world\n");
509
equal(run(pb).exitValue(), True.exitValue());
510
dir1Prog.delete();
511
pb.command(cmd);
512
513
// Test traditional shell scripts without #!
514
setFileContents(dir1Prog, "/bin/echo \"$@\"\n");
515
pb.command(new String[] {"prog", "hello", "world"});
516
checkPermissionDenied(pb);
517
dir1Prog.setExecutable(true);
518
equal(run(pb).out(), "hello world\n");
519
equal(run(pb).exitValue(), True.exitValue());
520
dir1Prog.delete();
521
pb.command(cmd);
522
523
// If prog found on both parent and child's PATH,
524
// parent's is used.
525
new File("dir1/prog").delete();
526
new File("dir2/prog").delete();
527
new File("prog").delete();
528
new File("dir3").mkdirs();
529
copy(TrueExe.path(), "dir1/prog");
530
copy(FalseExe.path(), "dir3/prog");
531
pb.environment().put("PATH","dir3");
532
equal(run(pb).exitValue(), True.exitValue());
533
copy(TrueExe.path(), "dir3/prog");
534
copy(FalseExe.path(), "dir1/prog");
535
equal(run(pb).exitValue(), False.exitValue());
536
537
} finally {
538
// cleanup
539
new File("dir1/prog").delete();
540
new File("dir2/prog").delete();
541
new File("dir3/prog").delete();
542
new File("dir1").delete();
543
new File("dir2").delete();
544
new File("dir3").delete();
545
new File("prog").delete();
546
}
547
}
548
549
if (failed != 0) throw new Error("PATH search algorithm");
550
}
551
else throw new Error("JavaChild invocation error");
552
}
553
}
554
555
private static void copy(String src, String dst) throws IOException {
556
Files.copy(Paths.get(src), Paths.get(dst),
557
StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
558
}
559
560
private static String javaChildOutput(ProcessBuilder pb, String...args) {
561
List<String> list = new ArrayList<String>(javaChildArgs);
562
for (String arg : args)
563
list.add(arg);
564
pb.command(list);
565
return commandOutput(pb);
566
}
567
568
private static String getenvInChild(ProcessBuilder pb) {
569
return javaChildOutput(pb, "System.getenv()");
570
}
571
572
private static String getenvInChild1234(ProcessBuilder pb) {
573
return javaChildOutput(pb, "System.getenv(\\u1234)");
574
}
575
576
private static String getenvInChild(ProcessBuilder pb, String name) {
577
return javaChildOutput(pb, "System.getenv(String)", name);
578
}
579
580
private static String pwdInChild(ProcessBuilder pb) {
581
return javaChildOutput(pb, "pwd");
582
}
583
584
private static final String javaExe =
585
System.getProperty("java.home") +
586
File.separator + "bin" + File.separator + "java";
587
588
private static final String classpath =
589
System.getProperty("java.class.path");
590
591
private static final List<String> javaChildArgs =
592
Arrays.asList(javaExe,
593
"-XX:+DisplayVMOutputToStderr",
594
"-classpath", absolutifyPath(classpath),
595
"Basic$JavaChild");
596
597
private static void testEncoding(String encoding, String tested) {
598
try {
599
// If round trip conversion works, should be able to set env vars
600
// correctly in child.
601
if (new String(tested.getBytes()).equals(tested)) {
602
out.println("Testing " + encoding + " environment values");
603
ProcessBuilder pb = new ProcessBuilder();
604
pb.environment().put("ASCIINAME",tested);
605
equal(getenvInChild(pb,"ASCIINAME"), tested);
606
}
607
} catch (Throwable t) { unexpected(t); }
608
}
609
610
static class Windows {
611
public static boolean is() { return is; }
612
private static final boolean is =
613
System.getProperty("os.name").startsWith("Windows");
614
}
615
616
static class AIX {
617
public static boolean is() { return is; }
618
private static final boolean is =
619
System.getProperty("os.name").equals("AIX");
620
}
621
622
static class Unix {
623
public static boolean is() { return is; }
624
private static final boolean is =
625
(! Windows.is() &&
626
new File("/bin/sh").exists() &&
627
new File("/bin/true").exists() &&
628
new File("/bin/false").exists());
629
}
630
631
static class UnicodeOS {
632
public static boolean is() { return is; }
633
private static final String osName = System.getProperty("os.name");
634
private static final boolean is =
635
// MacOS X would probably also qualify
636
osName.startsWith("Windows") &&
637
! osName.startsWith("Windows 9") &&
638
! osName.equals("Windows Me");
639
}
640
641
static class MacOSX {
642
public static boolean is() { return is; }
643
private static final String osName = System.getProperty("os.name");
644
private static final boolean is = osName.contains("OS X");
645
}
646
647
static class True {
648
public static int exitValue() { return 0; }
649
}
650
651
private static class False {
652
public static int exitValue() { return exitValue; }
653
private static final int exitValue = exitValue0();
654
private static int exitValue0() {
655
// /bin/false returns an *unspecified* non-zero number.
656
try {
657
if (! Unix.is())
658
return -1;
659
else {
660
int rc = new ProcessBuilder("/bin/false")
661
.start().waitFor();
662
check(rc != 0);
663
return rc;
664
}
665
} catch (Throwable t) { unexpected(t); return -1; }
666
}
667
}
668
669
// On Alpine Linux, /bin/true and /bin/false are just links to /bin/busybox.
670
// Some tests copy /bin/true and /bin/false to files with a different filename.
671
// However, copying the busbox executable into a file with a different name
672
// won't result in the expected return codes. As workaround, we create
673
// executable files that can be copied and produce the expected return
674
// values.
675
676
private static class TrueExe {
677
public static String path() { return path; }
678
private static final String path = path0();
679
private static String path0(){
680
if (!Platform.isBusybox("/bin/true")) {
681
return "/bin/true";
682
} else {
683
File trueExe = new File("true");
684
setFileContents(trueExe, "#!/bin/true\n");
685
trueExe.setExecutable(true);
686
return trueExe.getAbsolutePath();
687
}
688
}
689
}
690
691
private static class FalseExe {
692
public static String path() { return path; }
693
private static final String path = path0();
694
private static String path0(){
695
if (!Platform.isBusybox("/bin/false")) {
696
return "/bin/false";
697
} else {
698
File falseExe = new File("false");
699
setFileContents(falseExe, "#!/bin/false\n");
700
falseExe.setExecutable(true);
701
return falseExe.getAbsolutePath();
702
}
703
}
704
}
705
706
static class EnglishUnix {
707
private static final Boolean is =
708
(! Windows.is() && isEnglish("LANG") && isEnglish("LC_ALL"));
709
710
private static boolean isEnglish(String envvar) {
711
String val = getenv(envvar);
712
return (val == null) || val.matches("en.*") || val.matches("C");
713
}
714
715
/** Returns true if we can expect English OS error strings */
716
static boolean is() { return is; }
717
}
718
719
static class DelegatingProcess extends Process {
720
final Process p;
721
722
DelegatingProcess(Process p) {
723
this.p = p;
724
}
725
726
@Override
727
public void destroy() {
728
p.destroy();
729
}
730
731
@Override
732
public int exitValue() {
733
return p.exitValue();
734
}
735
736
@Override
737
public int waitFor() throws InterruptedException {
738
return p.waitFor();
739
}
740
741
@Override
742
public OutputStream getOutputStream() {
743
return p.getOutputStream();
744
}
745
746
@Override
747
public InputStream getInputStream() {
748
return p.getInputStream();
749
}
750
751
@Override
752
public InputStream getErrorStream() {
753
return p.getErrorStream();
754
}
755
}
756
757
private static boolean matches(String str, String regex) {
758
return Pattern.compile(regex).matcher(str).find();
759
}
760
761
private static String matchAndExtract(String str, String regex) {
762
Matcher matcher = Pattern.compile(regex).matcher(str);
763
if (matcher.find()) {
764
return matcher.group();
765
} else {
766
return "";
767
}
768
}
769
770
/* Only used for Mac OS X --
771
* Mac OS X (may) add the variable __CF_USER_TEXT_ENCODING to an empty
772
* environment. The environment variable JAVA_MAIN_CLASS_<pid> may also
773
* be set in Mac OS X.
774
* Remove them both from the list of env variables
775
*/
776
private static String removeMacExpectedVars(String vars) {
777
// Check for __CF_USER_TEXT_ENCODING
778
String cleanedVars = vars.replace("__CF_USER_TEXT_ENCODING="
779
+cfUserTextEncoding+",","");
780
// Check for JAVA_MAIN_CLASS_<pid>
781
String javaMainClassStr
782
= matchAndExtract(cleanedVars,
783
"JAVA_MAIN_CLASS_\\d+=Basic.JavaChild,");
784
return cleanedVars.replace(javaMainClassStr,"");
785
}
786
787
/* Only used for AIX --
788
* AIX adds the variable AIXTHREAD_GUARDPAGES=0 to the environment.
789
* Remove it from the list of env variables
790
*/
791
private static String removeAixExpectedVars(String vars) {
792
return vars.replace("AIXTHREAD_GUARDPAGES=0,", "");
793
}
794
795
private static String sortByLinesWindowsly(String text) {
796
String[] lines = text.split("\n");
797
Arrays.sort(lines, new WindowsComparator());
798
StringBuilder sb = new StringBuilder();
799
for (String line : lines)
800
sb.append(line).append("\n");
801
return sb.toString();
802
}
803
804
private static void checkMapSanity(Map<String,String> map) {
805
try {
806
Set<String> keySet = map.keySet();
807
Collection<String> values = map.values();
808
Set<Map.Entry<String,String>> entrySet = map.entrySet();
809
810
equal(entrySet.size(), keySet.size());
811
equal(entrySet.size(), values.size());
812
813
StringBuilder s1 = new StringBuilder();
814
for (Map.Entry<String,String> e : entrySet)
815
s1.append(e.getKey() + "=" + e.getValue() + "\n");
816
817
StringBuilder s2 = new StringBuilder();
818
for (String var : keySet)
819
s2.append(var + "=" + map.get(var) + "\n");
820
821
equal(s1.toString(), s2.toString());
822
823
Iterator<String> kIter = keySet.iterator();
824
Iterator<String> vIter = values.iterator();
825
Iterator<Map.Entry<String,String>> eIter = entrySet.iterator();
826
827
while (eIter.hasNext()) {
828
Map.Entry<String,String> entry = eIter.next();
829
String key = kIter.next();
830
String value = vIter.next();
831
check(entrySet.contains(entry));
832
check(keySet.contains(key));
833
check(values.contains(value));
834
check(map.containsKey(key));
835
check(map.containsValue(value));
836
equal(entry.getKey(), key);
837
equal(entry.getValue(), value);
838
}
839
check(!kIter.hasNext() &&
840
!vIter.hasNext());
841
842
} catch (Throwable t) { unexpected(t); }
843
}
844
845
private static void checkMapEquality(Map<String,String> map1,
846
Map<String,String> map2) {
847
try {
848
equal(map1.size(), map2.size());
849
equal(map1.isEmpty(), map2.isEmpty());
850
for (String key : map1.keySet()) {
851
equal(map1.get(key), map2.get(key));
852
check(map2.keySet().contains(key));
853
}
854
equal(map1, map2);
855
equal(map2, map1);
856
equal(map1.entrySet(), map2.entrySet());
857
equal(map2.entrySet(), map1.entrySet());
858
equal(map1.keySet(), map2.keySet());
859
equal(map2.keySet(), map1.keySet());
860
861
equal(map1.hashCode(), map2.hashCode());
862
equal(map1.entrySet().hashCode(), map2.entrySet().hashCode());
863
equal(map1.keySet().hashCode(), map2.keySet().hashCode());
864
} catch (Throwable t) { unexpected(t); }
865
}
866
867
static void checkRedirects(ProcessBuilder pb,
868
Redirect in, Redirect out, Redirect err) {
869
equal(pb.redirectInput(), in);
870
equal(pb.redirectOutput(), out);
871
equal(pb.redirectError(), err);
872
}
873
874
static void redirectIO(ProcessBuilder pb,
875
Redirect in, Redirect out, Redirect err) {
876
pb.redirectInput(in);
877
pb.redirectOutput(out);
878
pb.redirectError(err);
879
}
880
881
static void setFileContents(File file, String contents) {
882
try {
883
Writer w = new FileWriter(file);
884
w.write(contents);
885
w.close();
886
} catch (Throwable t) { unexpected(t); }
887
}
888
889
static String fileContents(File file) {
890
try {
891
Reader r = new FileReader(file);
892
StringBuilder sb = new StringBuilder();
893
char[] buffer = new char[1024];
894
int n;
895
while ((n = r.read(buffer)) != -1)
896
sb.append(buffer,0,n);
897
r.close();
898
return new String(sb);
899
} catch (Throwable t) { unexpected(t); return ""; }
900
}
901
902
static void testIORedirection() throws Throwable {
903
final File ifile = new File("ifile");
904
final File ofile = new File("ofile");
905
final File efile = new File("efile");
906
ifile.delete();
907
ofile.delete();
908
efile.delete();
909
910
//----------------------------------------------------------------
911
// Check mutual inequality of different types of Redirect
912
//----------------------------------------------------------------
913
Redirect[] redirects =
914
{ PIPE,
915
INHERIT,
916
DISCARD,
917
Redirect.from(ifile),
918
Redirect.to(ifile),
919
Redirect.appendTo(ifile),
920
Redirect.from(ofile),
921
Redirect.to(ofile),
922
Redirect.appendTo(ofile),
923
};
924
for (int i = 0; i < redirects.length; i++)
925
for (int j = 0; j < redirects.length; j++)
926
equal(redirects[i].equals(redirects[j]), (i == j));
927
928
//----------------------------------------------------------------
929
// Check basic properties of different types of Redirect
930
//----------------------------------------------------------------
931
equal(PIPE.type(), Redirect.Type.PIPE);
932
equal(PIPE.toString(), "PIPE");
933
equal(PIPE.file(), null);
934
935
equal(INHERIT.type(), Redirect.Type.INHERIT);
936
equal(INHERIT.toString(), "INHERIT");
937
equal(INHERIT.file(), null);
938
939
equal(DISCARD.type(), Redirect.Type.WRITE);
940
equal(DISCARD.toString(), "WRITE");
941
equal(DISCARD.file(), new File((Windows.is() ? "NUL" : "/dev/null")));
942
943
equal(Redirect.from(ifile).type(), Redirect.Type.READ);
944
equal(Redirect.from(ifile).toString(),
945
"redirect to read from file \"ifile\"");
946
equal(Redirect.from(ifile).file(), ifile);
947
equal(Redirect.from(ifile),
948
Redirect.from(ifile));
949
equal(Redirect.from(ifile).hashCode(),
950
Redirect.from(ifile).hashCode());
951
952
equal(Redirect.to(ofile).type(), Redirect.Type.WRITE);
953
equal(Redirect.to(ofile).toString(),
954
"redirect to write to file \"ofile\"");
955
equal(Redirect.to(ofile).file(), ofile);
956
equal(Redirect.to(ofile),
957
Redirect.to(ofile));
958
equal(Redirect.to(ofile).hashCode(),
959
Redirect.to(ofile).hashCode());
960
961
equal(Redirect.appendTo(ofile).type(), Redirect.Type.APPEND);
962
equal(Redirect.appendTo(efile).toString(),
963
"redirect to append to file \"efile\"");
964
equal(Redirect.appendTo(efile).file(), efile);
965
equal(Redirect.appendTo(efile),
966
Redirect.appendTo(efile));
967
equal(Redirect.appendTo(efile).hashCode(),
968
Redirect.appendTo(efile).hashCode());
969
970
//----------------------------------------------------------------
971
// Check initial values of redirects
972
//----------------------------------------------------------------
973
List<String> childArgs = new ArrayList<String>(javaChildArgs);
974
childArgs.add("testIO");
975
final ProcessBuilder pb = new ProcessBuilder(childArgs);
976
checkRedirects(pb, PIPE, PIPE, PIPE);
977
978
//----------------------------------------------------------------
979
// Check inheritIO
980
//----------------------------------------------------------------
981
pb.inheritIO();
982
checkRedirects(pb, INHERIT, INHERIT, INHERIT);
983
984
//----------------------------------------------------------------
985
// Check DISCARD for stdout,stderr
986
//----------------------------------------------------------------
987
redirectIO(pb, INHERIT, DISCARD, DISCARD);
988
checkRedirects(pb, INHERIT, DISCARD, DISCARD);
989
990
//----------------------------------------------------------------
991
// Check setters and getters agree
992
//----------------------------------------------------------------
993
pb.redirectInput(ifile);
994
equal(pb.redirectInput().file(), ifile);
995
equal(pb.redirectInput(), Redirect.from(ifile));
996
997
pb.redirectOutput(ofile);
998
equal(pb.redirectOutput().file(), ofile);
999
equal(pb.redirectOutput(), Redirect.to(ofile));
1000
1001
pb.redirectError(efile);
1002
equal(pb.redirectError().file(), efile);
1003
equal(pb.redirectError(), Redirect.to(efile));
1004
1005
THROWS(IllegalArgumentException.class,
1006
() -> pb.redirectInput(Redirect.to(ofile)),
1007
() -> pb.redirectOutput(Redirect.from(ifile)),
1008
() -> pb.redirectError(Redirect.from(ifile)),
1009
() -> pb.redirectInput(DISCARD));
1010
1011
THROWS(NullPointerException.class,
1012
() -> pb.redirectInput((File)null),
1013
() -> pb.redirectOutput((File)null),
1014
() -> pb.redirectError((File)null),
1015
() -> pb.redirectInput((Redirect)null),
1016
() -> pb.redirectOutput((Redirect)null),
1017
() -> pb.redirectError((Redirect)null));
1018
1019
THROWS(IOException.class,
1020
// Input file does not exist
1021
() -> pb.start());
1022
setFileContents(ifile, "standard input");
1023
1024
//----------------------------------------------------------------
1025
// Writing to non-existent files
1026
//----------------------------------------------------------------
1027
{
1028
ProcessResults r = run(pb);
1029
equal(r.exitValue(), 0);
1030
equal(fileContents(ofile), "standard output");
1031
equal(fileContents(efile), "standard error");
1032
equal(r.out(), "");
1033
equal(r.err(), "");
1034
ofile.delete();
1035
efile.delete();
1036
}
1037
1038
//----------------------------------------------------------------
1039
// Both redirectErrorStream + redirectError
1040
//----------------------------------------------------------------
1041
{
1042
pb.redirectErrorStream(true);
1043
ProcessResults r = run(pb);
1044
equal(r.exitValue(), 0);
1045
equal(fileContents(ofile),
1046
"standard error" + "standard output");
1047
equal(fileContents(efile), "");
1048
equal(r.out(), "");
1049
equal(r.err(), "");
1050
ofile.delete();
1051
efile.delete();
1052
}
1053
1054
//----------------------------------------------------------------
1055
// Appending to existing files
1056
//----------------------------------------------------------------
1057
{
1058
setFileContents(ofile, "ofile-contents");
1059
setFileContents(efile, "efile-contents");
1060
pb.redirectOutput(Redirect.appendTo(ofile));
1061
pb.redirectError(Redirect.appendTo(efile));
1062
pb.redirectErrorStream(false);
1063
ProcessResults r = run(pb);
1064
equal(r.exitValue(), 0);
1065
equal(fileContents(ofile),
1066
"ofile-contents" + "standard output");
1067
equal(fileContents(efile),
1068
"efile-contents" + "standard error");
1069
equal(r.out(), "");
1070
equal(r.err(), "");
1071
ofile.delete();
1072
efile.delete();
1073
}
1074
1075
//----------------------------------------------------------------
1076
// Replacing existing files
1077
//----------------------------------------------------------------
1078
{
1079
setFileContents(ofile, "ofile-contents");
1080
setFileContents(efile, "efile-contents");
1081
pb.redirectOutput(ofile);
1082
pb.redirectError(Redirect.to(efile));
1083
ProcessResults r = run(pb);
1084
equal(r.exitValue(), 0);
1085
equal(fileContents(ofile), "standard output");
1086
equal(fileContents(efile), "standard error");
1087
equal(r.out(), "");
1088
equal(r.err(), "");
1089
ofile.delete();
1090
efile.delete();
1091
}
1092
1093
//----------------------------------------------------------------
1094
// Appending twice to the same file?
1095
//----------------------------------------------------------------
1096
{
1097
setFileContents(ofile, "ofile-contents");
1098
setFileContents(efile, "efile-contents");
1099
Redirect appender = Redirect.appendTo(ofile);
1100
pb.redirectOutput(appender);
1101
pb.redirectError(appender);
1102
ProcessResults r = run(pb);
1103
equal(r.exitValue(), 0);
1104
equal(fileContents(ofile),
1105
"ofile-contents" +
1106
"standard error" +
1107
"standard output");
1108
equal(fileContents(efile), "efile-contents");
1109
equal(r.out(), "");
1110
equal(r.err(), "");
1111
ifile.delete();
1112
ofile.delete();
1113
efile.delete();
1114
}
1115
1116
//----------------------------------------------------------------
1117
// DISCARDing output
1118
//----------------------------------------------------------------
1119
{
1120
setFileContents(ifile, "standard input");
1121
pb.redirectOutput(DISCARD);
1122
pb.redirectError(DISCARD);
1123
ProcessResults r = run(pb);
1124
equal(r.exitValue(), 0);
1125
equal(r.out(), "");
1126
equal(r.err(), "");
1127
}
1128
1129
//----------------------------------------------------------------
1130
// DISCARDing output and redirecting error
1131
//----------------------------------------------------------------
1132
{
1133
setFileContents(ifile, "standard input");
1134
setFileContents(ofile, "ofile-contents");
1135
setFileContents(efile, "efile-contents");
1136
pb.redirectOutput(DISCARD);
1137
pb.redirectError(efile);
1138
ProcessResults r = run(pb);
1139
equal(r.exitValue(), 0);
1140
equal(fileContents(ofile), "ofile-contents");
1141
equal(fileContents(efile), "standard error");
1142
equal(r.out(), "");
1143
equal(r.err(), "");
1144
ofile.delete();
1145
efile.delete();
1146
}
1147
1148
//----------------------------------------------------------------
1149
// DISCARDing error and redirecting output
1150
//----------------------------------------------------------------
1151
{
1152
setFileContents(ifile, "standard input");
1153
setFileContents(ofile, "ofile-contents");
1154
setFileContents(efile, "efile-contents");
1155
pb.redirectOutput(ofile);
1156
pb.redirectError(DISCARD);
1157
ProcessResults r = run(pb);
1158
equal(r.exitValue(), 0);
1159
equal(fileContents(ofile), "standard output");
1160
equal(fileContents(efile), "efile-contents");
1161
equal(r.out(), "");
1162
equal(r.err(), "");
1163
ofile.delete();
1164
efile.delete();
1165
}
1166
1167
//----------------------------------------------------------------
1168
// DISCARDing output and merging error into output
1169
//----------------------------------------------------------------
1170
{
1171
setFileContents(ifile, "standard input");
1172
setFileContents(ofile, "ofile-contents");
1173
setFileContents(efile, "efile-contents");
1174
pb.redirectOutput(DISCARD);
1175
pb.redirectErrorStream(true);
1176
pb.redirectError(efile);
1177
ProcessResults r = run(pb);
1178
equal(r.exitValue(), 0);
1179
equal(fileContents(ofile), "ofile-contents"); // untouched
1180
equal(fileContents(efile), ""); // empty
1181
equal(r.out(), "");
1182
equal(r.err(), "");
1183
ifile.delete();
1184
ofile.delete();
1185
efile.delete();
1186
pb.redirectErrorStream(false); // reset for next test
1187
}
1188
1189
//----------------------------------------------------------------
1190
// Testing INHERIT is harder.
1191
// Note that this requires __FOUR__ nested JVMs involved in one test,
1192
// if you count the harness JVM.
1193
//----------------------------------------------------------------
1194
for (String testName : new String[] { "testInheritIO", "testRedirectInherit" } ) {
1195
redirectIO(pb, PIPE, PIPE, PIPE);
1196
List<String> command = pb.command();
1197
command.set(command.size() - 1, testName);
1198
Process p = pb.start();
1199
new PrintStream(p.getOutputStream()).print("standard input");
1200
p.getOutputStream().close();
1201
ProcessResults r = run(p);
1202
equal(r.exitValue(), 0);
1203
equal(r.out(), "standard output");
1204
equal(r.err(), "standard error");
1205
}
1206
1207
//----------------------------------------------------------------
1208
// Test security implications of I/O redirection
1209
//----------------------------------------------------------------
1210
1211
// Read access to current directory is always granted;
1212
// So create a tmpfile for input instead.
1213
final File tmpFile = File.createTempFile("Basic", "tmp");
1214
setFileContents(tmpFile, "standard input");
1215
1216
final Policy policy = new Policy();
1217
Policy.setPolicy(policy);
1218
System.setSecurityManager(new SecurityManager());
1219
try {
1220
final Permission xPermission
1221
= new FilePermission("<<ALL FILES>>", "execute");
1222
final Permission rxPermission
1223
= new FilePermission("<<ALL FILES>>", "read,execute");
1224
final Permission wxPermission
1225
= new FilePermission("<<ALL FILES>>", "write,execute");
1226
final Permission rwxPermission
1227
= new FilePermission("<<ALL FILES>>", "read,write,execute");
1228
1229
THROWS(SecurityException.class,
1230
() -> { policy.setPermissions(xPermission);
1231
redirectIO(pb, from(tmpFile), PIPE, PIPE);
1232
pb.start();},
1233
() -> { policy.setPermissions(rxPermission);
1234
redirectIO(pb, PIPE, to(ofile), PIPE);
1235
pb.start();},
1236
() -> { policy.setPermissions(rxPermission);
1237
redirectIO(pb, PIPE, PIPE, to(efile));
1238
pb.start();});
1239
1240
{
1241
policy.setPermissions(rxPermission);
1242
redirectIO(pb, from(tmpFile), PIPE, PIPE);
1243
ProcessResults r = run(pb);
1244
equal(r.out(), "standard output");
1245
equal(r.err(), "standard error");
1246
}
1247
1248
{
1249
policy.setPermissions(wxPermission);
1250
redirectIO(pb, PIPE, to(ofile), to(efile));
1251
Process p = pb.start();
1252
new PrintStream(p.getOutputStream()).print("standard input");
1253
p.getOutputStream().close();
1254
ProcessResults r = run(p);
1255
policy.setPermissions(rwxPermission);
1256
equal(fileContents(ofile), "standard output");
1257
equal(fileContents(efile), "standard error");
1258
}
1259
1260
{
1261
policy.setPermissions(rwxPermission);
1262
redirectIO(pb, from(tmpFile), to(ofile), to(efile));
1263
ProcessResults r = run(pb);
1264
policy.setPermissions(rwxPermission);
1265
equal(fileContents(ofile), "standard output");
1266
equal(fileContents(efile), "standard error");
1267
}
1268
1269
} finally {
1270
policy.setPermissions(new RuntimePermission("setSecurityManager"));
1271
System.setSecurityManager(null);
1272
tmpFile.delete();
1273
ifile.delete();
1274
ofile.delete();
1275
efile.delete();
1276
}
1277
}
1278
1279
static void checkProcessPid() {
1280
ProcessBuilder pb = new ProcessBuilder();
1281
List<String> list = new ArrayList<String>(javaChildArgs);
1282
list.add("pid");
1283
pb.command(list);
1284
try {
1285
Process p = pb.start();
1286
String s = commandOutput(p);
1287
long actualPid = Long.valueOf(s.trim());
1288
long expectedPid = p.pid();
1289
equal(actualPid, expectedPid);
1290
} catch (Throwable t) {
1291
unexpected(t);
1292
}
1293
1294
1295
// Test the default implementation of Process.getPid
1296
DelegatingProcess p = new DelegatingProcess(null);
1297
THROWS(UnsupportedOperationException.class,
1298
() -> p.pid(),
1299
() -> p.toHandle(),
1300
() -> p.supportsNormalTermination(),
1301
() -> p.children(),
1302
() -> p.descendants());
1303
1304
}
1305
1306
private static void realMain(String[] args) throws Throwable {
1307
if (Windows.is())
1308
System.out.println("This appears to be a Windows system.");
1309
if (Unix.is())
1310
System.out.println("This appears to be a Unix system.");
1311
if (UnicodeOS.is())
1312
System.out.println("This appears to be a Unicode-based OS.");
1313
1314
try { testIORedirection(); }
1315
catch (Throwable t) { unexpected(t); }
1316
1317
//----------------------------------------------------------------
1318
// Basic tests for getPid()
1319
//----------------------------------------------------------------
1320
checkProcessPid();
1321
1322
//----------------------------------------------------------------
1323
// Basic tests for setting, replacing and deleting envvars
1324
//----------------------------------------------------------------
1325
try {
1326
ProcessBuilder pb = new ProcessBuilder();
1327
Map<String,String> environ = pb.environment();
1328
1329
// New env var
1330
environ.put("QUUX", "BAR");
1331
equal(environ.get("QUUX"), "BAR");
1332
equal(getenvInChild(pb,"QUUX"), "BAR");
1333
1334
// Modify env var
1335
environ.put("QUUX","bear");
1336
equal(environ.get("QUUX"), "bear");
1337
equal(getenvInChild(pb,"QUUX"), "bear");
1338
checkMapSanity(environ);
1339
1340
// Remove env var
1341
environ.remove("QUUX");
1342
equal(environ.get("QUUX"), null);
1343
equal(getenvInChild(pb,"QUUX"), "null");
1344
checkMapSanity(environ);
1345
1346
// Remove non-existent env var
1347
environ.remove("QUUX");
1348
equal(environ.get("QUUX"), null);
1349
equal(getenvInChild(pb,"QUUX"), "null");
1350
checkMapSanity(environ);
1351
} catch (Throwable t) { unexpected(t); }
1352
1353
//----------------------------------------------------------------
1354
// Pass Empty environment to child
1355
//----------------------------------------------------------------
1356
try {
1357
ProcessBuilder pb = new ProcessBuilder();
1358
pb.environment().clear();
1359
String expected = Windows.is() ? "SystemRoot="+systemRoot+",": "";
1360
expected = AIX.is() ? "LIBPATH="+libpath+",": expected;
1361
if (Windows.is()) {
1362
pb.environment().put("SystemRoot", systemRoot);
1363
}
1364
if (AIX.is()) {
1365
pb.environment().put("LIBPATH", libpath);
1366
}
1367
String result = getenvInChild(pb);
1368
if (MacOSX.is()) {
1369
result = removeMacExpectedVars(result);
1370
}
1371
if (AIX.is()) {
1372
result = removeAixExpectedVars(result);
1373
}
1374
equal(result, expected);
1375
} catch (Throwable t) { unexpected(t); }
1376
1377
//----------------------------------------------------------------
1378
// System.getenv() is read-only.
1379
//----------------------------------------------------------------
1380
THROWS(UnsupportedOperationException.class,
1381
() -> getenv().put("FOO","BAR"),
1382
() -> getenv().remove("PATH"),
1383
() -> getenv().keySet().remove("PATH"),
1384
() -> getenv().values().remove("someValue"));
1385
1386
try {
1387
Collection<Map.Entry<String,String>> c = getenv().entrySet();
1388
if (! c.isEmpty())
1389
try {
1390
c.iterator().next().setValue("foo");
1391
fail("Expected UnsupportedOperationException not thrown");
1392
} catch (UnsupportedOperationException e) {} // OK
1393
} catch (Throwable t) { unexpected(t); }
1394
1395
//----------------------------------------------------------------
1396
// System.getenv() always returns the same object in our implementation.
1397
//----------------------------------------------------------------
1398
try {
1399
check(System.getenv() == System.getenv());
1400
} catch (Throwable t) { unexpected(t); }
1401
1402
//----------------------------------------------------------------
1403
// You can't create an env var name containing "=",
1404
// or an env var name or value containing NUL.
1405
//----------------------------------------------------------------
1406
{
1407
final Map<String,String> m = new ProcessBuilder().environment();
1408
THROWS(IllegalArgumentException.class,
1409
() -> m.put("FOO=","BAR"),
1410
() -> m.put("FOO\u0000","BAR"),
1411
() -> m.put("FOO","BAR\u0000"));
1412
}
1413
1414
//----------------------------------------------------------------
1415
// Commands must never be null.
1416
//----------------------------------------------------------------
1417
THROWS(NullPointerException.class,
1418
() -> new ProcessBuilder((List<String>)null),
1419
() -> new ProcessBuilder().command((List<String>)null));
1420
1421
//----------------------------------------------------------------
1422
// Put in a command; get the same one back out.
1423
//----------------------------------------------------------------
1424
try {
1425
List<String> command = new ArrayList<String>();
1426
ProcessBuilder pb = new ProcessBuilder(command);
1427
check(pb.command() == command);
1428
List<String> command2 = new ArrayList<String>(2);
1429
command2.add("foo");
1430
command2.add("bar");
1431
pb.command(command2);
1432
check(pb.command() == command2);
1433
pb.command("foo", "bar");
1434
check(pb.command() != command2 && pb.command().equals(command2));
1435
pb.command(command2);
1436
command2.add("baz");
1437
equal(pb.command().get(2), "baz");
1438
} catch (Throwable t) { unexpected(t); }
1439
1440
//----------------------------------------------------------------
1441
// Commands must contain at least one element.
1442
//----------------------------------------------------------------
1443
THROWS(IndexOutOfBoundsException.class,
1444
() -> new ProcessBuilder().start(),
1445
() -> new ProcessBuilder(new ArrayList<String>()).start(),
1446
() -> Runtime.getRuntime().exec(new String[]{}));
1447
1448
//----------------------------------------------------------------
1449
// Commands must not contain null elements at start() time.
1450
//----------------------------------------------------------------
1451
THROWS(NullPointerException.class,
1452
() -> new ProcessBuilder("foo",null,"bar").start(),
1453
() -> new ProcessBuilder((String)null).start(),
1454
() -> new ProcessBuilder(new String[]{null}).start(),
1455
() -> new ProcessBuilder(new String[]{"foo",null,"bar"}).start());
1456
1457
//----------------------------------------------------------------
1458
// Command lists are growable.
1459
//----------------------------------------------------------------
1460
try {
1461
new ProcessBuilder().command().add("foo");
1462
new ProcessBuilder("bar").command().add("foo");
1463
new ProcessBuilder(new String[]{"1","2"}).command().add("3");
1464
} catch (Throwable t) { unexpected(t); }
1465
1466
//----------------------------------------------------------------
1467
// Nulls in environment updates generate NullPointerException
1468
//----------------------------------------------------------------
1469
try {
1470
final Map<String,String> env = new ProcessBuilder().environment();
1471
THROWS(NullPointerException.class,
1472
() -> env.put("foo",null),
1473
() -> env.put(null,"foo"),
1474
() -> env.remove(null),
1475
() -> { for (Map.Entry<String,String> e : env.entrySet())
1476
e.setValue(null);},
1477
() -> Runtime.getRuntime().exec(new String[]{"foo"},
1478
new String[]{null}));
1479
} catch (Throwable t) { unexpected(t); }
1480
1481
//----------------------------------------------------------------
1482
// Non-String types in environment updates generate ClassCastException
1483
//----------------------------------------------------------------
1484
try {
1485
final Map<String,String> env = new ProcessBuilder().environment();
1486
THROWS(ClassCastException.class,
1487
() -> env.remove(TRUE),
1488
() -> env.keySet().remove(TRUE),
1489
() -> env.values().remove(TRUE),
1490
() -> env.entrySet().remove(TRUE));
1491
} catch (Throwable t) { unexpected(t); }
1492
1493
//----------------------------------------------------------------
1494
// Check query operations on environment maps
1495
//----------------------------------------------------------------
1496
try {
1497
List<Map<String,String>> envs =
1498
new ArrayList<Map<String,String>>(2);
1499
envs.add(System.getenv());
1500
envs.add(new ProcessBuilder().environment());
1501
for (final Map<String,String> env : envs) {
1502
//----------------------------------------------------------------
1503
// Nulls in environment queries are forbidden.
1504
//----------------------------------------------------------------
1505
THROWS(NullPointerException.class,
1506
() -> getenv(null),
1507
() -> env.get(null),
1508
() -> env.containsKey(null),
1509
() -> env.containsValue(null),
1510
() -> env.keySet().contains(null),
1511
() -> env.values().contains(null));
1512
1513
//----------------------------------------------------------------
1514
// Non-String types in environment queries are forbidden.
1515
//----------------------------------------------------------------
1516
THROWS(ClassCastException.class,
1517
() -> env.get(TRUE),
1518
() -> env.containsKey(TRUE),
1519
() -> env.containsValue(TRUE),
1520
() -> env.keySet().contains(TRUE),
1521
() -> env.values().contains(TRUE));
1522
1523
//----------------------------------------------------------------
1524
// Illegal String values in environment queries are (grumble) OK
1525
//----------------------------------------------------------------
1526
equal(env.get("\u0000"), null);
1527
check(! env.containsKey("\u0000"));
1528
check(! env.containsValue("\u0000"));
1529
check(! env.keySet().contains("\u0000"));
1530
check(! env.values().contains("\u0000"));
1531
}
1532
1533
} catch (Throwable t) { unexpected(t); }
1534
1535
try {
1536
final Set<Map.Entry<String,String>> entrySet =
1537
new ProcessBuilder().environment().entrySet();
1538
THROWS(NullPointerException.class,
1539
() -> entrySet.contains(null));
1540
THROWS(ClassCastException.class,
1541
() -> entrySet.contains(TRUE),
1542
() -> entrySet.contains(
1543
new SimpleImmutableEntry<Boolean,String>(TRUE,"")));
1544
1545
check(! entrySet.contains
1546
(new SimpleImmutableEntry<String,String>("", "")));
1547
} catch (Throwable t) { unexpected(t); }
1548
1549
//----------------------------------------------------------------
1550
// Put in a directory; get the same one back out.
1551
//----------------------------------------------------------------
1552
try {
1553
ProcessBuilder pb = new ProcessBuilder();
1554
File foo = new File("foo");
1555
equal(pb.directory(), null);
1556
equal(pb.directory(foo).directory(), foo);
1557
equal(pb.directory(null).directory(), null);
1558
} catch (Throwable t) { unexpected(t); }
1559
1560
//----------------------------------------------------------------
1561
// If round-trip conversion works, check envvar pass-through to child
1562
//----------------------------------------------------------------
1563
try {
1564
testEncoding("ASCII", "xyzzy");
1565
testEncoding("Latin1", "\u00f1\u00e1");
1566
testEncoding("Unicode", "\u22f1\u11e1");
1567
} catch (Throwable t) { unexpected(t); }
1568
1569
//----------------------------------------------------------------
1570
// A surprisingly large number of ways to delete an environment var.
1571
//----------------------------------------------------------------
1572
testVariableDeleter(new EnvironmentFrobber() {
1573
public void doIt(Map<String,String> environ) {
1574
environ.remove("Foo");}});
1575
1576
testVariableDeleter(new EnvironmentFrobber() {
1577
public void doIt(Map<String,String> environ) {
1578
environ.keySet().remove("Foo");}});
1579
1580
testVariableDeleter(new EnvironmentFrobber() {
1581
public void doIt(Map<String,String> environ) {
1582
environ.values().remove("BAAR");}});
1583
1584
testVariableDeleter(new EnvironmentFrobber() {
1585
public void doIt(Map<String,String> environ) {
1586
// Legally fabricate a ProcessEnvironment.StringEntry,
1587
// even though it's private.
1588
Map<String,String> environ2
1589
= new ProcessBuilder().environment();
1590
environ2.clear();
1591
environ2.put("Foo","BAAR");
1592
// Subtlety alert.
1593
Map.Entry<String,String> e
1594
= environ2.entrySet().iterator().next();
1595
environ.entrySet().remove(e);}});
1596
1597
testVariableDeleter(new EnvironmentFrobber() {
1598
public void doIt(Map<String,String> environ) {
1599
Map.Entry<String,String> victim = null;
1600
for (Map.Entry<String,String> e : environ.entrySet())
1601
if (e.getKey().equals("Foo"))
1602
victim = e;
1603
if (victim != null)
1604
environ.entrySet().remove(victim);}});
1605
1606
testVariableDeleter(new EnvironmentFrobber() {
1607
public void doIt(Map<String,String> environ) {
1608
Iterator<String> it = environ.keySet().iterator();
1609
while (it.hasNext()) {
1610
String val = it.next();
1611
if (val.equals("Foo"))
1612
it.remove();}}});
1613
1614
testVariableDeleter(new EnvironmentFrobber() {
1615
public void doIt(Map<String,String> environ) {
1616
Iterator<Map.Entry<String,String>> it
1617
= environ.entrySet().iterator();
1618
while (it.hasNext()) {
1619
Map.Entry<String,String> e = it.next();
1620
if (e.getKey().equals("Foo"))
1621
it.remove();}}});
1622
1623
testVariableDeleter(new EnvironmentFrobber() {
1624
public void doIt(Map<String,String> environ) {
1625
Iterator<String> it = environ.values().iterator();
1626
while (it.hasNext()) {
1627
String val = it.next();
1628
if (val.equals("BAAR"))
1629
it.remove();}}});
1630
1631
//----------------------------------------------------------------
1632
// A surprisingly small number of ways to add an environment var.
1633
//----------------------------------------------------------------
1634
testVariableAdder(new EnvironmentFrobber() {
1635
public void doIt(Map<String,String> environ) {
1636
environ.put("Foo","Bahrein");}});
1637
1638
//----------------------------------------------------------------
1639
// A few ways to modify an environment var.
1640
//----------------------------------------------------------------
1641
testVariableModifier(new EnvironmentFrobber() {
1642
public void doIt(Map<String,String> environ) {
1643
environ.put("Foo","NewValue");}});
1644
1645
testVariableModifier(new EnvironmentFrobber() {
1646
public void doIt(Map<String,String> environ) {
1647
for (Map.Entry<String,String> e : environ.entrySet())
1648
if (e.getKey().equals("Foo"))
1649
e.setValue("NewValue");}});
1650
1651
//----------------------------------------------------------------
1652
// Fiddle with environment sizes
1653
//----------------------------------------------------------------
1654
try {
1655
Map<String,String> environ = new ProcessBuilder().environment();
1656
int size = environ.size();
1657
checkSizes(environ, size);
1658
1659
environ.put("UnLiKeLYeNVIROmtNam", "someVal");
1660
checkSizes(environ, size+1);
1661
1662
// Check for environment independence
1663
new ProcessBuilder().environment().clear();
1664
1665
environ.put("UnLiKeLYeNVIROmtNam", "someOtherVal");
1666
checkSizes(environ, size+1);
1667
1668
environ.remove("UnLiKeLYeNVIROmtNam");
1669
checkSizes(environ, size);
1670
1671
environ.clear();
1672
checkSizes(environ, 0);
1673
1674
environ.clear();
1675
checkSizes(environ, 0);
1676
1677
environ = new ProcessBuilder().environment();
1678
environ.keySet().clear();
1679
checkSizes(environ, 0);
1680
1681
environ = new ProcessBuilder().environment();
1682
environ.entrySet().clear();
1683
checkSizes(environ, 0);
1684
1685
environ = new ProcessBuilder().environment();
1686
environ.values().clear();
1687
checkSizes(environ, 0);
1688
} catch (Throwable t) { unexpected(t); }
1689
1690
//----------------------------------------------------------------
1691
// Check that various map invariants hold
1692
//----------------------------------------------------------------
1693
checkMapSanity(new ProcessBuilder().environment());
1694
checkMapSanity(System.getenv());
1695
checkMapEquality(new ProcessBuilder().environment(),
1696
new ProcessBuilder().environment());
1697
1698
1699
//----------------------------------------------------------------
1700
// Check effects on external "env" command.
1701
//----------------------------------------------------------------
1702
try {
1703
Set<String> env1 = new HashSet<String>
1704
(Arrays.asList(nativeEnv((String[])null).split("\n")));
1705
1706
ProcessBuilder pb = new ProcessBuilder();
1707
pb.environment().put("QwErTyUiOp","AsDfGhJk");
1708
1709
Set<String> env2 = new HashSet<String>
1710
(Arrays.asList(nativeEnv(pb).split("\n")));
1711
1712
check(env2.size() == env1.size() + 1);
1713
env1.add("QwErTyUiOp=AsDfGhJk");
1714
check(env1.equals(env2));
1715
} catch (Throwable t) { unexpected(t); }
1716
1717
//----------------------------------------------------------------
1718
// Test Runtime.exec(...envp...)
1719
// Check for sort order of environment variables on Windows.
1720
//----------------------------------------------------------------
1721
try {
1722
String systemRoot = "SystemRoot=" + System.getenv("SystemRoot");
1723
// '+' < 'A' < 'Z' < '_' < 'a' < 'z' < '~'
1724
String[]envp = {"FOO=BAR","BAZ=GORP","QUUX=",
1725
"+=+", "_=_", "~=~", systemRoot};
1726
String output = nativeEnv(envp);
1727
String expected = "+=+\nBAZ=GORP\nFOO=BAR\nQUUX=\n"+systemRoot+"\n_=_\n~=~\n";
1728
// On Windows, Java must keep the environment sorted.
1729
// Order is random on Unix, so this test does the sort.
1730
if (! Windows.is())
1731
output = sortByLinesWindowsly(output);
1732
equal(output, expected);
1733
} catch (Throwable t) { unexpected(t); }
1734
1735
//----------------------------------------------------------------
1736
// Test Runtime.exec(...envp...)
1737
// and check SystemRoot gets set automatically on Windows
1738
//----------------------------------------------------------------
1739
try {
1740
if (Windows.is()) {
1741
String systemRoot = "SystemRoot=" + System.getenv("SystemRoot");
1742
String[]envp = {"FOO=BAR","BAZ=GORP","QUUX=",
1743
"+=+", "_=_", "~=~"};
1744
String output = nativeEnv(envp);
1745
String expected = "+=+\nBAZ=GORP\nFOO=BAR\nQUUX=\n"+systemRoot+"\n_=_\n~=~\n";
1746
equal(output, expected);
1747
}
1748
} catch (Throwable t) { unexpected(t); }
1749
1750
//----------------------------------------------------------------
1751
// System.getenv() must be consistent with System.getenv(String)
1752
//----------------------------------------------------------------
1753
try {
1754
for (Map.Entry<String,String> e : getenv().entrySet())
1755
equal(getenv(e.getKey()), e.getValue());
1756
} catch (Throwable t) { unexpected(t); }
1757
1758
//----------------------------------------------------------------
1759
// Fiddle with working directory in child
1760
//----------------------------------------------------------------
1761
try {
1762
String canonicalUserDir =
1763
new File(System.getProperty("user.dir")).getCanonicalPath();
1764
String[] sdirs = new String[]
1765
{".", "..", "/", "/bin",
1766
"C:", "c:", "C:/", "c:\\", "\\", "\\bin",
1767
"c:\\windows ", "c:\\Program Files", "c:\\Program Files\\" };
1768
for (String sdir : sdirs) {
1769
File dir = new File(sdir);
1770
if (! (dir.isDirectory() && dir.exists()))
1771
continue;
1772
out.println("Testing directory " + dir);
1773
//dir = new File(dir.getCanonicalPath());
1774
1775
ProcessBuilder pb = new ProcessBuilder();
1776
equal(pb.directory(), null);
1777
equal(pwdInChild(pb), canonicalUserDir);
1778
1779
pb.directory(dir);
1780
equal(pb.directory(), dir);
1781
equal(pwdInChild(pb), dir.getCanonicalPath());
1782
1783
pb.directory(null);
1784
equal(pb.directory(), null);
1785
equal(pwdInChild(pb), canonicalUserDir);
1786
1787
pb.directory(dir);
1788
}
1789
} catch (Throwable t) { unexpected(t); }
1790
1791
//----------------------------------------------------------------
1792
// Working directory with Unicode in child
1793
//----------------------------------------------------------------
1794
try {
1795
if (UnicodeOS.is()) {
1796
File dir = new File(System.getProperty("test.dir", "."),
1797
"ProcessBuilderDir\u4e00\u4e02");
1798
try {
1799
if (!dir.exists())
1800
dir.mkdir();
1801
out.println("Testing Unicode directory:" + dir);
1802
ProcessBuilder pb = new ProcessBuilder();
1803
pb.directory(dir);
1804
equal(pwdInChild(pb), dir.getCanonicalPath());
1805
} finally {
1806
if (dir.exists())
1807
dir.delete();
1808
}
1809
}
1810
} catch (Throwable t) { unexpected(t); }
1811
1812
//----------------------------------------------------------------
1813
// OOME in child allocating maximally sized array
1814
// Test for hotspot/jvmti bug 6850957
1815
//----------------------------------------------------------------
1816
try {
1817
List<String> list = new ArrayList<String>(javaChildArgs);
1818
list.add(1, String.format("-XX:OnOutOfMemoryError=%s -version",
1819
javaExe));
1820
list.add("ArrayOOME");
1821
ProcessResults r = run(new ProcessBuilder(list));
1822
check(r.err().contains("java.lang.OutOfMemoryError:"));
1823
check(r.err().contains(javaExe));
1824
check(r.err().contains(System.getProperty("java.version")));
1825
equal(r.exitValue(), 1);
1826
} catch (Throwable t) { unexpected(t); }
1827
1828
//----------------------------------------------------------------
1829
// Windows has tricky semi-case-insensitive semantics
1830
//----------------------------------------------------------------
1831
if (Windows.is())
1832
try {
1833
out.println("Running case insensitve variable tests");
1834
for (String[] namePair :
1835
new String[][]
1836
{ new String[]{"PATH","PaTh"},
1837
new String[]{"home","HOME"},
1838
new String[]{"SYSTEMROOT","SystemRoot"}}) {
1839
check((getenv(namePair[0]) == null &&
1840
getenv(namePair[1]) == null)
1841
||
1842
getenv(namePair[0]).equals(getenv(namePair[1])),
1843
"Windows environment variables are not case insensitive");
1844
}
1845
} catch (Throwable t) { unexpected(t); }
1846
1847
//----------------------------------------------------------------
1848
// Test proper Unicode child environment transfer
1849
//----------------------------------------------------------------
1850
if (UnicodeOS.is())
1851
try {
1852
ProcessBuilder pb = new ProcessBuilder();
1853
pb.environment().put("\u1234","\u5678");
1854
pb.environment().remove("PATH");
1855
equal(getenvInChild1234(pb), "\u5678");
1856
} catch (Throwable t) { unexpected(t); }
1857
1858
1859
//----------------------------------------------------------------
1860
// Test Runtime.exec(...envp...) with envstrings with initial `='
1861
//----------------------------------------------------------------
1862
try {
1863
List<String> childArgs = new ArrayList<String>(javaChildArgs);
1864
childArgs.add("System.getenv()");
1865
String[] cmdp = childArgs.toArray(new String[childArgs.size()]);
1866
String[] envp;
1867
String[] envpWin = {"=C:=\\", "=ExitValue=3", "SystemRoot="+systemRoot};
1868
String[] envpOth = {"=ExitValue=3", "=C:=\\"};
1869
if (Windows.is()) {
1870
envp = envpWin;
1871
} else {
1872
envp = envpOth;
1873
}
1874
Process p = Runtime.getRuntime().exec(cmdp, envp);
1875
String expected = Windows.is() ? "=C:=\\,=ExitValue=3,SystemRoot="+systemRoot+"," : "=C:=\\,";
1876
expected = AIX.is() ? expected + "LIBPATH="+libpath+",": expected;
1877
String commandOutput = commandOutput(p);
1878
if (MacOSX.is()) {
1879
commandOutput = removeMacExpectedVars(commandOutput);
1880
}
1881
if (AIX.is()) {
1882
commandOutput = removeAixExpectedVars(commandOutput);
1883
}
1884
equal(commandOutput, expected);
1885
if (Windows.is()) {
1886
ProcessBuilder pb = new ProcessBuilder(childArgs);
1887
pb.environment().clear();
1888
pb.environment().put("SystemRoot", systemRoot);
1889
pb.environment().put("=ExitValue", "3");
1890
pb.environment().put("=C:", "\\");
1891
equal(commandOutput(pb), expected);
1892
}
1893
} catch (Throwable t) { unexpected(t); }
1894
1895
//----------------------------------------------------------------
1896
// Test Runtime.exec(...envp...) with envstrings without any `='
1897
//----------------------------------------------------------------
1898
try {
1899
String[] cmdp = {"echo"};
1900
String[] envp = {"Hello", "World"}; // Yuck!
1901
Process p = Runtime.getRuntime().exec(cmdp, envp);
1902
equal(commandOutput(p), "\n");
1903
} catch (Throwable t) { unexpected(t); }
1904
1905
//----------------------------------------------------------------
1906
// Test Runtime.exec(...envp...) with envstrings containing NULs
1907
//----------------------------------------------------------------
1908
try {
1909
List<String> childArgs = new ArrayList<String>(javaChildArgs);
1910
childArgs.add("System.getenv()");
1911
String[] cmdp = childArgs.toArray(new String[childArgs.size()]);
1912
String[] envpWin = {"SystemRoot="+systemRoot, "LC_ALL=C\u0000\u0000", // Yuck!
1913
"FO\u0000=B\u0000R"};
1914
String[] envpOth = {"LC_ALL=C\u0000\u0000", // Yuck!
1915
"FO\u0000=B\u0000R"};
1916
String[] envp;
1917
if (Windows.is()) {
1918
envp = envpWin;
1919
} else {
1920
envp = envpOth;
1921
}
1922
System.out.println ("cmdp");
1923
for (int i=0; i<cmdp.length; i++) {
1924
System.out.printf ("cmdp %d: %s\n", i, cmdp[i]);
1925
}
1926
System.out.println ("envp");
1927
for (int i=0; i<envp.length; i++) {
1928
System.out.printf ("envp %d: %s\n", i, envp[i]);
1929
}
1930
Process p = Runtime.getRuntime().exec(cmdp, envp);
1931
String commandOutput = commandOutput(p);
1932
if (MacOSX.is()) {
1933
commandOutput = removeMacExpectedVars(commandOutput);
1934
}
1935
if (AIX.is()) {
1936
commandOutput = removeAixExpectedVars(commandOutput);
1937
}
1938
check(commandOutput.equals(Windows.is()
1939
? "LC_ALL=C,SystemRoot="+systemRoot+","
1940
: AIX.is()
1941
? "LC_ALL=C,LIBPATH="+libpath+","
1942
: "LC_ALL=C,"),
1943
"Incorrect handling of envstrings containing NULs");
1944
} catch (Throwable t) { unexpected(t); }
1945
1946
//----------------------------------------------------------------
1947
// Test the redirectErrorStream property
1948
//----------------------------------------------------------------
1949
try {
1950
ProcessBuilder pb = new ProcessBuilder();
1951
equal(pb.redirectErrorStream(), false);
1952
equal(pb.redirectErrorStream(true), pb);
1953
equal(pb.redirectErrorStream(), true);
1954
equal(pb.redirectErrorStream(false), pb);
1955
equal(pb.redirectErrorStream(), false);
1956
} catch (Throwable t) { unexpected(t); }
1957
1958
try {
1959
List<String> childArgs = new ArrayList<String>(javaChildArgs);
1960
childArgs.add("OutErr");
1961
ProcessBuilder pb = new ProcessBuilder(childArgs);
1962
{
1963
ProcessResults r = run(pb);
1964
equal(r.out(), "outout");
1965
equal(r.err(), "errerr");
1966
}
1967
{
1968
pb.redirectErrorStream(true);
1969
ProcessResults r = run(pb);
1970
equal(r.out(), "outerrouterr");
1971
equal(r.err(), "");
1972
}
1973
} catch (Throwable t) { unexpected(t); }
1974
1975
if (Unix.is()) {
1976
//----------------------------------------------------------------
1977
// We can find true and false when PATH is null
1978
//----------------------------------------------------------------
1979
try {
1980
List<String> childArgs = new ArrayList<String>(javaChildArgs);
1981
childArgs.add("null PATH");
1982
ProcessBuilder pb = new ProcessBuilder(childArgs);
1983
pb.environment().remove("PATH");
1984
ProcessResults r = run(pb);
1985
equal(r.out(), "");
1986
equal(r.err(), "");
1987
equal(r.exitValue(), 0);
1988
} catch (Throwable t) { unexpected(t); }
1989
1990
//----------------------------------------------------------------
1991
// PATH search algorithm on Unix
1992
//----------------------------------------------------------------
1993
try {
1994
List<String> childArgs = new ArrayList<String>(javaChildArgs);
1995
childArgs.add("PATH search algorithm");
1996
ProcessBuilder pb = new ProcessBuilder(childArgs);
1997
pb.environment().put("PATH", "dir1:dir2:");
1998
ProcessResults r = run(pb);
1999
equal(r.out(), "");
2000
equal(r.err(), "");
2001
equal(r.exitValue(), True.exitValue());
2002
} catch (Throwable t) { unexpected(t); }
2003
2004
//----------------------------------------------------------------
2005
// Parent's, not child's PATH is used
2006
//----------------------------------------------------------------
2007
try {
2008
new File("suBdiR").mkdirs();
2009
copy(TrueExe.path(), "suBdiR/unliKely");
2010
final ProcessBuilder pb =
2011
new ProcessBuilder(new String[]{"unliKely"});
2012
pb.environment().put("PATH", "suBdiR");
2013
THROWS(IOException.class, () -> pb.start());
2014
} catch (Throwable t) { unexpected(t);
2015
} finally {
2016
new File("suBdiR/unliKely").delete();
2017
new File("suBdiR").delete();
2018
}
2019
}
2020
2021
//----------------------------------------------------------------
2022
// Attempt to start bogus program ""
2023
//----------------------------------------------------------------
2024
try {
2025
new ProcessBuilder("").start();
2026
fail("Expected IOException not thrown");
2027
} catch (IOException e) {
2028
String m = e.getMessage();
2029
if (EnglishUnix.is() &&
2030
! matches(m, NO_SUCH_FILE_ERROR_MSG))
2031
unexpected(e);
2032
} catch (Throwable t) { unexpected(t); }
2033
2034
//----------------------------------------------------------------
2035
// Check that attempt to execute program name with funny
2036
// characters throws an exception containing those characters.
2037
//----------------------------------------------------------------
2038
for (String programName : new String[] {"\u00f0", "\u01f0"})
2039
try {
2040
new ProcessBuilder(programName).start();
2041
fail("Expected IOException not thrown");
2042
} catch (IOException e) {
2043
String m = e.getMessage();
2044
Pattern p = Pattern.compile(programName);
2045
if (! matches(m, programName)
2046
|| (EnglishUnix.is() &&
2047
! matches(m, NO_SUCH_FILE_ERROR_MSG)))
2048
unexpected(e);
2049
} catch (Throwable t) { unexpected(t); }
2050
2051
//----------------------------------------------------------------
2052
// Attempt to start process in nonexistent directory fails.
2053
//----------------------------------------------------------------
2054
try {
2055
new ProcessBuilder("echo")
2056
.directory(new File("UnLiKeLY"))
2057
.start();
2058
fail("Expected IOException not thrown");
2059
} catch (IOException e) {
2060
String m = e.getMessage();
2061
if (! matches(m, "in directory")
2062
|| (EnglishUnix.is() &&
2063
! matches(m, NO_SUCH_FILE_ERROR_MSG)))
2064
unexpected(e);
2065
} catch (Throwable t) { unexpected(t); }
2066
2067
//----------------------------------------------------------------
2068
// Attempt to write 4095 bytes to the pipe buffer without a
2069
// reader to drain it would deadlock, if not for the fact that
2070
// interprocess pipe buffers are at least 4096 bytes.
2071
//
2072
// Also, check that available reports all the bytes expected
2073
// in the pipe buffer, and that I/O operations do the expected
2074
// things.
2075
//----------------------------------------------------------------
2076
try {
2077
List<String> childArgs = new ArrayList<String>(javaChildArgs);
2078
childArgs.add("print4095");
2079
final int SIZE = 4095;
2080
final Process p = new ProcessBuilder(childArgs).start();
2081
print4095(p.getOutputStream(), (byte) '!'); // Might hang!
2082
p.waitFor(); // Might hang!
2083
equal(SIZE, p.getInputStream().available());
2084
equal(SIZE, p.getErrorStream().available());
2085
THROWS(IOException.class,
2086
() -> { p.getOutputStream().write((byte) '!');
2087
p.getOutputStream().flush();});
2088
2089
final byte[] bytes = new byte[SIZE + 1];
2090
equal(SIZE, p.getInputStream().read(bytes));
2091
for (int i = 0; i < SIZE; i++)
2092
equal((byte) '!', bytes[i]);
2093
equal((byte) 0, bytes[SIZE]);
2094
2095
equal(SIZE, p.getErrorStream().read(bytes));
2096
for (int i = 0; i < SIZE; i++)
2097
equal((byte) 'E', bytes[i]);
2098
equal((byte) 0, bytes[SIZE]);
2099
2100
equal(0, p.getInputStream().available());
2101
equal(0, p.getErrorStream().available());
2102
equal(-1, p.getErrorStream().read());
2103
equal(-1, p.getInputStream().read());
2104
2105
equal(p.exitValue(), 5);
2106
2107
p.getInputStream().close();
2108
p.getErrorStream().close();
2109
try { p.getOutputStream().close(); } catch (IOException flushFailed) { }
2110
2111
InputStream[] streams = { p.getInputStream(), p.getErrorStream() };
2112
for (final InputStream in : streams) {
2113
Fun[] ops = {
2114
() -> in.read(),
2115
() -> in.read(bytes),
2116
() -> in.available()
2117
};
2118
for (Fun op : ops) {
2119
try {
2120
op.f();
2121
fail();
2122
} catch (IOException expected) {
2123
check(expected.getMessage()
2124
.matches("[Ss]tream [Cc]losed"));
2125
}
2126
}
2127
}
2128
} catch (Throwable t) { unexpected(t); }
2129
2130
//----------------------------------------------------------------
2131
// Check that reads which are pending when Process.destroy is
2132
// called, get EOF, or IOException("Stream closed").
2133
//----------------------------------------------------------------
2134
try {
2135
final int cases = 4;
2136
for (int i = 0; i < cases; i++) {
2137
final int action = i;
2138
List<String> childArgs = new ArrayList<>(javaChildArgs);
2139
final ProcessBuilder pb = new ProcessBuilder(childArgs);
2140
{
2141
// Redirect any child VM error output away from the stream being tested
2142
// and to the log file. For background see:
2143
// 8231297: java/lang/ProcessBuilder/Basic.java test fails intermittently
2144
// Destroying the process may, depending on the timing, cause some output
2145
// from the child VM.
2146
// This test requires the thread reading from the subprocess be blocked
2147
// in the read from the subprocess; there should be no bytes to read.
2148
// Modify the argument list shared with ProcessBuilder to redirect VM output.
2149
assert (childArgs.get(1).equals("-XX:+DisplayVMOutputToStderr")) : "Expected arg 1 to be \"-XX:+DisplayVMOutputToStderr\"";
2150
switch (action & 0x1) {
2151
case 0:
2152
childArgs.set(1, "-XX:+DisplayVMOutputToStderr");
2153
childArgs.add(2, "-Xlog:all=warning:stderr");
2154
pb.redirectError(INHERIT);
2155
break;
2156
case 1:
2157
childArgs.set(1, "-XX:+DisplayVMOutputToStdout");
2158
childArgs.add(2, "-Xlog:all=warning:stdout");
2159
pb.redirectOutput(INHERIT);
2160
break;
2161
default:
2162
throw new Error();
2163
}
2164
}
2165
childArgs.add("sleep");
2166
final byte[] bytes = new byte[10];
2167
final Process p = pb.start();
2168
final CountDownLatch latch = new CountDownLatch(1);
2169
final InputStream s;
2170
switch (action & 0x1) {
2171
case 0: s = p.getInputStream(); break;
2172
case 1: s = p.getErrorStream(); break;
2173
default: throw new Error();
2174
}
2175
final Thread thread = new Thread() {
2176
public void run() {
2177
try {
2178
int r;
2179
latch.countDown();
2180
switch (action & 0x2) {
2181
case 0: r = s.read(); break;
2182
case 2: r = s.read(bytes); break;
2183
default: throw new Error();
2184
}
2185
if (r >= 0) {
2186
// The child sent unexpected output; print it to diagnose
2187
System.out.println("Unexpected child output:");
2188
if ((action & 0x2) == 0) {
2189
System.out.write(r); // Single character
2190
2191
} else {
2192
System.out.write(bytes, 0, r);
2193
}
2194
for (int c = s.read(); c >= 0; c = s.read())
2195
System.out.write(c);
2196
System.out.println("\nEND Child output.");
2197
}
2198
equal(-1, r);
2199
} catch (IOException ioe) {
2200
if (!ioe.getMessage().equals("Stream closed")) {
2201
// BufferedInputStream may throw IOE("Stream closed").
2202
unexpected(ioe);
2203
}
2204
} catch (Throwable t) { unexpected(t); }}};
2205
2206
thread.start();
2207
latch.await();
2208
Thread.sleep(10);
2209
2210
if (s instanceof BufferedInputStream) {
2211
// Wait until after the s.read occurs in "thread" by
2212
// checking when the input stream monitor is acquired
2213
// (BufferedInputStream.read is synchronized)
2214
while (!isLocked(s, 10)) {
2215
Thread.sleep(100);
2216
}
2217
}
2218
p.destroy();
2219
thread.join();
2220
}
2221
} catch (Throwable t) { unexpected(t); }
2222
2223
//----------------------------------------------------------------
2224
// Check that subprocesses which create subprocesses of their
2225
// own do not cause parent to hang waiting for file
2226
// descriptors to be closed.
2227
//----------------------------------------------------------------
2228
try {
2229
if (Unix.is()
2230
&& new File("/bin/bash").exists()
2231
&& new File("/bin/sleep").exists()) {
2232
// Notice that we only destroy the process created by us (i.e.
2233
// our child) but not our grandchild (i.e. '/bin/sleep'). So
2234
// pay attention that the grandchild doesn't run too long to
2235
// avoid polluting the process space with useless processes.
2236
// Running the grandchild for 60s should be more than enough.
2237
final String[] cmd = { "/bin/bash", "-c", "(/bin/sleep 60)" };
2238
final String[] cmdkill = { "/bin/bash", "-c", "(/usr/bin/pkill -f \"sleep 60\")" };
2239
final ProcessBuilder pb = new ProcessBuilder(cmd);
2240
final Process p = pb.start();
2241
final InputStream stdout = p.getInputStream();
2242
final InputStream stderr = p.getErrorStream();
2243
final OutputStream stdin = p.getOutputStream();
2244
final Thread reader = new Thread() {
2245
public void run() {
2246
try { stdout.read(); }
2247
catch (IOException e) {
2248
// Check that reader failed because stream was
2249
// asynchronously closed.
2250
// e.printStackTrace();
2251
String msg = e.getMessage();
2252
if (EnglishUnix.is() &&
2253
! (msg.matches(".*Bad file.*") ||
2254
msg.matches(".*Stream closed.*")))
2255
unexpected(e);
2256
}
2257
catch (Throwable t) { unexpected(t); }}};
2258
reader.setDaemon(true);
2259
reader.start();
2260
Thread.sleep(100);
2261
p.destroy();
2262
check(p.waitFor() != 0);
2263
check(p.exitValue() != 0);
2264
// Subprocess is now dead, but file descriptors remain open.
2265
// Make sure the test will fail if we don't manage to close
2266
// the open streams within 30 seconds. Notice that this time
2267
// must be shorter than the sleep time of the grandchild.
2268
Timer t = new Timer("test/java/lang/ProcessBuilder/Basic.java process reaper", true);
2269
t.schedule(new TimerTask() {
2270
public void run() {
2271
fail("Subprocesses which create subprocesses of " +
2272
"their own caused the parent to hang while " +
2273
"waiting for file descriptors to be closed.");
2274
System.exit(-1);
2275
}
2276
}, 30000);
2277
stdout.close();
2278
stderr.close();
2279
stdin.close();
2280
new ProcessBuilder(cmdkill).start();
2281
// All streams successfully closed so we can cancel the timer.
2282
t.cancel();
2283
//----------------------------------------------------------
2284
// There remain unsolved issues with asynchronous close.
2285
// Here's a highly non-portable experiment to demonstrate:
2286
//----------------------------------------------------------
2287
if (Boolean.getBoolean("wakeupJeff!")) {
2288
System.out.println("wakeupJeff!");
2289
// Initialize signal handler for INTERRUPT_SIGNAL.
2290
new FileInputStream("/bin/sleep").getChannel().close();
2291
// Send INTERRUPT_SIGNAL to every thread in this java.
2292
String[] wakeupJeff = {
2293
"/bin/bash", "-c",
2294
"/bin/ps --noheaders -Lfp $PPID | " +
2295
"/usr/bin/perl -nale 'print $F[3]' | " +
2296
// INTERRUPT_SIGNAL == 62 on my machine du jour.
2297
"/usr/bin/xargs kill -62"
2298
};
2299
new ProcessBuilder(wakeupJeff).start().waitFor();
2300
// If wakeupJeff worked, reader probably got EBADF.
2301
reader.join();
2302
}
2303
}
2304
2305
//----------------------------------------------------------------
2306
// Check the Process toString() method
2307
//----------------------------------------------------------------
2308
{
2309
List<String> childArgs = new ArrayList<String>(javaChildArgs);
2310
childArgs.add("testIO");
2311
ProcessBuilder pb = new ProcessBuilder(childArgs);
2312
pb.redirectInput(Redirect.PIPE);
2313
pb.redirectOutput(DISCARD);
2314
pb.redirectError(DISCARD);
2315
final Process p = pb.start();
2316
// Child process waits until it gets input
2317
String s = p.toString();
2318
check(s.contains("not exited"));
2319
check(s.contains("pid=" + p.pid() + ","));
2320
2321
new PrintStream(p.getOutputStream()).print("standard input");
2322
p.getOutputStream().close();
2323
2324
// Check the toString after it exits
2325
int exitValue = p.waitFor();
2326
s = p.toString();
2327
check(s.contains("pid=" + p.pid() + ","));
2328
check(s.contains("exitValue=" + exitValue) &&
2329
!s.contains("not exited"));
2330
}
2331
} catch (Throwable t) { unexpected(t); }
2332
2333
//----------------------------------------------------------------
2334
// Attempt to start process with insufficient permissions fails.
2335
//----------------------------------------------------------------
2336
try {
2337
new File("emptyCommand").delete();
2338
new FileOutputStream("emptyCommand").close();
2339
new File("emptyCommand").setExecutable(false);
2340
new ProcessBuilder("./emptyCommand").start();
2341
fail("Expected IOException not thrown");
2342
} catch (IOException e) {
2343
new File("./emptyCommand").delete();
2344
String m = e.getMessage();
2345
if (EnglishUnix.is() &&
2346
! matches(m, PERMISSION_DENIED_ERROR_MSG))
2347
unexpected(e);
2348
} catch (Throwable t) { unexpected(t); }
2349
2350
new File("emptyCommand").delete();
2351
2352
//----------------------------------------------------------------
2353
// Check for correct security permission behavior
2354
//----------------------------------------------------------------
2355
final Policy policy = new Policy();
2356
Policy.setPolicy(policy);
2357
System.setSecurityManager(new SecurityManager());
2358
2359
try {
2360
// No permissions required to CREATE a ProcessBuilder
2361
policy.setPermissions(/* Nothing */);
2362
new ProcessBuilder("env").directory(null).directory();
2363
new ProcessBuilder("env").directory(new File("dir")).directory();
2364
new ProcessBuilder("env").command("??").command();
2365
} catch (Throwable t) { unexpected(t); }
2366
2367
THROWS(SecurityException.class,
2368
() -> { policy.setPermissions(/* Nothing */);
2369
System.getenv("foo");},
2370
() -> { policy.setPermissions(/* Nothing */);
2371
System.getenv();},
2372
() -> { policy.setPermissions(/* Nothing */);
2373
new ProcessBuilder("echo").start();},
2374
() -> { policy.setPermissions(/* Nothing */);
2375
Runtime.getRuntime().exec("echo");},
2376
() -> { policy.setPermissions(
2377
new RuntimePermission("getenv.bar"));
2378
System.getenv("foo");});
2379
2380
try {
2381
policy.setPermissions(new RuntimePermission("getenv.foo"));
2382
System.getenv("foo");
2383
2384
policy.setPermissions(new RuntimePermission("getenv.*"));
2385
System.getenv("foo");
2386
System.getenv();
2387
new ProcessBuilder().environment();
2388
} catch (Throwable t) { unexpected(t); }
2389
2390
2391
final Permission execPermission
2392
= new FilePermission("<<ALL FILES>>", "execute");
2393
2394
THROWS(SecurityException.class,
2395
() -> { // environment permission by itself insufficient
2396
policy.setPermissions(new RuntimePermission("getenv.*"));
2397
ProcessBuilder pb = new ProcessBuilder("env");
2398
pb.environment().put("foo","bar");
2399
pb.start();},
2400
() -> { // exec permission by itself insufficient
2401
policy.setPermissions(execPermission);
2402
ProcessBuilder pb = new ProcessBuilder("env");
2403
pb.environment().put("foo","bar");
2404
pb.start();});
2405
2406
try {
2407
// Both permissions? OK.
2408
policy.setPermissions(new RuntimePermission("getenv.*"),
2409
execPermission);
2410
ProcessBuilder pb = new ProcessBuilder("env");
2411
pb.environment().put("foo","bar");
2412
Process p = pb.start();
2413
closeStreams(p);
2414
} catch (IOException e) { // OK
2415
} catch (Throwable t) { unexpected(t); }
2416
2417
try {
2418
// Don't need environment permission unless READING environment
2419
policy.setPermissions(execPermission);
2420
Runtime.getRuntime().exec("env", new String[]{});
2421
} catch (IOException e) { // OK
2422
} catch (Throwable t) { unexpected(t); }
2423
2424
try {
2425
// Don't need environment permission unless READING environment
2426
policy.setPermissions(execPermission);
2427
new ProcessBuilder("env").start();
2428
} catch (IOException e) { // OK
2429
} catch (Throwable t) { unexpected(t); }
2430
2431
// Restore "normal" state without a security manager
2432
policy.setPermissions(new RuntimePermission("setSecurityManager"));
2433
System.setSecurityManager(null);
2434
2435
//----------------------------------------------------------------
2436
// Check that Process.isAlive() &
2437
// Process.waitFor(0, TimeUnit.MILLISECONDS) work as expected.
2438
//----------------------------------------------------------------
2439
try {
2440
List<String> childArgs = new ArrayList<String>(javaChildArgs);
2441
childArgs.add("sleep");
2442
final Process p = new ProcessBuilder(childArgs).start();
2443
long start = System.nanoTime();
2444
if (!p.isAlive() || p.waitFor(0, TimeUnit.MILLISECONDS)) {
2445
fail("Test failed: Process exited prematurely");
2446
}
2447
long end = System.nanoTime();
2448
// give waitFor(timeout) a wide berth (2s)
2449
System.out.printf(" waitFor process: delta: %d%n",(end - start) );
2450
2451
if ((end - start) > TimeUnit.SECONDS.toNanos(2))
2452
fail("Test failed: waitFor took too long (" + (end - start) + "ns)");
2453
2454
p.destroy();
2455
p.waitFor();
2456
2457
if (p.isAlive() ||
2458
!p.waitFor(0, TimeUnit.MILLISECONDS))
2459
{
2460
fail("Test failed: Process still alive - please terminate " +
2461
p.toString() + " manually");
2462
}
2463
} catch (Throwable t) { unexpected(t); }
2464
2465
//----------------------------------------------------------------
2466
// Check that Process.waitFor(timeout, TimeUnit.MILLISECONDS)
2467
// works as expected.
2468
//----------------------------------------------------------------
2469
try {
2470
List<String> childArgs = new ArrayList<String>(javaChildArgs);
2471
childArgs.add("sleep");
2472
final Process p = new ProcessBuilder(childArgs).start();
2473
long start = System.nanoTime();
2474
2475
p.waitFor(10, TimeUnit.MILLISECONDS);
2476
2477
long end = System.nanoTime();
2478
if ((end - start) < TimeUnit.MILLISECONDS.toNanos(10))
2479
fail("Test failed: waitFor didn't take long enough (" + (end - start) + "ns)");
2480
2481
p.destroy();
2482
} catch (Throwable t) { unexpected(t); }
2483
2484
//----------------------------------------------------------------
2485
// Check that Process.waitFor(timeout, TimeUnit.MILLISECONDS)
2486
// interrupt works as expected, if interrupted while waiting.
2487
//----------------------------------------------------------------
2488
try {
2489
List<String> childArgs = new ArrayList<String>(javaChildArgs);
2490
childArgs.add("sleep");
2491
final Process p = new ProcessBuilder(childArgs).start();
2492
final long start = System.nanoTime();
2493
final CountDownLatch aboutToWaitFor = new CountDownLatch(1);
2494
2495
final Thread thread = new Thread() {
2496
public void run() {
2497
try {
2498
aboutToWaitFor.countDown();
2499
Thread.currentThread().interrupt();
2500
boolean result = p.waitFor(30L * 1000L, TimeUnit.MILLISECONDS);
2501
fail("waitFor() wasn't interrupted, its return value was: " + result);
2502
} catch (InterruptedException success) {
2503
} catch (Throwable t) { unexpected(t); }
2504
}
2505
};
2506
2507
thread.start();
2508
aboutToWaitFor.await();
2509
thread.interrupt();
2510
thread.join(10L * 1000L);
2511
check(millisElapsedSince(start) < 10L * 1000L);
2512
check(!thread.isAlive());
2513
p.destroy();
2514
} catch (Throwable t) { unexpected(t); }
2515
2516
//----------------------------------------------------------------
2517
// Check that Process.waitFor(Long.MAX_VALUE, TimeUnit.MILLISECONDS)
2518
// interrupt works as expected, if interrupted while waiting.
2519
//----------------------------------------------------------------
2520
try {
2521
List<String> childArgs = new ArrayList<String>(javaChildArgs);
2522
childArgs.add("sleep");
2523
final Process p = new ProcessBuilder(childArgs).start();
2524
final long start = System.nanoTime();
2525
final CountDownLatch aboutToWaitFor = new CountDownLatch(1);
2526
2527
final Thread thread = new Thread() {
2528
public void run() {
2529
try {
2530
aboutToWaitFor.countDown();
2531
Thread.currentThread().interrupt();
2532
boolean result = p.waitFor(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
2533
fail("waitFor() wasn't interrupted, its return value was: " + result);
2534
} catch (InterruptedException success) {
2535
} catch (Throwable t) { unexpected(t); }
2536
}
2537
};
2538
2539
thread.start();
2540
aboutToWaitFor.await();
2541
thread.interrupt();
2542
thread.join(10L * 1000L);
2543
check(millisElapsedSince(start) < 10L * 1000L);
2544
check(!thread.isAlive());
2545
p.destroy();
2546
} catch (Throwable t) { unexpected(t); }
2547
2548
//----------------------------------------------------------------
2549
// Check that Process.waitFor(timeout, TimeUnit.MILLISECONDS)
2550
// interrupt works as expected, if interrupted before waiting.
2551
//----------------------------------------------------------------
2552
try {
2553
List<String> childArgs = new ArrayList<String>(javaChildArgs);
2554
childArgs.add("sleep");
2555
final Process p = new ProcessBuilder(childArgs).start();
2556
final long start = System.nanoTime();
2557
final CountDownLatch threadStarted = new CountDownLatch(1);
2558
2559
final Thread thread = new Thread() {
2560
public void run() {
2561
try {
2562
threadStarted.countDown();
2563
do { Thread.yield(); }
2564
while (!Thread.currentThread().isInterrupted());
2565
boolean result = p.waitFor(30L * 1000L, TimeUnit.MILLISECONDS);
2566
fail("waitFor() wasn't interrupted, its return value was: " + result);
2567
} catch (InterruptedException success) {
2568
} catch (Throwable t) { unexpected(t); }
2569
}
2570
};
2571
2572
thread.start();
2573
threadStarted.await();
2574
thread.interrupt();
2575
thread.join(10L * 1000L);
2576
check(millisElapsedSince(start) < 10L * 1000L);
2577
check(!thread.isAlive());
2578
p.destroy();
2579
} catch (Throwable t) { unexpected(t); }
2580
2581
//----------------------------------------------------------------
2582
// Check that Process.waitFor(timeout, null) throws NPE.
2583
//----------------------------------------------------------------
2584
try {
2585
List<String> childArgs = new ArrayList<String>(javaChildArgs);
2586
childArgs.add("sleep");
2587
final Process p = new ProcessBuilder(childArgs).start();
2588
THROWS(NullPointerException.class,
2589
() -> p.waitFor(10L, null));
2590
THROWS(NullPointerException.class,
2591
() -> p.waitFor(0L, null));
2592
THROWS(NullPointerException.class,
2593
() -> p.waitFor(-1L, null));
2594
// Terminate process and recheck after it exits
2595
p.destroy();
2596
p.waitFor();
2597
THROWS(NullPointerException.class,
2598
() -> p.waitFor(10L, null));
2599
THROWS(NullPointerException.class,
2600
() -> p.waitFor(0L, null));
2601
THROWS(NullPointerException.class,
2602
() -> p.waitFor(-1L, null));
2603
} catch (Throwable t) { unexpected(t); }
2604
2605
//----------------------------------------------------------------
2606
// Check that default implementation of Process.waitFor(timeout, null) throws NPE.
2607
//----------------------------------------------------------------
2608
try {
2609
List<String> childArgs = new ArrayList<String>(javaChildArgs);
2610
childArgs.add("sleep");
2611
final Process proc = new ProcessBuilder(childArgs).start();
2612
final DelegatingProcess p = new DelegatingProcess(proc);
2613
2614
THROWS(NullPointerException.class,
2615
() -> p.waitFor(10L, null));
2616
THROWS(NullPointerException.class,
2617
() -> p.waitFor(0L, null));
2618
THROWS(NullPointerException.class,
2619
() -> p.waitFor(-1L, null));
2620
// Terminate process and recheck after it exits
2621
p.destroy();
2622
p.waitFor();
2623
THROWS(NullPointerException.class,
2624
() -> p.waitFor(10L, null));
2625
THROWS(NullPointerException.class,
2626
() -> p.waitFor(0L, null));
2627
THROWS(NullPointerException.class,
2628
() -> p.waitFor(-1L, null));
2629
} catch (Throwable t) { unexpected(t); }
2630
2631
//----------------------------------------------------------------
2632
// Check the default implementation for
2633
// Process.waitFor(long, TimeUnit)
2634
//----------------------------------------------------------------
2635
try {
2636
List<String> childArgs = new ArrayList<String>(javaChildArgs);
2637
childArgs.add("sleep");
2638
final Process proc = new ProcessBuilder(childArgs).start();
2639
DelegatingProcess p = new DelegatingProcess(proc);
2640
long start = System.nanoTime();
2641
2642
p.waitFor(1000, TimeUnit.MILLISECONDS);
2643
2644
long end = System.nanoTime();
2645
if ((end - start) < 500000000)
2646
fail("Test failed: waitFor didn't take long enough");
2647
2648
p.destroy();
2649
2650
p.waitFor(1000, TimeUnit.MILLISECONDS);
2651
} catch (Throwable t) { unexpected(t); }
2652
}
2653
2654
static void closeStreams(Process p) {
2655
try {
2656
p.getOutputStream().close();
2657
p.getInputStream().close();
2658
p.getErrorStream().close();
2659
} catch (Throwable t) { unexpected(t); }
2660
}
2661
2662
//----------------------------------------------------------------
2663
// A Policy class designed to make permissions fiddling very easy.
2664
//----------------------------------------------------------------
2665
private static class Policy extends java.security.Policy {
2666
static final java.security.Policy DEFAULT_POLICY = java.security.Policy.getPolicy();
2667
2668
private Permissions perms;
2669
2670
public void setPermissions(Permission...permissions) {
2671
perms = new Permissions();
2672
for (Permission permission : permissions)
2673
perms.add(permission);
2674
}
2675
2676
public Policy() { setPermissions(/* Nothing */); }
2677
2678
public PermissionCollection getPermissions(CodeSource cs) {
2679
return perms;
2680
}
2681
2682
public PermissionCollection getPermissions(ProtectionDomain pd) {
2683
return perms;
2684
}
2685
2686
public boolean implies(ProtectionDomain pd, Permission p) {
2687
return perms.implies(p) || DEFAULT_POLICY.implies(pd, p);
2688
}
2689
2690
public void refresh() {}
2691
}
2692
2693
private static class StreamAccumulator extends Thread {
2694
private final InputStream is;
2695
private final StringBuilder sb = new StringBuilder();
2696
private Throwable throwable = null;
2697
2698
public String result () throws Throwable {
2699
if (throwable != null)
2700
throw throwable;
2701
return sb.toString();
2702
}
2703
2704
StreamAccumulator (InputStream is) {
2705
this.is = is;
2706
}
2707
2708
public void run() {
2709
try {
2710
Reader r = new InputStreamReader(is);
2711
char[] buf = new char[4096];
2712
int n;
2713
while ((n = r.read(buf)) > 0) {
2714
sb.append(buf,0,n);
2715
}
2716
} catch (Throwable t) {
2717
throwable = t;
2718
} finally {
2719
try { is.close(); }
2720
catch (Throwable t) { throwable = t; }
2721
}
2722
}
2723
}
2724
2725
static ProcessResults run(ProcessBuilder pb) {
2726
try {
2727
return run(pb.start());
2728
} catch (Throwable t) { unexpected(t); return null; }
2729
}
2730
2731
private static ProcessResults run(Process p) {
2732
Throwable throwable = null;
2733
int exitValue = -1;
2734
String out = "";
2735
String err = "";
2736
2737
StreamAccumulator outAccumulator =
2738
new StreamAccumulator(p.getInputStream());
2739
StreamAccumulator errAccumulator =
2740
new StreamAccumulator(p.getErrorStream());
2741
2742
try {
2743
outAccumulator.start();
2744
errAccumulator.start();
2745
2746
exitValue = p.waitFor();
2747
2748
outAccumulator.join();
2749
errAccumulator.join();
2750
2751
out = outAccumulator.result();
2752
err = errAccumulator.result();
2753
} catch (Throwable t) {
2754
throwable = t;
2755
}
2756
2757
return new ProcessResults(out, err, exitValue, throwable);
2758
}
2759
2760
//----------------------------------------------------------------
2761
// Results of a command
2762
//----------------------------------------------------------------
2763
private static class ProcessResults {
2764
private final String out;
2765
private final String err;
2766
private final int exitValue;
2767
private final Throwable throwable;
2768
2769
public ProcessResults(String out,
2770
String err,
2771
int exitValue,
2772
Throwable throwable) {
2773
this.out = out;
2774
this.err = err;
2775
this.exitValue = exitValue;
2776
this.throwable = throwable;
2777
}
2778
2779
public String out() { return out; }
2780
public String err() { return err; }
2781
public int exitValue() { return exitValue; }
2782
public Throwable throwable() { return throwable; }
2783
2784
public String toString() {
2785
StringBuilder sb = new StringBuilder();
2786
sb.append("<STDOUT>\n" + out() + "</STDOUT>\n")
2787
.append("<STDERR>\n" + err() + "</STDERR>\n")
2788
.append("exitValue = " + exitValue + "\n");
2789
if (throwable != null)
2790
sb.append(throwable.getStackTrace());
2791
return sb.toString();
2792
}
2793
}
2794
2795
//--------------------- Infrastructure ---------------------------
2796
static volatile int passed = 0, failed = 0;
2797
static void pass() {passed++;}
2798
static void fail() {failed++; Thread.dumpStack();}
2799
static void fail(String msg) {System.err.println(msg); fail();}
2800
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
2801
static void check(boolean cond) {if (cond) pass(); else fail();}
2802
static void check(boolean cond, String m) {if (cond) pass(); else fail(m);}
2803
static void equal(Object x, Object y) {
2804
if (x == null ? y == null : x.equals(y)) pass();
2805
else fail(">'" + x + "'<" + " not equal to " + "'" + y + "'");}
2806
2807
public static void main(String[] args) throws Throwable {
2808
try {realMain(args);} catch (Throwable t) {unexpected(t);}
2809
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
2810
if (failed > 0) throw new AssertionError("Some tests failed");}
2811
interface Fun {void f() throws Throwable;}
2812
static void THROWS(Class<? extends Throwable> k, Fun... fs) {
2813
for (Fun f : fs)
2814
try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
2815
catch (Throwable t) {
2816
if (k.isAssignableFrom(t.getClass())) pass();
2817
else unexpected(t);}}
2818
2819
static boolean isLocked(final Object monitor, final long millis) throws InterruptedException {
2820
return new Thread() {
2821
volatile boolean unlocked;
2822
2823
@Override
2824
public void run() {
2825
synchronized (monitor) { unlocked = true; }
2826
}
2827
2828
boolean isLocked() throws InterruptedException {
2829
start();
2830
join(millis);
2831
return !unlocked;
2832
}
2833
}.isLocked();
2834
}
2835
}
2836
2837