PageRenderTime 69ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/java-1.7.0-openjdk/openjdk/jdk/test/java/lang/ProcessBuilder/Basic.java

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