PageRenderTime 77ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

/test/java/lang/ProcessBuilder/Basic.java

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