PageRenderTime 65ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

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

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