PageRenderTime 47ms CodeModel.GetById 36ms RepoModel.GetById 4ms app.codeStats 0ms

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

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