PageRenderTime 45ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/MRI-J/jdk/test/java/lang/ProcessBuilder/Basic.java

http://github.com/GregBowyer/ManagedRuntimeInitiative
Java | 1525 lines | 1132 code | 185 blank | 208 comment | 121 complexity | 3d55f8a0b0f1e3050b3ac033dccea565 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-3.0
  1. /*
  2. * Copyright 2003-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20. * CA 95054 USA or visit www.sun.com if you need additional information or
  21. * have any 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
  28. * @summary Basic tests for Process and Environment Variable code
  29. * @run main/othervm Basic
  30. * @author Martin Buchholz
  31. */
  32. import java.io.*;
  33. import java.util.*;
  34. import java.security.*;
  35. import java.util.regex.Pattern;
  36. import static java.lang.System.getenv;
  37. import static java.lang.System.out;
  38. import static java.lang.Boolean.TRUE;
  39. import static java.util.AbstractMap.SimpleImmutableEntry;
  40. public class Basic {
  41. private static String commandOutput(Reader r) throws Throwable {
  42. StringBuilder sb = new StringBuilder();
  43. int c;
  44. while ((c = r.read()) > 0)
  45. if (c != '\r')
  46. sb.append((char) c);
  47. return sb.toString();
  48. }
  49. private static String commandOutput(Process p) throws Throwable {
  50. check(p.getInputStream() == p.getInputStream());
  51. check(p.getOutputStream() == p.getOutputStream());
  52. check(p.getErrorStream() == p.getErrorStream());
  53. Reader r = new InputStreamReader(p.getInputStream(),"UTF-8");
  54. String output = commandOutput(r);
  55. equal(p.waitFor(), 0);
  56. equal(p.exitValue(), 0);
  57. return output;
  58. }
  59. private static String commandOutput(ProcessBuilder pb) {
  60. try {
  61. return commandOutput(pb.start());
  62. } catch (Throwable t) {
  63. String commandline = "";
  64. for (String arg : pb.command())
  65. commandline += " " + arg;
  66. System.out.println("Exception trying to run process: " + commandline);
  67. unexpected(t);
  68. return "";
  69. }
  70. }
  71. private static String commandOutput(String...command) {
  72. try {
  73. return commandOutput(Runtime.getRuntime().exec(command));
  74. } catch (Throwable t) {
  75. String commandline = "";
  76. for (String arg : command)
  77. commandline += " " + arg;
  78. System.out.println("Exception trying to run process: " + commandline);
  79. unexpected(t);
  80. return "";
  81. }
  82. }
  83. private static void checkCommandOutput(ProcessBuilder pb,
  84. String expected,
  85. String failureMsg) {
  86. String got = commandOutput(pb);
  87. check(got.equals(expected),
  88. failureMsg + "\n" +
  89. "Expected: \"" + expected + "\"\n" +
  90. "Got: \"" + got + "\"");
  91. }
  92. private static String absolutifyPath(String path) {
  93. StringBuilder sb = new StringBuilder();
  94. for (String file : path.split(File.pathSeparator)) {
  95. if (sb.length() != 0)
  96. sb.append(File.pathSeparator);
  97. sb.append(new File(file).getAbsolutePath());
  98. }
  99. return sb.toString();
  100. }
  101. // compare windows-style, by canonicalizing to upper case,
  102. // not lower case as String.compareToIgnoreCase does
  103. private static class WindowsComparator
  104. implements Comparator<String> {
  105. public int compare(String x, String y) {
  106. return x.toUpperCase(Locale.US)
  107. .compareTo(y.toUpperCase(Locale.US));
  108. }
  109. }
  110. private static String sortedLines(String lines) {
  111. String[] arr = lines.split("\n");
  112. List<String> ls = new ArrayList<String>();
  113. for (String s : arr)
  114. ls.add(s);
  115. Collections.sort(ls, new WindowsComparator());
  116. StringBuilder sb = new StringBuilder();
  117. for (String s : ls)
  118. sb.append(s + "\n");
  119. return sb.toString();
  120. }
  121. private static void compareLinesIgnoreCase(String lines1, String lines2) {
  122. if (! (sortedLines(lines1).equalsIgnoreCase(sortedLines(lines2)))) {
  123. String dashes =
  124. "-----------------------------------------------------";
  125. out.println(dashes);
  126. out.print(sortedLines(lines1));
  127. out.println(dashes);
  128. out.print(sortedLines(lines2));
  129. out.println(dashes);
  130. out.println("sizes: " + sortedLines(lines1).length() +
  131. " " + sortedLines(lines2).length());
  132. fail("Sorted string contents differ");
  133. }
  134. }
  135. private static final Runtime runtime = Runtime.getRuntime();
  136. private static final String[] winEnvCommand = {"cmd.exe", "/c", "set"};
  137. private static String winEnvFilter(String env) {
  138. return env.replaceAll("\r", "")
  139. .replaceAll("(?m)^(?:COMSPEC|PROMPT|PATHEXT)=.*\n","");
  140. }
  141. private static String unixEnvProg() {
  142. return new File("/usr/bin/env").canExecute() ? "/usr/bin/env"
  143. : "/bin/env";
  144. }
  145. private static String nativeEnv(String[] env) {
  146. try {
  147. if (Windows.is()) {
  148. return winEnvFilter
  149. (commandOutput(runtime.exec(winEnvCommand, env)));
  150. } else {
  151. return commandOutput(runtime.exec(unixEnvProg(), env));
  152. }
  153. } catch (Throwable t) { throw new Error(t); }
  154. }
  155. private static String nativeEnv(ProcessBuilder pb) {
  156. try {
  157. if (Windows.is()) {
  158. pb.command(winEnvCommand);
  159. return winEnvFilter(commandOutput(pb));
  160. } else {
  161. pb.command(new String[]{unixEnvProg()});
  162. return commandOutput(pb);
  163. }
  164. } catch (Throwable t) { throw new Error(t); }
  165. }
  166. private static void checkSizes(Map<String,String> environ, int size) {
  167. try {
  168. equal(size, environ.size());
  169. equal(size, environ.entrySet().size());
  170. equal(size, environ.keySet().size());
  171. equal(size, environ.values().size());
  172. boolean isEmpty = (size == 0);
  173. equal(isEmpty, environ.isEmpty());
  174. equal(isEmpty, environ.entrySet().isEmpty());
  175. equal(isEmpty, environ.keySet().isEmpty());
  176. equal(isEmpty, environ.values().isEmpty());
  177. } catch (Throwable t) { unexpected(t); }
  178. }
  179. private interface EnvironmentFrobber {
  180. void doIt(Map<String,String> environ);
  181. }
  182. private static void testVariableDeleter(EnvironmentFrobber fooDeleter) {
  183. try {
  184. Map<String,String> environ = new ProcessBuilder().environment();
  185. environ.put("Foo", "BAAR");
  186. fooDeleter.doIt(environ);
  187. equal(environ.get("Foo"), null);
  188. equal(environ.remove("Foo"), null);
  189. } catch (Throwable t) { unexpected(t); }
  190. }
  191. private static void testVariableAdder(EnvironmentFrobber fooAdder) {
  192. try {
  193. Map<String,String> environ = new ProcessBuilder().environment();
  194. environ.remove("Foo");
  195. fooAdder.doIt(environ);
  196. equal(environ.get("Foo"), "Bahrein");
  197. } catch (Throwable t) { unexpected(t); }
  198. }
  199. private static void testVariableModifier(EnvironmentFrobber fooModifier) {
  200. try {
  201. Map<String,String> environ = new ProcessBuilder().environment();
  202. environ.put("Foo","OldValue");
  203. fooModifier.doIt(environ);
  204. equal(environ.get("Foo"), "NewValue");
  205. } catch (Throwable t) { unexpected(t); }
  206. }
  207. private static void printUTF8(String s) throws IOException {
  208. out.write(s.getBytes("UTF-8"));
  209. }
  210. private static String getenvAsString(Map<String,String> environment) {
  211. StringBuilder sb = new StringBuilder();
  212. for (Map.Entry<String,String> e : environment.entrySet())
  213. // Ignore magic environment variables added by the launcher
  214. if (! e.getKey().equals("NLSPATH") &&
  215. ! e.getKey().equals("XFILESEARCHPATH") &&
  216. ! e.getKey().equals("LD_LIBRARY_PATH"))
  217. sb.append(e.getKey())
  218. .append('=')
  219. .append(e.getValue())
  220. .append(',');
  221. return sb.toString();
  222. }
  223. static void print4095(OutputStream s) throws Throwable {
  224. byte[] bytes = new byte[4095];
  225. Arrays.fill(bytes, (byte) '!');
  226. s.write(bytes); // Might hang!
  227. }
  228. public static class JavaChild {
  229. public static void main(String args[]) throws Throwable {
  230. String action = args[0];
  231. if (action.equals("System.getenv(String)")) {
  232. String val = System.getenv(args[1]);
  233. printUTF8(val == null ? "null" : val);
  234. } else if (action.equals("System.getenv(\\u1234)")) {
  235. String val = System.getenv("\u1234");
  236. printUTF8(val == null ? "null" : val);
  237. } else if (action.equals("System.getenv()")) {
  238. printUTF8(getenvAsString(System.getenv()));
  239. } else if (action.equals("pwd")) {
  240. printUTF8(new File(System.getProperty("user.dir"))
  241. .getCanonicalPath());
  242. } else if (action.equals("print4095")) {
  243. print4095(System.out);
  244. System.exit(5);
  245. } else if (action.equals("OutErr")) {
  246. // You might think the system streams would be
  247. // buffered, and in fact they are implemented using
  248. // BufferedOutputStream, but each and every print
  249. // causes immediate operating system I/O.
  250. System.out.print("out");
  251. System.err.print("err");
  252. System.out.print("out");
  253. System.err.print("err");
  254. } else if (action.equals("null PATH")) {
  255. equal(System.getenv("PATH"), null);
  256. check(new File("/bin/true").exists());
  257. check(new File("/bin/false").exists());
  258. ProcessBuilder pb1 = new ProcessBuilder();
  259. ProcessBuilder pb2 = new ProcessBuilder();
  260. pb2.environment().put("PATH", "anyOldPathIgnoredAnyways");
  261. ProcessResults r;
  262. for (final ProcessBuilder pb :
  263. new ProcessBuilder[] {pb1, pb2}) {
  264. pb.command("true");
  265. r = run(pb.start());
  266. equal(r.exitValue(), True.exitValue());
  267. pb.command("false");
  268. r = run(pb.start());
  269. equal(r.exitValue(), False.exitValue());
  270. }
  271. if (failed != 0) throw new Error("null PATH");
  272. } else if (action.equals("PATH search algorithm")) {
  273. equal(System.getenv("PATH"), "dir1:dir2:");
  274. check(new File("/bin/true").exists());
  275. check(new File("/bin/false").exists());
  276. String[] cmd = {"prog"};
  277. ProcessBuilder pb1 = new ProcessBuilder(cmd);
  278. ProcessBuilder pb2 = new ProcessBuilder(cmd);
  279. ProcessBuilder pb3 = new ProcessBuilder(cmd);
  280. pb2.environment().put("PATH", "anyOldPathIgnoredAnyways");
  281. pb3.environment().remove("PATH");
  282. for (final ProcessBuilder pb :
  283. new ProcessBuilder[] {pb1, pb2, pb3}) {
  284. try {
  285. // Not on PATH at all; directories don't exist
  286. try {
  287. pb.start();
  288. fail("Expected IOException not thrown");
  289. } catch (IOException e) {
  290. String m = e.getMessage();
  291. if (EnglishUnix.is() &&
  292. ! matches(m, "No such file"))
  293. unexpected(e);
  294. } catch (Throwable t) { unexpected(t); }
  295. // Not on PATH at all; directories exist
  296. new File("dir1").mkdirs();
  297. new File("dir2").mkdirs();
  298. try {
  299. pb.start();
  300. fail("Expected IOException not thrown");
  301. } catch (IOException e) {
  302. String m = e.getMessage();
  303. if (EnglishUnix.is() &&
  304. ! matches(m, "No such file"))
  305. unexpected(e);
  306. } catch (Throwable t) { unexpected(t); }
  307. // Can't execute a directory -- permission denied
  308. // Report EACCES errno
  309. new File("dir1/prog").mkdirs();
  310. try {
  311. pb.start();
  312. fail("Expected IOException not thrown");
  313. } catch (IOException e) {
  314. String m = e.getMessage();
  315. if (EnglishUnix.is() &&
  316. ! matches(m, "Permission denied"))
  317. unexpected(e);
  318. } catch (Throwable t) { unexpected(t); }
  319. // continue searching if EACCES
  320. copy("/bin/true", "dir2/prog");
  321. equal(run(pb.start()).exitValue(), True.exitValue());
  322. new File("dir1/prog").delete();
  323. new File("dir2/prog").delete();
  324. new File("dir2/prog").mkdirs();
  325. copy("/bin/true", "dir1/prog");
  326. equal(run(pb.start()).exitValue(), True.exitValue());
  327. // Check empty PATH component means current directory
  328. new File("dir1/prog").delete();
  329. new File("dir2/prog").delete();
  330. copy("/bin/true", "./prog");
  331. equal(run(pb.start()).exitValue(), True.exitValue());
  332. // If prog found on both parent and child's PATH,
  333. // parent's is used.
  334. new File("dir1/prog").delete();
  335. new File("dir2/prog").delete();
  336. new File("prog").delete();
  337. new File("dir3").mkdirs();
  338. copy("/bin/true", "dir1/prog");
  339. copy("/bin/false", "dir3/prog");
  340. pb.environment().put("PATH","dir3");
  341. equal(run(pb.start()).exitValue(), True.exitValue());
  342. copy("/bin/true", "dir3/prog");
  343. copy("/bin/false", "dir1/prog");
  344. equal(run(pb.start()).exitValue(), False.exitValue());
  345. } finally {
  346. // cleanup
  347. new File("dir1/prog").delete();
  348. new File("dir2/prog").delete();
  349. new File("dir3/prog").delete();
  350. new File("dir1").delete();
  351. new File("dir2").delete();
  352. new File("dir3").delete();
  353. new File("prog").delete();
  354. }
  355. }
  356. if (failed != 0) throw new Error("PATH search algorithm");
  357. }
  358. else throw new Error("JavaChild invocation error");
  359. }
  360. }
  361. private static void copy(String src, String dst) {
  362. system("/bin/cp", "-fp", src, dst);
  363. }
  364. private static void system(String... command) {
  365. try {
  366. ProcessBuilder pb = new ProcessBuilder(command);
  367. ProcessResults r = run(pb.start());
  368. equal(r.exitValue(), 0);
  369. equal(r.out(), "");
  370. equal(r.err(), "");
  371. } catch (Throwable t) { unexpected(t); }
  372. }
  373. private static String javaChildOutput(ProcessBuilder pb, String...args) {
  374. List<String> list = new ArrayList<String>(javaChildArgs);
  375. for (String arg : args)
  376. list.add(arg);
  377. pb.command(list);
  378. return commandOutput(pb);
  379. }
  380. private static String getenvInChild(ProcessBuilder pb) {
  381. return javaChildOutput(pb, "System.getenv()");
  382. }
  383. private static String getenvInChild1234(ProcessBuilder pb) {
  384. return javaChildOutput(pb, "System.getenv(\\u1234)");
  385. }
  386. private static String getenvInChild(ProcessBuilder pb, String name) {
  387. return javaChildOutput(pb, "System.getenv(String)", name);
  388. }
  389. private static String pwdInChild(ProcessBuilder pb) {
  390. return javaChildOutput(pb, "pwd");
  391. }
  392. private static final String javaExe =
  393. System.getProperty("java.home") +
  394. File.separator + "bin" + File.separator + "java";
  395. private static final String classpath =
  396. System.getProperty("java.class.path");
  397. private static final List<String> javaChildArgs =
  398. Arrays.asList(new String[]
  399. { javaExe, "-classpath", absolutifyPath(classpath),
  400. "Basic$JavaChild"});
  401. private static void testEncoding(String encoding, String tested) {
  402. try {
  403. // If round trip conversion works, should be able to set env vars
  404. // correctly in child.
  405. if (new String(tested.getBytes()).equals(tested)) {
  406. out.println("Testing " + encoding + " environment values");
  407. ProcessBuilder pb = new ProcessBuilder();
  408. pb.environment().put("ASCIINAME",tested);
  409. equal(getenvInChild(pb,"ASCIINAME"), tested);
  410. }
  411. } catch (Throwable t) { unexpected(t); }
  412. }
  413. static class Windows {
  414. public static boolean is() { return is; }
  415. private static final boolean is =
  416. System.getProperty("os.name").startsWith("Windows");
  417. }
  418. static class Unix {
  419. public static boolean is() { return is; }
  420. private static final boolean is =
  421. (! Windows.is() &&
  422. new File("/bin/sh").exists() &&
  423. new File("/bin/true").exists() &&
  424. new File("/bin/false").exists());
  425. }
  426. static class UnicodeOS {
  427. public static boolean is() { return is; }
  428. private static final String osName = System.getProperty("os.name");
  429. private static final boolean is =
  430. // MacOS X would probably also qualify
  431. osName.startsWith("Windows") &&
  432. ! osName.startsWith("Windows 9") &&
  433. ! osName.equals("Windows Me");
  434. }
  435. static class True {
  436. public static int exitValue() { return 0; }
  437. }
  438. private static class False {
  439. public static int exitValue() { return exitValue; }
  440. private static final int exitValue = exitValue0();
  441. private static int exitValue0() {
  442. // /bin/false returns an *unspecified* non-zero number.
  443. try {
  444. if (! Unix.is())
  445. return -1;
  446. else {
  447. int rc = new ProcessBuilder("/bin/false")
  448. .start().waitFor();
  449. check(rc != 0);
  450. return rc;
  451. }
  452. } catch (Throwable t) { unexpected(t); return -1; }
  453. }
  454. }
  455. static class EnglishUnix {
  456. private final static Boolean is =
  457. (! Windows.is() && isEnglish("LANG") && isEnglish("LC_ALL"));
  458. private static boolean isEnglish(String envvar) {
  459. String val = getenv(envvar);
  460. return (val == null) || val.matches("en.*");
  461. }
  462. /** Returns true if we can expect English OS error strings */
  463. static boolean is() { return is; }
  464. }
  465. private static boolean matches(String str, String regex) {
  466. return Pattern.compile(regex).matcher(str).find();
  467. }
  468. private static String sortByLinesWindowsly(String text) {
  469. String[] lines = text.split("\n");
  470. Arrays.sort(lines, new WindowsComparator());
  471. StringBuilder sb = new StringBuilder();
  472. for (String line : lines)
  473. sb.append(line).append("\n");
  474. return sb.toString();
  475. }
  476. private static void checkMapSanity(Map<String,String> map) {
  477. try {
  478. Set<String> keySet = map.keySet();
  479. Collection<String> values = map.values();
  480. Set<Map.Entry<String,String>> entrySet = map.entrySet();
  481. equal(entrySet.size(), keySet.size());
  482. equal(entrySet.size(), values.size());
  483. StringBuilder s1 = new StringBuilder();
  484. for (Map.Entry<String,String> e : entrySet)
  485. s1.append(e.getKey() + "=" + e.getValue() + "\n");
  486. StringBuilder s2 = new StringBuilder();
  487. for (String var : keySet)
  488. s2.append(var + "=" + map.get(var) + "\n");
  489. equal(s1.toString(), s2.toString());
  490. Iterator<String> kIter = keySet.iterator();
  491. Iterator<String> vIter = values.iterator();
  492. Iterator<Map.Entry<String,String>> eIter = entrySet.iterator();
  493. while (eIter.hasNext()) {
  494. Map.Entry<String,String> entry = eIter.next();
  495. String key = kIter.next();
  496. String value = vIter.next();
  497. check(entrySet.contains(entry));
  498. check(keySet.contains(key));
  499. check(values.contains(value));
  500. check(map.containsKey(key));
  501. check(map.containsValue(value));
  502. equal(entry.getKey(), key);
  503. equal(entry.getValue(), value);
  504. }
  505. check(! kIter.hasNext() &&
  506. ! vIter.hasNext());
  507. } catch (Throwable t) { unexpected(t); }
  508. }
  509. private static void checkMapEquality(Map<String,String> map1,
  510. Map<String,String> map2) {
  511. try {
  512. equal(map1.size(), map2.size());
  513. equal(map1.isEmpty(), map2.isEmpty());
  514. for (String key : map1.keySet()) {
  515. equal(map1.get(key), map2.get(key));
  516. check(map2.keySet().contains(key));
  517. }
  518. equal(map1, map2);
  519. equal(map2, map1);
  520. equal(map1.entrySet(), map2.entrySet());
  521. equal(map2.entrySet(), map1.entrySet());
  522. equal(map1.keySet(), map2.keySet());
  523. equal(map2.keySet(), map1.keySet());
  524. equal(map1.hashCode(), map2.hashCode());
  525. equal(map1.entrySet().hashCode(), map2.entrySet().hashCode());
  526. equal(map1.keySet().hashCode(), map2.keySet().hashCode());
  527. } catch (Throwable t) { unexpected(t); }
  528. }
  529. private static void realMain(String[] args) throws Throwable {
  530. if (Windows.is())
  531. System.out.println("This appears to be a Windows system.");
  532. if (Unix.is())
  533. System.out.println("This appears to be a Unix system.");
  534. if (UnicodeOS.is())
  535. System.out.println("This appears to be a Unicode-based OS.");
  536. //----------------------------------------------------------------
  537. // Basic tests for setting, replacing and deleting envvars
  538. //----------------------------------------------------------------
  539. try {
  540. ProcessBuilder pb = new ProcessBuilder();
  541. Map<String,String> environ = pb.environment();
  542. // New env var
  543. environ.put("QUUX", "BAR");
  544. equal(environ.get("QUUX"), "BAR");
  545. equal(getenvInChild(pb,"QUUX"), "BAR");
  546. // Modify env var
  547. environ.put("QUUX","bear");
  548. equal(environ.get("QUUX"), "bear");
  549. equal(getenvInChild(pb,"QUUX"), "bear");
  550. checkMapSanity(environ);
  551. // Remove env var
  552. environ.remove("QUUX");
  553. equal(environ.get("QUUX"), null);
  554. equal(getenvInChild(pb,"QUUX"), "null");
  555. checkMapSanity(environ);
  556. // Remove non-existent env var
  557. environ.remove("QUUX");
  558. equal(environ.get("QUUX"), null);
  559. equal(getenvInChild(pb,"QUUX"), "null");
  560. checkMapSanity(environ);
  561. } catch (Throwable t) { unexpected(t); }
  562. //----------------------------------------------------------------
  563. // Pass Empty environment to child
  564. //----------------------------------------------------------------
  565. try {
  566. ProcessBuilder pb = new ProcessBuilder();
  567. pb.environment().clear();
  568. equal(getenvInChild(pb), "");
  569. } catch (Throwable t) { unexpected(t); }
  570. //----------------------------------------------------------------
  571. // System.getenv() is read-only.
  572. //----------------------------------------------------------------
  573. THROWS(UnsupportedOperationException.class,
  574. new Fun(){void f(){ getenv().put("FOO","BAR");}},
  575. new Fun(){void f(){ getenv().remove("PATH");}},
  576. new Fun(){void f(){ getenv().keySet().remove("PATH");}},
  577. new Fun(){void f(){ getenv().values().remove("someValue");}});
  578. try {
  579. Collection<Map.Entry<String,String>> c = getenv().entrySet();
  580. if (! c.isEmpty())
  581. try {
  582. c.iterator().next().setValue("foo");
  583. fail("Expected UnsupportedOperationException not thrown");
  584. } catch (UnsupportedOperationException e) {} // OK
  585. } catch (Throwable t) { unexpected(t); }
  586. //----------------------------------------------------------------
  587. // System.getenv() always returns the same object in our implementation.
  588. //----------------------------------------------------------------
  589. try {
  590. check(System.getenv() == System.getenv());
  591. } catch (Throwable t) { unexpected(t); }
  592. //----------------------------------------------------------------
  593. // You can't create an env var name containing "=",
  594. // or an env var name or value containing NUL.
  595. //----------------------------------------------------------------
  596. {
  597. final Map<String,String> m = new ProcessBuilder().environment();
  598. THROWS(IllegalArgumentException.class,
  599. new Fun(){void f(){ m.put("FOO=","BAR");}},
  600. new Fun(){void f(){ m.put("FOO\u0000","BAR");}},
  601. new Fun(){void f(){ m.put("FOO","BAR\u0000");}});
  602. }
  603. //----------------------------------------------------------------
  604. // Commands must never be null.
  605. //----------------------------------------------------------------
  606. THROWS(NullPointerException.class,
  607. new Fun(){void f(){
  608. new ProcessBuilder((List<String>)null);}},
  609. new Fun(){void f(){
  610. new ProcessBuilder().command((List<String>)null);}});
  611. //----------------------------------------------------------------
  612. // Put in a command; get the same one back out.
  613. //----------------------------------------------------------------
  614. try {
  615. List<String> command = new ArrayList<String>();
  616. ProcessBuilder pb = new ProcessBuilder(command);
  617. check(pb.command() == command);
  618. List<String> command2 = new ArrayList<String>(2);
  619. command2.add("foo");
  620. command2.add("bar");
  621. pb.command(command2);
  622. check(pb.command() == command2);
  623. pb.command("foo", "bar");
  624. check(pb.command() != command2 && pb.command().equals(command2));
  625. pb.command(command2);
  626. command2.add("baz");
  627. equal(pb.command().get(2), "baz");
  628. } catch (Throwable t) { unexpected(t); }
  629. //----------------------------------------------------------------
  630. // Commands must contain at least one element.
  631. //----------------------------------------------------------------
  632. THROWS(IndexOutOfBoundsException.class,
  633. new Fun() { void f() throws IOException {
  634. new ProcessBuilder().start();}},
  635. new Fun() { void f() throws IOException {
  636. new ProcessBuilder(new ArrayList<String>()).start();}},
  637. new Fun() { void f() throws IOException {
  638. Runtime.getRuntime().exec(new String[]{});}});
  639. //----------------------------------------------------------------
  640. // Commands must not contain null elements at start() time.
  641. //----------------------------------------------------------------
  642. THROWS(NullPointerException.class,
  643. new Fun() { void f() throws IOException {
  644. new ProcessBuilder("foo",null,"bar").start();}},
  645. new Fun() { void f() throws IOException {
  646. new ProcessBuilder((String)null).start();}},
  647. new Fun() { void f() throws IOException {
  648. new ProcessBuilder(new String[]{null}).start();}},
  649. new Fun() { void f() throws IOException {
  650. new ProcessBuilder(new String[]{"foo",null,"bar"}).start();}});
  651. //----------------------------------------------------------------
  652. // Command lists are growable.
  653. //----------------------------------------------------------------
  654. try {
  655. new ProcessBuilder().command().add("foo");
  656. new ProcessBuilder("bar").command().add("foo");
  657. new ProcessBuilder(new String[]{"1","2"}).command().add("3");
  658. } catch (Throwable t) { unexpected(t); }
  659. //----------------------------------------------------------------
  660. // Nulls in environment updates generate NullPointerException
  661. //----------------------------------------------------------------
  662. try {
  663. final Map<String,String> env = new ProcessBuilder().environment();
  664. THROWS(NullPointerException.class,
  665. new Fun(){void f(){ env.put("foo",null);}},
  666. new Fun(){void f(){ env.put(null,"foo");}},
  667. new Fun(){void f(){ env.remove(null);}},
  668. new Fun(){void f(){
  669. for (Map.Entry<String,String> e : env.entrySet())
  670. e.setValue(null);}},
  671. new Fun() { void f() throws IOException {
  672. Runtime.getRuntime().exec(new String[]{"foo"},
  673. new String[]{null});}});
  674. } catch (Throwable t) { unexpected(t); }
  675. //----------------------------------------------------------------
  676. // Non-String types in environment updates generate ClassCastException
  677. //----------------------------------------------------------------
  678. try {
  679. final Map<String,String> env = new ProcessBuilder().environment();
  680. THROWS(ClassCastException.class,
  681. new Fun(){void f(){ env.remove(TRUE);}},
  682. new Fun(){void f(){ env.keySet().remove(TRUE);}},
  683. new Fun(){void f(){ env.values().remove(TRUE);}},
  684. new Fun(){void f(){ env.entrySet().remove(TRUE);}});
  685. } catch (Throwable t) { unexpected(t); }
  686. //----------------------------------------------------------------
  687. // Check query operations on environment maps
  688. //----------------------------------------------------------------
  689. try {
  690. List<Map<String,String>> envs =
  691. new ArrayList<Map<String,String>>(2);
  692. envs.add(System.getenv());
  693. envs.add(new ProcessBuilder().environment());
  694. for (final Map<String,String> env : envs) {
  695. //----------------------------------------------------------------
  696. // Nulls in environment queries are forbidden.
  697. //----------------------------------------------------------------
  698. THROWS(NullPointerException.class,
  699. new Fun(){void f(){ getenv(null);}},
  700. new Fun(){void f(){ env.get(null);}},
  701. new Fun(){void f(){ env.containsKey(null);}},
  702. new Fun(){void f(){ env.containsValue(null);}},
  703. new Fun(){void f(){ env.keySet().contains(null);}},
  704. new Fun(){void f(){ env.values().contains(null);}});
  705. //----------------------------------------------------------------
  706. // Non-String types in environment queries are forbidden.
  707. //----------------------------------------------------------------
  708. THROWS(ClassCastException.class,
  709. new Fun(){void f(){ env.get(TRUE);}},
  710. new Fun(){void f(){ env.containsKey(TRUE);}},
  711. new Fun(){void f(){ env.containsValue(TRUE);}},
  712. new Fun(){void f(){ env.keySet().contains(TRUE);}},
  713. new Fun(){void f(){ env.values().contains(TRUE);}});
  714. //----------------------------------------------------------------
  715. // Illegal String values in environment queries are (grumble) OK
  716. //----------------------------------------------------------------
  717. equal(env.get("\u0000"), null);
  718. check(! env.containsKey("\u0000"));
  719. check(! env.containsValue("\u0000"));
  720. check(! env.keySet().contains("\u0000"));
  721. check(! env.values().contains("\u0000"));
  722. }
  723. } catch (Throwable t) { unexpected(t); }
  724. try {
  725. final Set<Map.Entry<String,String>> entrySet =
  726. new ProcessBuilder().environment().entrySet();
  727. THROWS(NullPointerException.class,
  728. new Fun(){void f(){ entrySet.contains(null);}});
  729. THROWS(ClassCastException.class,
  730. new Fun(){void f(){ entrySet.contains(TRUE);}},
  731. new Fun(){void f(){
  732. entrySet.contains(
  733. new SimpleImmutableEntry<Boolean,String>(TRUE,""));}});
  734. check(! entrySet.contains
  735. (new SimpleImmutableEntry<String,String>("", "")));
  736. } catch (Throwable t) { unexpected(t); }
  737. //----------------------------------------------------------------
  738. // Put in a directory; get the same one back out.
  739. //----------------------------------------------------------------
  740. try {
  741. ProcessBuilder pb = new ProcessBuilder();
  742. File foo = new File("foo");
  743. equal(pb.directory(), null);
  744. equal(pb.directory(foo).directory(), foo);
  745. equal(pb.directory(null).directory(), null);
  746. } catch (Throwable t) { unexpected(t); }
  747. //----------------------------------------------------------------
  748. // If round-trip conversion works, check envvar pass-through to child
  749. //----------------------------------------------------------------
  750. try {
  751. testEncoding("ASCII", "xyzzy");
  752. testEncoding("Latin1", "\u00f1\u00e1");
  753. testEncoding("Unicode", "\u22f1\u11e1");
  754. } catch (Throwable t) { unexpected(t); }
  755. //----------------------------------------------------------------
  756. // A surprisingly large number of ways to delete an environment var.
  757. //----------------------------------------------------------------
  758. testVariableDeleter(new EnvironmentFrobber() {
  759. public void doIt(Map<String,String> environ) {
  760. environ.remove("Foo");}});
  761. testVariableDeleter(new EnvironmentFrobber() {
  762. public void doIt(Map<String,String> environ) {
  763. environ.keySet().remove("Foo");}});
  764. testVariableDeleter(new EnvironmentFrobber() {
  765. public void doIt(Map<String,String> environ) {
  766. environ.values().remove("BAAR");}});
  767. testVariableDeleter(new EnvironmentFrobber() {
  768. public void doIt(Map<String,String> environ) {
  769. // Legally fabricate a ProcessEnvironment.StringEntry,
  770. // even though it's private.
  771. Map<String,String> environ2
  772. = new ProcessBuilder().environment();
  773. environ2.clear();
  774. environ2.put("Foo","BAAR");
  775. // Subtlety alert.
  776. Map.Entry<String,String> e
  777. = environ2.entrySet().iterator().next();
  778. environ.entrySet().remove(e);}});
  779. testVariableDeleter(new EnvironmentFrobber() {
  780. public void doIt(Map<String,String> environ) {
  781. Map.Entry<String,String> victim = null;
  782. for (Map.Entry<String,String> e : environ.entrySet())
  783. if (e.getKey().equals("Foo"))
  784. victim = e;
  785. if (victim != null)
  786. environ.entrySet().remove(victim);}});
  787. testVariableDeleter(new EnvironmentFrobber() {
  788. public void doIt(Map<String,String> environ) {
  789. Iterator<String> it = environ.keySet().iterator();
  790. while (it.hasNext()) {
  791. String val = it.next();
  792. if (val.equals("Foo"))
  793. it.remove();}}});
  794. testVariableDeleter(new EnvironmentFrobber() {
  795. public void doIt(Map<String,String> environ) {
  796. Iterator<Map.Entry<String,String>> it
  797. = environ.entrySet().iterator();
  798. while (it.hasNext()) {
  799. Map.Entry<String,String> e = it.next();
  800. if (e.getKey().equals("Foo"))
  801. it.remove();}}});
  802. testVariableDeleter(new EnvironmentFrobber() {
  803. public void doIt(Map<String,String> environ) {
  804. Iterator<String> it = environ.values().iterator();
  805. while (it.hasNext()) {
  806. String val = it.next();
  807. if (val.equals("BAAR"))
  808. it.remove();}}});
  809. //----------------------------------------------------------------
  810. // A surprisingly small number of ways to add an environment var.
  811. //----------------------------------------------------------------
  812. testVariableAdder(new EnvironmentFrobber() {
  813. public void doIt(Map<String,String> environ) {
  814. environ.put("Foo","Bahrein");}});
  815. //----------------------------------------------------------------
  816. // A few ways to modify an environment var.
  817. //----------------------------------------------------------------
  818. testVariableModifier(new EnvironmentFrobber() {
  819. public void doIt(Map<String,String> environ) {
  820. environ.put("Foo","NewValue");}});
  821. testVariableModifier(new EnvironmentFrobber() {
  822. public void doIt(Map<String,String> environ) {
  823. for (Map.Entry<String,String> e : environ.entrySet())
  824. if (e.getKey().equals("Foo"))
  825. e.setValue("NewValue");}});
  826. //----------------------------------------------------------------
  827. // Fiddle with environment sizes
  828. //----------------------------------------------------------------
  829. try {
  830. Map<String,String> environ = new ProcessBuilder().environment();
  831. int size = environ.size();
  832. checkSizes(environ, size);
  833. environ.put("UnLiKeLYeNVIROmtNam", "someVal");
  834. checkSizes(environ, size+1);
  835. // Check for environment independence
  836. new ProcessBuilder().environment().clear();
  837. environ.put("UnLiKeLYeNVIROmtNam", "someOtherVal");
  838. checkSizes(environ, size+1);
  839. environ.remove("UnLiKeLYeNVIROmtNam");
  840. checkSizes(environ, size);
  841. environ.clear();
  842. checkSizes(environ, 0);
  843. environ.clear();
  844. checkSizes(environ, 0);
  845. environ = new ProcessBuilder().environment();
  846. environ.keySet().clear();
  847. checkSizes(environ, 0);
  848. environ = new ProcessBuilder().environment();
  849. environ.entrySet().clear();
  850. checkSizes(environ, 0);
  851. environ = new ProcessBuilder().environment();
  852. environ.values().clear();
  853. checkSizes(environ, 0);
  854. } catch (Throwable t) { unexpected(t); }
  855. //----------------------------------------------------------------
  856. // Check that various map invariants hold
  857. //----------------------------------------------------------------
  858. checkMapSanity(new ProcessBuilder().environment());
  859. checkMapSanity(System.getenv());
  860. checkMapEquality(new ProcessBuilder().environment(),
  861. new ProcessBuilder().environment());
  862. //----------------------------------------------------------------
  863. // Check effects on external "env" command.
  864. //----------------------------------------------------------------
  865. try {
  866. Set<String> env1 = new HashSet<String>
  867. (Arrays.asList(nativeEnv((String[])null).split("\n")));
  868. ProcessBuilder pb = new ProcessBuilder();
  869. pb.environment().put("QwErTyUiOp","AsDfGhJk");
  870. Set<String> env2 = new HashSet<String>
  871. (Arrays.asList(nativeEnv(pb).split("\n")));
  872. check(env2.size() == env1.size() + 1);
  873. env1.add("QwErTyUiOp=AsDfGhJk");
  874. check(env1.equals(env2));
  875. } catch (Throwable t) { unexpected(t); }
  876. //----------------------------------------------------------------
  877. // Test Runtime.exec(...envp...)
  878. // Check for sort order of environment variables on Windows.
  879. //----------------------------------------------------------------
  880. try {
  881. // '+' < 'A' < 'Z' < '_' < 'a' < 'z' < '~'
  882. String[]envp = {"FOO=BAR","BAZ=GORP","QUUX=",
  883. "+=+", "_=_", "~=~"};
  884. String output = nativeEnv(envp);
  885. String expected = "+=+\nBAZ=GORP\nFOO=BAR\nQUUX=\n_=_\n~=~\n";
  886. // On Windows, Java must keep the environment sorted.
  887. // Order is random on Unix, so this test does the sort.
  888. if (! Windows.is())
  889. output = sortByLinesWindowsly(output);
  890. equal(output, expected);
  891. } catch (Throwable t) { unexpected(t); }
  892. //----------------------------------------------------------------
  893. // System.getenv() must be consistent with System.getenv(String)
  894. //----------------------------------------------------------------
  895. try {
  896. for (Map.Entry<String,String> e : getenv().entrySet())
  897. equal(getenv(e.getKey()), e.getValue());
  898. } catch (Throwable t) { unexpected(t); }
  899. //----------------------------------------------------------------
  900. // Fiddle with working directory in child
  901. //----------------------------------------------------------------
  902. try {
  903. String canonicalUserDir =
  904. new File(System.getProperty("user.dir")).getCanonicalPath();
  905. String[] sdirs = new String[]
  906. {".", "..", "/", "/bin",
  907. "C:", "c:", "C:/", "c:\\", "\\", "\\bin" };
  908. for (String sdir : sdirs) {
  909. File dir = new File(sdir);
  910. if (! (dir.isDirectory() && dir.exists()))
  911. continue;
  912. out.println("Testing directory " + dir);
  913. dir = new File(dir.getCanonicalPath());
  914. ProcessBuilder pb = new ProcessBuilder();
  915. equal(pb.directory(), null);
  916. equal(pwdInChild(pb), canonicalUserDir);
  917. pb.directory(dir);
  918. equal(pb.directory(), dir);
  919. equal(pwdInChild(pb), dir.toString());
  920. pb.directory(null);
  921. equal(pb.directory(), null);
  922. equal(pwdInChild(pb), canonicalUserDir);
  923. pb.directory(dir);
  924. }
  925. } catch (Throwable t) { unexpected(t); }
  926. //----------------------------------------------------------------
  927. // Windows has tricky semi-case-insensitive semantics
  928. //----------------------------------------------------------------
  929. if (Windows.is())
  930. try {
  931. out.println("Running case insensitve variable tests");
  932. for (String[] namePair :
  933. new String[][]
  934. { new String[]{"PATH","PaTh"},
  935. new String[]{"home","HOME"},
  936. new String[]{"SYSTEMROOT","SystemRoot"}}) {
  937. check((getenv(namePair[0]) == null &&
  938. getenv(namePair[1]) == null)
  939. ||
  940. getenv(namePair[0]).equals(getenv(namePair[1])),
  941. "Windows environment variables are not case insensitive");
  942. }
  943. } catch (Throwable t) { unexpected(t); }
  944. //----------------------------------------------------------------
  945. // Test proper Unicode child environment transfer
  946. //----------------------------------------------------------------
  947. if (UnicodeOS.is())
  948. try {
  949. ProcessBuilder pb = new ProcessBuilder();
  950. pb.environment().put("\u1234","\u5678");
  951. pb.environment().remove("PATH");
  952. equal(getenvInChild1234(pb), "\u5678");
  953. } catch (Throwable t) { unexpected(t); }
  954. //----------------------------------------------------------------
  955. // Test Runtime.exec(...envp...) with envstrings with initial `='
  956. //----------------------------------------------------------------
  957. try {
  958. List<String> childArgs = new ArrayList<String>(javaChildArgs);
  959. childArgs.add("System.getenv()");
  960. String[] cmdp = childArgs.toArray(new String[childArgs.size()]);
  961. String[] envp = {"=ExitValue=3", "=C:=\\"};
  962. Process p = Runtime.getRuntime().exec(cmdp, envp);
  963. String expected = Windows.is() ? "=C:=\\,=ExitValue=3," : "=C:=\\,";
  964. equal(commandOutput(p), expected);
  965. if (Windows.is()) {
  966. ProcessBuilder pb = new ProcessBuilder(childArgs);
  967. pb.environment().clear();
  968. pb.environment().put("=ExitValue", "3");
  969. pb.environment().put("=C:", "\\");
  970. equal(commandOutput(pb), expected);
  971. }
  972. } catch (Throwable t) { unexpected(t); }
  973. //----------------------------------------------------------------
  974. // Test Runtime.exec(...envp...) with envstrings without any `='
  975. //----------------------------------------------------------------
  976. try {
  977. String[] cmdp = {"echo"};
  978. String[] envp = {"Hello", "World"}; // Yuck!
  979. Process p = Runtime.getRuntime().exec(cmdp, envp);
  980. equal(commandOutput(p), "\n");
  981. } catch (Throwable t) { unexpected(t); }
  982. //----------------------------------------------------------------
  983. // Test Runtime.exec(...envp...) with envstrings containing NULs
  984. //----------------------------------------------------------------
  985. try {
  986. List<String> childArgs = new ArrayList<String>(javaChildArgs);
  987. childArgs.add("System.getenv()");
  988. String[] cmdp = childArgs.toArray(new String[childArgs.size()]);
  989. String[] envp = {"LC_ALL=C\u0000\u0000", // Yuck!
  990. "FO\u0000=B\u0000R"};
  991. Process p = Runtime.getRuntime().exec(cmdp, envp);
  992. check(commandOutput(p).equals("LC_ALL=C,"),
  993. "Incorrect handling of envstrings containing NULs");
  994. } catch (Throwable t) { unexpected(t); }
  995. //----------------------------------------------------------------
  996. // Test the redirectErrorStream property
  997. //----------------------------------------------------------------
  998. try {
  999. ProcessBuilder pb = new ProcessBuilder();
  1000. equal(pb.redirectErrorStream(), false);
  1001. equal(pb.redirectErrorStream(true), pb);
  1002. equal(pb.redirectErrorStream(), true);
  1003. equal(pb.redirectErrorStream(false), pb);
  1004. equal(pb.redirectErrorStream(), false);
  1005. } catch (Throwable t) { unexpected(t); }
  1006. try {
  1007. List<String> childArgs = new ArrayList<String>(javaChildArgs);
  1008. childArgs.add("OutErr");
  1009. ProcessBuilder pb = new ProcessBuilder(childArgs);
  1010. {
  1011. ProcessResults r = run(pb.start());
  1012. equal(r.out(), "outout");
  1013. equal(r.err(), "errerr");
  1014. }
  1015. {
  1016. pb.redirectErrorStream(true);
  1017. ProcessResults r = run(pb.start());
  1018. equal(r.out(), "outerrouterr");
  1019. equal(r.err(), "");
  1020. }
  1021. } catch (Throwable t) { unexpected(t); }
  1022. if (! Windows.is() &&
  1023. new File("/bin/true").exists() &&
  1024. new File("/bin/false").exists()) {
  1025. //----------------------------------------------------------------
  1026. // We can find true and false when PATH is null
  1027. //----------------------------------------------------------------
  1028. try {
  1029. List<String> childArgs = new ArrayList<String>(javaChildArgs);
  1030. childArgs.add("null PATH");
  1031. ProcessBuilder pb = new ProcessBuilder(childArgs);
  1032. pb.environment().remove("PATH");
  1033. ProcessResults r = run(pb.start());
  1034. equal(r.out(), "");
  1035. equal(r.err(), "");
  1036. equal(r.exitValue(), 0);
  1037. } catch (Throwable t) { unexpected(t); }
  1038. //----------------------------------------------------------------
  1039. // PATH search algorithm on Unix
  1040. //----------------------------------------------------------------
  1041. try {
  1042. List<String> childArgs = new ArrayList<String>(javaChildArgs);
  1043. childArgs.add("PATH search algorithm");
  1044. ProcessBuilder pb = new ProcessBuilder(childArgs);
  1045. pb.environment().put("PATH", "dir1:dir2:");
  1046. ProcessResults r = run(pb.start());
  1047. equal(r.out(), "");
  1048. equal(r.err(), "");
  1049. equal(r.exitValue(), True.exitValue());
  1050. } catch (Throwable t) { unexpected(t); }
  1051. //----------------------------------------------------------------
  1052. // Parent's, not child's PATH is used
  1053. //----------------------------------------------------------------
  1054. try {
  1055. new File("suBdiR").mkdirs();
  1056. copy("/bin/true", "suBdiR/unliKely");
  1057. final ProcessBuilder pb =
  1058. new ProcessBuilder(new String[]{"unliKely"});
  1059. pb.environment().put("PATH", "suBdiR");
  1060. THROWS(IOException.class,
  1061. new Fun() {void f() throws Throwable {pb.start();}});
  1062. } catch (Throwable t) { unexpected(t);
  1063. } finally {
  1064. new File("suBdiR/unliKely").delete();
  1065. new File("suBdiR").delete();
  1066. }
  1067. }
  1068. //----------------------------------------------------------------
  1069. // Attempt to start bogus program ""
  1070. //----------------------------------------------------------------
  1071. try {
  1072. new ProcessBuilder("").start();
  1073. fail("Expected IOException not thrown");
  1074. } catch (IOException e) {
  1075. String m = e.getMessage();
  1076. if (EnglishUnix.is() &&
  1077. ! matches(m, "No such file or directory"))
  1078. unexpected(e);
  1079. } catch (Throwable t) { unexpected(t); }
  1080. //----------------------------------------------------------------
  1081. // Check that attempt to execute program name with funny
  1082. // characters throws an exception containing those characters.
  1083. //----------------------------------------------------------------
  1084. for (String programName : new String[] {"\u00f0", "\u01f0"})
  1085. try {
  1086. new ProcessBuilder(programName).start();
  1087. fail("Expected IOException not thrown");
  1088. } catch (IOException e) {
  1089. String m = e.getMessage();
  1090. Pattern p = Pattern.compile(programName);
  1091. if (! matches(m, programName)
  1092. || (EnglishUnix.is()
  1093. && ! matches(m, "No such file or directory")))
  1094. unexpected(e);
  1095. } catch (Throwable t) { unexpected(t); }
  1096. //----------------------------------------------------------------
  1097. // Attempt to start process in nonexistent directory fails.
  1098. //----------------------------------------------------------------
  1099. try {
  1100. new ProcessBuilder("echo")
  1101. .directory(new File("UnLiKeLY"))
  1102. .start();
  1103. fail("Expected IOException not thrown");
  1104. } catch (IOException e) {
  1105. String m = e.getMessage();
  1106. if (! matches(m, "in directory")
  1107. || (EnglishUnix.is() &&
  1108. ! matches(m, "No such file or directory")))
  1109. unexpected(e);
  1110. } catch (Throwable t) { unexpected(t); }
  1111. //----------------------------------------------------------------
  1112. // This would deadlock, if not for the fact that
  1113. // interprocess pipe buffers are at least 4096 bytes.
  1114. //----------------------------------------------------------------
  1115. try {
  1116. List<String> childArgs = new ArrayList<String>(javaChildArgs);
  1117. childArgs.add("print4095");
  1118. Process p = new ProcessBuilder(childArgs).start();
  1119. print4095(p.getOutputStream()); // Might hang!
  1120. p.waitFor(); // Might hang!
  1121. equal(p.exitValue(), 5);
  1122. } catch (Throwable t) { unexpected(t); }
  1123. //----------------------------------------------------------------
  1124. // Attempt to start process with insufficient permissions fails.
  1125. //----------------------------------------------------------------
  1126. try {
  1127. new File("emptyCommand").delete();
  1128. new FileOutputStream("emptyCommand").close();
  1129. new File("emptyCommand").setExecutable(false);
  1130. new ProcessBuilder("./emptyCommand").start();
  1131. fail("Expected IOException not thrown");
  1132. } catch (IOException e) {
  1133. new File("./emptyCommand").delete();
  1134. String m = e.getMessage();
  1135. //e.printStackTrace();
  1136. if (EnglishUnix.is() &&
  1137. ! matches(m, "Permission denied"))
  1138. unexpected(e);
  1139. } catch (Throwable t) { unexpected(t); }
  1140. new File("emptyCommand").delete();
  1141. //----------------------------------------------------------------
  1142. // Check for correct security permission behavior
  1143. //----------------------------------------------------------------
  1144. final Policy policy = new Policy();
  1145. Policy.setPolicy(policy);
  1146. System.setSecurityManager(new SecurityManager());
  1147. try {
  1148. // No permissions required to CREATE a ProcessBuilder
  1149. policy.setPermissions(/* Nothing */);
  1150. new ProcessBuilder("env").directory(null).directory();
  1151. new ProcessBuilder("env").directory(new File("dir")).directory();
  1152. new ProcessBuilder("env").command("??").command();
  1153. } catch (Throwable t) { unexpected(t); }
  1154. THROWS(SecurityException.class,
  1155. new Fun() { void f() throws IOException {
  1156. policy.setPermissions(/* Nothing */);
  1157. System.getenv("foo");}},
  1158. new Fun() { void f() throws IOException {
  1159. policy.setPermissions(/* Nothing */);
  1160. System.getenv();}},
  1161. new Fun() { void f() throws IOException {
  1162. policy.setPermissions(/* Nothing */);
  1163. new ProcessBuilder("echo").start();}},
  1164. new Fun() { void f() throws IOException {
  1165. policy.setPermissions(/* Nothing */);
  1166. Runtime.getRuntime().exec("echo");}},
  1167. new Fun() { void f() throws IOException {
  1168. policy.setPermissions(new RuntimePermission("getenv.bar"));
  1169. System.getenv("foo");}});
  1170. try {
  1171. policy.setPermissions(new RuntimePermission("getenv.foo"));
  1172. System.getenv("foo");
  1173. policy.setPermissions(new RuntimePermission("getenv.*"));
  1174. System.getenv("foo");
  1175. System.getenv();
  1176. new ProcessBuilder().environment();
  1177. } catch (Throwable t) { unexpected(t); }
  1178. final Permission execPermission
  1179. = new FilePermission("<<ALL FILES>>", "execute");
  1180. THROWS(SecurityException.class,
  1181. new Fun() { void f() throws IOException {
  1182. // environment permission by itself insufficient
  1183. policy.setPermissions(new RuntimePermission("getenv.*"));
  1184. ProcessBuilder pb = new ProcessBuilder("env");
  1185. pb.environment().put("foo","bar");
  1186. pb.start();}},
  1187. new Fun() { void f() throws IOException {
  1188. // exec permission by itself insufficient
  1189. policy.setPermissions(execPermission);
  1190. ProcessBuilder pb = new ProcessBuilder("env");
  1191. pb.environment().put("foo","bar");
  1192. pb.start();}});
  1193. try {
  1194. // Both permissions? OK.
  1195. policy.setPermissions(new RuntimePermission("getenv.*"),
  1196. execPermission);
  1197. ProcessBuilder pb = new ProcessBuilder("env");
  1198. pb.environment().put("foo","bar");
  1199. pb.start();
  1200. } catch (IOException e) { // OK
  1201. } catch (Throwable t) { unexpected(t); }
  1202. try {
  1203. // Don't need environment permission unless READING environment
  1204. policy.setPermissions(execPermission);
  1205. Runtime.getRuntime().exec("env", new String[]{});
  1206. } catch (IOException e) { // OK
  1207. } catch (Throwable t) { unexpected(t); }
  1208. try {
  1209. // Don't need environment permission unless READING environment
  1210. policy.setPermissions(execPermission);
  1211. new ProcessBuilder("env").start();
  1212. } catch (IOException e) { // OK
  1213. } catch (Throwable t) { unexpected(t); }
  1214. // Restore "normal" state without a security manager
  1215. policy.setPermissions(new RuntimePermission("setSecurityManager"));
  1216. System.setSecurityManager(null);
  1217. }
  1218. //----------------------------------------------------------------
  1219. // A Policy class designed to make permissions fiddling very easy.
  1220. //----------------------------------------------------------------
  1221. private static class Policy extends java.security.Policy {
  1222. private Permissions perms;
  1223. public void setPermissions(Permission...permissions) {
  1224. perms = new Permissions();
  1225. for (Permission permission : permissions)
  1226. perms.add(permission);
  1227. }
  1228. public Policy() { setPermissions(/* Nothing */); }
  1229. public PermissionCollection getPermissions(CodeSource cs) {
  1230. return perms;
  1231. }
  1232. public PermissionCollection getPermissions(ProtectionDomain pd) {
  1233. return perms;
  1234. }
  1235. public boolean implies(ProtectionDomain pd, Permission p) {
  1236. return perms.implies(p);
  1237. }
  1238. public void refresh() {}
  1239. }
  1240. private static class StreamAccumulator extends Thread {
  1241. private final InputStream is;
  1242. private final StringBuilder sb = new StringBuilder();
  1243. private Throwable throwable = null;
  1244. public String result () throws Throwable {
  1245. if (throwable != null)
  1246. throw throwable;
  1247. return sb.toString();
  1248. }
  1249. StreamAccumulator (InputStream is) {
  1250. this.is = is;
  1251. }
  1252. public void run() {
  1253. try {
  1254. Reader r = new InputStreamReader(is);
  1255. char[] buf = new char[4096];
  1256. int n;
  1257. while ((n = r.read(buf)) > 0) {
  1258. sb.append(buf,0,n);
  1259. }
  1260. } catch (Throwable t) {
  1261. throwable = t;
  1262. }
  1263. }
  1264. }
  1265. private static ProcessResults run(Process p) {
  1266. Throwable throwable = null;
  1267. int exitValue = -1;
  1268. String out = "";
  1269. String err = "";
  1270. StreamAccumulator outAccumulator =
  1271. new StreamAccumulator(p.getInputStream());
  1272. StreamAccumulator errAccumulator =
  1273. new StreamAccumulator(p.getErrorStream());
  1274. try {
  1275. outAccumulator.start();
  1276. errAccumulator.start();
  1277. exitValue = p.waitFor();
  1278. outAccumulator.join();
  1279. errAccumulator.join();
  1280. out = outAccumulator.result();
  1281. err = errAccumulator.result();
  1282. } catch (Throwable t) {
  1283. throwable = t;
  1284. }
  1285. return new ProcessResults(out, err, exitValue, throwable);
  1286. }
  1287. //----------------------------------------------------------------
  1288. // Results of a command
  1289. //----------------------------------------------------------------
  1290. private static class ProcessResults {
  1291. private final String out;
  1292. private final String err;
  1293. private final int exitValue;
  1294. private final Throwable throwable;
  1295. public ProcessResults(String out,
  1296. String err,
  1297. int exitValue,
  1298. Throwable throwable) {
  1299. this.out = out;
  1300. this.err = err;
  1301. this.exitValue = exitValue;
  1302. this.throwable = throwable;
  1303. }
  1304. public String out() { return out; }
  1305. public String err() { return err; }
  1306. public int exitValue() { return exitValue; }
  1307. public Throwable throwable() { return throwable; }
  1308. public String toString() {
  1309. StringBuilder sb = new StringBuilder();
  1310. sb.append("<STDOUT>\n" + out() + "</STDOUT>\n")
  1311. .append("<STDERR>\n" + err() + "</STDERR>\n")
  1312. .append("exitValue = " + exitValue + "\n");
  1313. if (throwable != null)
  1314. sb.append(throwable.getStackTrace());
  1315. return sb.toString();
  1316. }
  1317. }
  1318. //--------------------- Infrastructure ---------------------------
  1319. static volatile int passed = 0, failed = 0;
  1320. static void pass() {passed++;}
  1321. static void fail() {failed++; Thread.dumpStack();}
  1322. static void fail(String msg) {System.out.println(msg); fail();}
  1323. static void unexpected(Throwable t) {failed++; t.printStackTrace();}
  1324. static void check(boolean cond) {if (cond) pass(); else fail();}
  1325. static void check(boolean cond, String m) {if (cond) pass(); else fail(m);}
  1326. static void equal(Object x, Object y) {
  1327. if (x == null ? y == null : x.equals(y)) pass();
  1328. else fail(x + " not equal to " + y);}
  1329. public static void main(String[] args) throws Throwable {
  1330. try {realMain(args);} catch (Throwable t) {unexpected(t);}
  1331. System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
  1332. if (failed > 0) throw new AssertionError("Some tests failed");}
  1333. private static abstract class Fun {abstract void f() throws Throwable;}
  1334. static void THROWS(Class<? extends Throwable> k, Fun... fs) {
  1335. for (Fun f : fs)
  1336. try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
  1337. catch (Throwable t) {
  1338. if (k.isAssignableFrom(t.getClass())) pass();
  1339. else unexpected(t);}}
  1340. }