PageRenderTime 35ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

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

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