PageRenderTime 67ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

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

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