PageRenderTime 144ms CodeModel.GetById 40ms RepoModel.GetById 2ms app.codeStats 0ms

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

https://bitbucket.org/screenconnect/openjdk8-jdk
Java | 2519 lines | 1931 code | 264 blank | 324 comment | 179 complexity | 972191f934bad15b791bbce7f0dced27 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  3. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4. *
  5. * This code is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License version 2 only, as
  7. * published by the Free Software Foundation.
  8. *
  9. * This code is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  12. * version 2 for more details (a copy is included in the LICENSE file that
  13. * accompanied this code).
  14. *
  15. * You should have received a copy of the GNU General Public License version
  16. * 2 along with this work; if not, write to the Free Software Foundation,
  17. * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18. *
  19. * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20. * or visit www.oracle.com if you need additional information or have any
  21. * questions.
  22. */
  23. /*
  24. * @test
  25. * @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689
  26. * 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313
  27. * 6464154 6523983 6206031 4960438 6631352 6631966 6850957 6850958
  28. * 4947220 7018606 7034570 4244896 5049299
  29. * @summary Basic tests for Process and Environment Variable code
  30. * @run main/othervm/timeout=300 Basic
  31. * @run main/othervm/timeout=300 -Djdk.lang.Process.launchMechanism=fork Basic
  32. * @author Martin Buchholz
  33. */
  34. import java.lang.ProcessBuilder.Redirect;
  35. import static java.lang.ProcessBuilder.Redirect.*;
  36. import java.io.*;
  37. import java.lang.reflect.Field;
  38. import java.util.*;
  39. import java.util.concurrent.CountDownLatch;
  40. import java.util.concurrent.TimeUnit;
  41. import java.security.*;
  42. import sun.misc.Unsafe;
  43. import java.util.regex.Pattern;
  44. import java.util.regex.Matcher;
  45. import static java.lang.System.getenv;
  46. import static java.lang.System.out;
  47. import static java.lang.Boolean.TRUE;
  48. import static java.util.AbstractMap.SimpleImmutableEntry;
  49. public class Basic {
  50. /* used for Windows only */
  51. static final String systemRoot = System.getenv("SystemRoot");
  52. /* used for Mac OS X only */
  53. static final String cfUserTextEncoding = System.getenv("__CF_USER_TEXT_ENCODING");
  54. /* used for AIX only */
  55. static final String libpath = System.getenv("LIBPATH");
  56. private static String commandOutput(Reader r) throws Throwable {
  57. StringBuilder sb = new StringBuilder();
  58. int c;
  59. while ((c = r.read()) > 0)
  60. if (c != '\r')
  61. sb.append((char) c);
  62. return sb.toString();
  63. }
  64. private static String commandOutput(Process p) throws Throwable {
  65. check(p.getInputStream() == p.getInputStream());
  66. check(p.getOutputStream() == p.getOutputStream());
  67. check(p.getErrorStream() == p.getErrorStream());
  68. Reader r = new InputStreamReader(p.getInputStream(),"UTF-8");
  69. String output = commandOutput(r);
  70. equal(p.waitFor(), 0);
  71. equal(p.exitValue(), 0);
  72. // The debug/fastdebug versions of the VM may write some warnings to stdout
  73. // (i.e. "Warning: Cannot open log file: hotspot.log" if the VM is started
  74. // in a directory without write permissions). These warnings will confuse tests
  75. // which match the entire output of the child process so better filter them out.
  76. return output.replaceAll("Warning:.*\\n", "");
  77. }
  78. private static String commandOutput(ProcessBuilder pb) {
  79. try {
  80. return commandOutput(pb.start());
  81. } catch (Throwable t) {
  82. String commandline = "";
  83. for (String arg : pb.command())
  84. commandline += " " + arg;
  85. System.out.println("Exception trying to run process: " + commandline);
  86. unexpected(t);
  87. return "";
  88. }
  89. }
  90. private static String commandOutput(String...command) {
  91. try {
  92. return commandOutput(Runtime.getRuntime().exec(command));
  93. } catch (Throwable t) {
  94. String commandline = "";
  95. for (String arg : command)
  96. commandline += " " + arg;
  97. System.out.println("Exception trying to run process: " + commandline);
  98. unexpected(t);
  99. return "";
  100. }
  101. }
  102. private static void checkCommandOutput(ProcessBuilder pb,
  103. String expected,
  104. String failureMsg) {
  105. String got = commandOutput(pb);
  106. check(got.equals(expected),
  107. failureMsg + "\n" +
  108. "Expected: \"" + expected + "\"\n" +
  109. "Got: \"" + got + "\"");
  110. }
  111. private static String absolutifyPath(String path) {
  112. StringBuilder sb = new StringBuilder();
  113. for (String file : path.split(File.pathSeparator)) {
  114. if (sb.length() != 0)
  115. sb.append(File.pathSeparator);
  116. sb.append(new File(file).getAbsolutePath());
  117. }
  118. return sb.toString();
  119. }
  120. // compare windows-style, by canonicalizing to upper case,
  121. // not lower case as String.compareToIgnoreCase does
  122. private static class WindowsComparator
  123. implements Comparator<String> {
  124. public int compare(String x, String y) {
  125. return x.toUpperCase(Locale.US)
  126. .compareTo(y.toUpperCase(Locale.US));
  127. }
  128. }
  129. private static String sortedLines(String lines) {
  130. String[] arr = lines.split("\n");
  131. List<String> ls = new ArrayList<String>();
  132. for (String s : arr)
  133. ls.add(s);
  134. Collections.sort(ls, new WindowsComparator());
  135. StringBuilder sb = new StringBuilder();
  136. for (String s : ls)
  137. sb.append(s + "\n");
  138. return sb.toString();
  139. }
  140. private static void compareLinesIgnoreCase(String lines1, String lines2) {
  141. if (! (sortedLines(lines1).equalsIgnoreCase(sortedLines(lines2)))) {
  142. String dashes =
  143. "-----------------------------------------------------";
  144. out.println(dashes);
  145. out.print(sortedLines(lines1));
  146. out.println(dashes);
  147. out.print(sortedLines(lines2));
  148. out.println(dashes);
  149. out.println("sizes: " + sortedLines(lines1).length() +
  150. " " + sortedLines(lines2).length());
  151. fail("Sorted string contents differ");
  152. }
  153. }
  154. private static final Runtime runtime = Runtime.getRuntime();
  155. private static final String[] winEnvCommand = {"cmd.exe", "/c", "set"};
  156. private static String winEnvFilter(String env) {
  157. return env.replaceAll("\r", "")
  158. .replaceAll("(?m)^(?:COMSPEC|PROMPT|PATHEXT)=.*\n","");
  159. }
  160. private static String unixEnvProg() {
  161. return new File("/usr/bin/env").canExecute() ? "/usr/bin/env"
  162. : "/bin/env";
  163. }
  164. private static String nativeEnv(String[] env) {
  165. try {
  166. if (Windows.is()) {
  167. return winEnvFilter
  168. (commandOutput(runtime.exec(winEnvCommand, env)));
  169. } else {
  170. return commandOutput(runtime.exec(unixEnvProg(), env));
  171. }
  172. } catch (Throwable t) { throw new Error(t); }
  173. }
  174. private static String nativeEnv(ProcessBuilder pb) {
  175. try {
  176. if (Windows.is()) {
  177. pb.command(winEnvCommand);
  178. return winEnvFilter(commandOutput(pb));
  179. } else {
  180. pb.command(new String[]{unixEnvProg()});
  181. return commandOutput(pb);
  182. }
  183. } catch (Throwable t) { throw new Error(t); }
  184. }
  185. private static void checkSizes(Map<String,String> environ, int size) {
  186. try {
  187. equal(size, environ.size());
  188. equal(size, environ.entrySet().size());
  189. equal(size, environ.keySet().size());
  190. equal(size, environ.values().size());
  191. boolean isEmpty = (size == 0);
  192. equal(isEmpty, environ.isEmpty());
  193. equal(isEmpty, environ.entrySet().isEmpty());
  194. equal(isEmpty, environ.keySet().isEmpty());
  195. equal(isEmpty, environ.values().isEmpty());
  196. } catch (Throwable t) { unexpected(t); }
  197. }
  198. private interface EnvironmentFrobber {
  199. void doIt(Map<String,String> environ);
  200. }
  201. private static void testVariableDeleter(EnvironmentFrobber fooDeleter) {
  202. try {
  203. Map<String,String> environ = new ProcessBuilder().environment();
  204. environ.put("Foo", "BAAR");
  205. fooDeleter.doIt(environ);
  206. equal(environ.get("Foo"), null);
  207. equal(environ.remove("Foo"), null);
  208. } catch (Throwable t) { unexpected(t); }
  209. }
  210. private static void testVariableAdder(EnvironmentFrobber fooAdder) {
  211. try {
  212. Map<String,String> environ = new ProcessBuilder().environment();
  213. environ.remove("Foo");
  214. fooAdder.doIt(environ);
  215. equal(environ.get("Foo"), "Bahrein");
  216. } catch (Throwable t) { unexpected(t); }
  217. }
  218. private static void testVariableModifier(EnvironmentFrobber fooModifier) {
  219. try {
  220. Map<String,String> environ = new ProcessBuilder().environment();
  221. environ.put("Foo","OldValue");
  222. fooModifier.doIt(environ);
  223. equal(environ.get("Foo"), "NewValue");
  224. } catch (Throwable t) { unexpected(t); }
  225. }
  226. private static void printUTF8(String s) throws IOException {
  227. out.write(s.getBytes("UTF-8"));
  228. }
  229. private static String getenvAsString(Map<String,String> environment) {
  230. StringBuilder sb = new StringBuilder();
  231. environment = new TreeMap<>(environment);
  232. for (Map.Entry<String,String> e : environment.entrySet())
  233. // Ignore magic environment variables added by the launcher
  234. if (! e.getKey().equals("NLSPATH") &&
  235. ! e.getKey().equals("XFILESEARCHPATH") &&
  236. ! e.getKey().equals("LD_LIBRARY_PATH"))
  237. sb.append(e.getKey())
  238. .append('=')
  239. .append(e.getValue())
  240. .append(',');
  241. return sb.toString();
  242. }
  243. static void print4095(OutputStream s, byte b) throws Throwable {
  244. byte[] bytes = new byte[4095];
  245. Arrays.fill(bytes, b);
  246. s.write(bytes); // Might hang!
  247. }
  248. static void checkPermissionDenied(ProcessBuilder pb) {
  249. try {
  250. pb.start();
  251. fail("Expected IOException not thrown");
  252. } catch (IOException e) {
  253. String m = e.getMessage();
  254. if (EnglishUnix.is() &&
  255. ! matches(m, "Permission denied"))
  256. unexpected(e);
  257. } catch (Throwable t) { unexpected(t); }
  258. }
  259. public static class JavaChild {
  260. public static void main(String args[]) throws Throwable {
  261. String action = args[0];
  262. if (action.equals("sleep")) {
  263. Thread.sleep(10 * 60 * 1000L);
  264. } else if (action.equals("testIO")) {
  265. String expected = "standard input";
  266. char[] buf = new char[expected.length()+1];
  267. int n = new InputStreamReader(System.in).read(buf,0,buf.length);
  268. if (n != expected.length())
  269. System.exit(5);
  270. if (! new String(buf,0,n).equals(expected))
  271. System.exit(5);
  272. System.err.print("standard error");
  273. System.out.print("standard output");
  274. } else if (action.equals("testInheritIO")
  275. || action.equals("testRedirectInherit")) {
  276. List<String> childArgs = new ArrayList<String>(javaChildArgs);
  277. childArgs.add("testIO");
  278. ProcessBuilder pb = new ProcessBuilder(childArgs);
  279. if (action.equals("testInheritIO"))
  280. pb.inheritIO();
  281. else
  282. redirectIO(pb, INHERIT, INHERIT, INHERIT);
  283. ProcessResults r = run(pb);
  284. if (! r.out().equals(""))
  285. System.exit(7);
  286. if (! r.err().equals(""))
  287. System.exit(8);
  288. if (r.exitValue() != 0)
  289. System.exit(9);
  290. } else if (action.equals("System.getenv(String)")) {
  291. String val = System.getenv(args[1]);
  292. printUTF8(val == null ? "null" : val);
  293. } else if (action.equals("System.getenv(\\u1234)")) {
  294. String val = System.getenv("\u1234");
  295. printUTF8(val == null ? "null" : val);
  296. } else if (action.equals("System.getenv()")) {
  297. printUTF8(getenvAsString(System.getenv()));
  298. } else if (action.equals("ArrayOOME")) {
  299. Object dummy;
  300. switch(new Random().nextInt(3)) {
  301. case 0: dummy = new Integer[Integer.MAX_VALUE]; break;
  302. case 1: dummy = new double[Integer.MAX_VALUE]; break;
  303. case 2: dummy = new byte[Integer.MAX_VALUE][]; break;
  304. default: throw new InternalError();
  305. }
  306. } else if (action.equals("pwd")) {
  307. printUTF8(new File(System.getProperty("user.dir"))
  308. .getCanonicalPath());
  309. } else if (action.equals("print4095")) {
  310. print4095(System.out, (byte) '!');
  311. print4095(System.err, (byte) 'E');
  312. System.exit(5);
  313. } else if (action.equals("OutErr")) {
  314. // You might think the system streams would be
  315. // buffered, and in fact they are implemented using
  316. // BufferedOutputStream, but each and every print
  317. // causes immediate operating system I/O.
  318. System.out.print("out");
  319. System.err.print("err");
  320. System.out.print("out");
  321. System.err.print("err");
  322. } else if (action.equals("null PATH")) {
  323. equal(System.getenv("PATH"), null);
  324. check(new File("/bin/true").exists());
  325. check(new File("/bin/false").exists());
  326. ProcessBuilder pb1 = new ProcessBuilder();
  327. ProcessBuilder pb2 = new ProcessBuilder();
  328. pb2.environment().put("PATH", "anyOldPathIgnoredAnyways");
  329. ProcessResults r;
  330. for (final ProcessBuilder pb :
  331. new ProcessBuilder[] {pb1, pb2}) {
  332. pb.command("true");
  333. equal(run(pb).exitValue(), True.exitValue());
  334. pb.command("false");
  335. equal(run(pb).exitValue(), False.exitValue());
  336. }
  337. if (failed != 0) throw new Error("null PATH");
  338. } else if (action.equals("PATH search algorithm")) {
  339. equal(System.getenv("PATH"), "dir1:dir2:");
  340. check(new File("/bin/true").exists());
  341. check(new File("/bin/false").exists());
  342. String[] cmd = {"prog"};
  343. ProcessBuilder pb1 = new ProcessBuilder(cmd);
  344. ProcessBuilder pb2 = new ProcessBuilder(cmd);
  345. ProcessBuilder pb3 = new ProcessBuilder(cmd);
  346. pb2.environment().put("PATH", "anyOldPathIgnoredAnyways");
  347. pb3.environment().remove("PATH");
  348. for (final ProcessBuilder pb :
  349. new ProcessBuilder[] {pb1, pb2, pb3}) {
  350. try {
  351. // Not on PATH at all; directories don't exist
  352. try {
  353. pb.start();
  354. fail("Expected IOException not thrown");
  355. } catch (IOException e) {
  356. String m = e.getMessage();
  357. if (EnglishUnix.is() &&
  358. ! matches(m, "No such file"))
  359. unexpected(e);
  360. } catch (Throwable t) { unexpected(t); }
  361. // Not on PATH at all; directories exist
  362. new File("dir1").mkdirs();
  363. new File("dir2").mkdirs();
  364. try {
  365. pb.start();
  366. fail("Expected IOException not thrown");
  367. } catch (IOException e) {
  368. String m = e.getMessage();
  369. if (EnglishUnix.is() &&
  370. ! matches(m, "No such file"))
  371. unexpected(e);
  372. } catch (Throwable t) { unexpected(t); }
  373. // Can't execute a directory -- permission denied
  374. // Report EACCES errno
  375. new File("dir1/prog").mkdirs();
  376. checkPermissionDenied(pb);
  377. // continue searching if EACCES
  378. copy("/bin/true", "dir2/prog");
  379. equal(run(pb).exitValue(), True.exitValue());
  380. new File("dir1/prog").delete();
  381. new File("dir2/prog").delete();
  382. new File("dir2/prog").mkdirs();
  383. copy("/bin/true", "dir1/prog");
  384. equal(run(pb).exitValue(), True.exitValue());
  385. // Check empty PATH component means current directory.
  386. //
  387. // While we're here, let's test different kinds of
  388. // Unix executables, and PATH vs explicit searching.
  389. new File("dir1/prog").delete();
  390. new File("dir2/prog").delete();
  391. for (String[] command :
  392. new String[][] {
  393. new String[] {"./prog"},
  394. cmd}) {
  395. pb.command(command);
  396. File prog = new File("./prog");
  397. // "Normal" binaries
  398. copy("/bin/true", "./prog");
  399. equal(run(pb).exitValue(),
  400. True.exitValue());
  401. copy("/bin/false", "./prog");
  402. equal(run(pb).exitValue(),
  403. False.exitValue());
  404. prog.delete();
  405. // Interpreter scripts with #!
  406. setFileContents(prog, "#!/bin/true\n");
  407. prog.setExecutable(true);
  408. equal(run(pb).exitValue(),
  409. True.exitValue());
  410. prog.delete();
  411. setFileContents(prog, "#!/bin/false\n");
  412. prog.setExecutable(true);
  413. equal(run(pb).exitValue(),
  414. False.exitValue());
  415. // Traditional shell scripts without #!
  416. setFileContents(prog, "exec /bin/true\n");
  417. prog.setExecutable(true);
  418. equal(run(pb).exitValue(),
  419. True.exitValue());
  420. prog.delete();
  421. setFileContents(prog, "exec /bin/false\n");
  422. prog.setExecutable(true);
  423. equal(run(pb).exitValue(),
  424. False.exitValue());
  425. prog.delete();
  426. }
  427. // Test Unix interpreter scripts
  428. File dir1Prog = new File("dir1/prog");
  429. dir1Prog.delete();
  430. pb.command(new String[] {"prog", "world"});
  431. setFileContents(dir1Prog, "#!/bin/echo hello\n");
  432. checkPermissionDenied(pb);
  433. dir1Prog.setExecutable(true);
  434. equal(run(pb).out(), "hello dir1/prog world\n");
  435. equal(run(pb).exitValue(), True.exitValue());
  436. dir1Prog.delete();
  437. pb.command(cmd);
  438. // Test traditional shell scripts without #!
  439. setFileContents(dir1Prog, "/bin/echo \"$@\"\n");
  440. pb.command(new String[] {"prog", "hello", "world"});
  441. checkPermissionDenied(pb);
  442. dir1Prog.setExecutable(true);
  443. equal(run(pb).out(), "hello world\n");
  444. equal(run(pb).exitValue(), True.exitValue());
  445. dir1Prog.delete();
  446. pb.command(cmd);
  447. // If prog found on both parent and child's PATH,
  448. // parent's is used.
  449. new File("dir1/prog").delete();
  450. new File("dir2/prog").delete();
  451. new File("prog").delete();
  452. new File("dir3").mkdirs();
  453. copy("/bin/true", "dir1/prog");
  454. copy("/bin/false", "dir3/prog");
  455. pb.environment().put("PATH","dir3");
  456. equal(run(pb).exitValue(), True.exitValue());
  457. copy("/bin/true", "dir3/prog");
  458. copy("/bin/false", "dir1/prog");
  459. equal(run(pb).exitValue(), False.exitValue());
  460. } finally {
  461. // cleanup
  462. new File("dir1/prog").delete();
  463. new File("dir2/prog").delete();
  464. new File("dir3/prog").delete();
  465. new File("dir1").delete();
  466. new File("dir2").delete();
  467. new File("dir3").delete();
  468. new File("prog").delete();
  469. }
  470. }
  471. if (failed != 0) throw new Error("PATH search algorithm");
  472. }
  473. else throw new Error("JavaChild invocation error");
  474. }
  475. }
  476. private static void copy(String src, String dst) {
  477. system("/bin/cp", "-fp", src, dst);
  478. }
  479. private static void system(String... command) {
  480. try {
  481. ProcessBuilder pb = new ProcessBuilder(command);
  482. ProcessResults r = run(pb.start());
  483. equal(r.exitValue(), 0);
  484. equal(r.out(), "");
  485. equal(r.err(), "");
  486. } catch (Throwable t) { unexpected(t); }
  487. }
  488. private static String javaChildOutput(ProcessBuilder pb, String...args) {
  489. List<String> list = new ArrayList<String>(javaChildArgs);
  490. for (String arg : args)
  491. list.add(arg);
  492. pb.command(list);
  493. return commandOutput(pb);
  494. }
  495. private static String getenvInChild(ProcessBuilder pb) {
  496. return javaChildOutput(pb, "System.getenv()");
  497. }
  498. private static String getenvInChild1234(ProcessBuilder pb) {
  499. return javaChildOutput(pb, "System.getenv(\\u1234)");
  500. }
  501. private static String getenvInChild(ProcessBuilder pb, String name) {
  502. return javaChildOutput(pb, "System.getenv(String)", name);
  503. }
  504. private static String pwdInChild(ProcessBuilder pb) {
  505. return javaChildOutput(pb, "pwd");
  506. }
  507. private static final String javaExe =
  508. System.getProperty("java.home") +
  509. File.separator + "bin" + File.separator + "java";
  510. private static final String classpath =
  511. System.getProperty("java.class.path");
  512. private static final List<String> javaChildArgs =
  513. Arrays.asList(javaExe,
  514. "-XX:+DisplayVMOutputToStderr",
  515. "-classpath", absolutifyPath(classpath),
  516. "Basic$JavaChild");
  517. private static void testEncoding(String encoding, String tested) {
  518. try {
  519. // If round trip conversion works, should be able to set env vars
  520. // correctly in child.
  521. if (new String(tested.getBytes()).equals(tested)) {
  522. out.println("Testing " + encoding + " environment values");
  523. ProcessBuilder pb = new ProcessBuilder();
  524. pb.environment().put("ASCIINAME",tested);
  525. equal(getenvInChild(pb,"ASCIINAME"), tested);
  526. }
  527. } catch (Throwable t) { unexpected(t); }
  528. }
  529. static class Windows {
  530. public static boolean is() { return is; }
  531. private static final boolean is =
  532. System.getProperty("os.name").startsWith("Windows");
  533. }
  534. static class AIX {
  535. public static boolean is() { return is; }
  536. private static final boolean is =
  537. System.getProperty("os.name").equals("AIX");
  538. }
  539. static class Unix {
  540. public static boolean is() { return is; }
  541. private static final boolean is =
  542. (! Windows.is() &&
  543. new File("/bin/sh").exists() &&
  544. new File("/bin/true").exists() &&
  545. new File("/bin/false").exists());
  546. }
  547. static class UnicodeOS {
  548. public static boolean is() { return is; }
  549. private static final String osName = System.getProperty("os.name");
  550. private static final boolean is =
  551. // MacOS X would probably also qualify
  552. osName.startsWith("Windows") &&
  553. ! osName.startsWith("Windows 9") &&
  554. ! osName.equals("Windows Me");
  555. }
  556. static class MacOSX {
  557. public static boolean is() { return is; }
  558. private static final String osName = System.getProperty("os.name");
  559. private static final boolean is = osName.contains("OS X");
  560. }
  561. static class True {
  562. public static int exitValue() { return 0; }
  563. }
  564. private static class False {
  565. public static int exitValue() { return exitValue; }
  566. private static final int exitValue = exitValue0();
  567. private static int exitValue0() {
  568. // /bin/false returns an *unspecified* non-zero number.
  569. try {
  570. if (! Unix.is())
  571. return -1;
  572. else {
  573. int rc = new ProcessBuilder("/bin/false")
  574. .start().waitFor();
  575. check(rc != 0);
  576. return rc;
  577. }
  578. } catch (Throwable t) { unexpected(t); return -1; }
  579. }
  580. }
  581. static class EnglishUnix {
  582. private final static Boolean is =
  583. (! Windows.is() && isEnglish("LANG") && isEnglish("LC_ALL"));
  584. private static boolean isEnglish(String envvar) {
  585. String val = getenv(envvar);
  586. return (val == null) || val.matches("en.*") || val.matches("C");
  587. }
  588. /** Returns true if we can expect English OS error strings */
  589. static boolean is() { return is; }
  590. }
  591. static class DelegatingProcess extends Process {
  592. final Process p;
  593. DelegatingProcess(Process p) {
  594. this.p = p;
  595. }
  596. @Override
  597. public void destroy() {
  598. p.destroy();
  599. }
  600. @Override
  601. public int exitValue() {
  602. return p.exitValue();
  603. }
  604. @Override
  605. public int waitFor() throws InterruptedException {
  606. return p.waitFor();
  607. }
  608. @Override
  609. public OutputStream getOutputStream() {
  610. return p.getOutputStream();
  611. }
  612. @Override
  613. public InputStream getInputStream() {
  614. return p.getInputStream();
  615. }
  616. @Override
  617. public InputStream getErrorStream() {
  618. return p.getErrorStream();
  619. }
  620. }
  621. private static boolean matches(String str, String regex) {
  622. return Pattern.compile(regex).matcher(str).find();
  623. }
  624. private static String matchAndExtract(String str, String regex) {
  625. Matcher matcher = Pattern.compile(regex).matcher(str);
  626. if (matcher.find()) {
  627. return matcher.group();
  628. } else {
  629. return "";
  630. }
  631. }
  632. /* Only used for Mac OS X --
  633. * Mac OS X (may) add the variable __CF_USER_TEXT_ENCODING to an empty
  634. * environment. The environment variable JAVA_MAIN_CLASS_<pid> may also
  635. * be set in Mac OS X.
  636. * Remove them both from the list of env variables
  637. */
  638. private static String removeMacExpectedVars(String vars) {
  639. // Check for __CF_USER_TEXT_ENCODING
  640. String cleanedVars = vars.replace("__CF_USER_TEXT_ENCODING="
  641. +cfUserTextEncoding+",","");
  642. // Check for JAVA_MAIN_CLASS_<pid>
  643. String javaMainClassStr
  644. = matchAndExtract(cleanedVars,
  645. "JAVA_MAIN_CLASS_\\d+=Basic.JavaChild,");
  646. return cleanedVars.replace(javaMainClassStr,"");
  647. }
  648. /* Only used for AIX --
  649. * AIX adds the variable AIXTHREAD_GUARDPAGES=0 to the environment.
  650. * Remove it from the list of env variables
  651. */
  652. private static String removeAixExpectedVars(String vars) {
  653. return vars.replace("AIXTHREAD_GUARDPAGES=0,","");
  654. }
  655. private static String sortByLinesWindowsly(String text) {
  656. String[] lines = text.split("\n");
  657. Arrays.sort(lines, new WindowsComparator());
  658. StringBuilder sb = new StringBuilder();
  659. for (String line : lines)
  660. sb.append(line).append("\n");
  661. return sb.toString();
  662. }
  663. private static void checkMapSanity(Map<String,String> map) {
  664. try {
  665. Set<String> keySet = map.keySet();
  666. Collection<String> values = map.values();
  667. Set<Map.Entry<String,String>> entrySet = map.entrySet();
  668. equal(entrySet.size(), keySet.size());
  669. equal(entrySet.size(), values.size());
  670. StringBuilder s1 = new StringBuilder();
  671. for (Map.Entry<String,String> e : entrySet)
  672. s1.append(e.getKey() + "=" + e.getValue() + "\n");
  673. StringBuilder s2 = new StringBuilder();
  674. for (String var : keySet)
  675. s2.append(var + "=" + map.get(var) + "\n");
  676. equal(s1.toString(), s2.toString());
  677. Iterator<String> kIter = keySet.iterator();
  678. Iterator<String> vIter = values.iterator();
  679. Iterator<Map.Entry<String,String>> eIter = entrySet.iterator();
  680. while (eIter.hasNext()) {
  681. Map.Entry<String,String> entry = eIter.next();
  682. String key = kIter.next();
  683. String value = vIter.next();
  684. check(entrySet.contains(entry));
  685. check(keySet.contains(key));
  686. check(values.contains(value));
  687. check(map.containsKey(key));
  688. check(map.containsValue(value));
  689. equal(entry.getKey(), key);
  690. equal(entry.getValue(), value);
  691. }
  692. check(! kIter.hasNext() &&
  693. ! vIter.hasNext());
  694. } catch (Throwable t) { unexpected(t); }
  695. }
  696. private static void checkMapEquality(Map<String,String> map1,
  697. Map<String,String> map2) {
  698. try {
  699. equal(map1.size(), map2.size());
  700. equal(map1.isEmpty(), map2.isEmpty());
  701. for (String key : map1.keySet()) {
  702. equal(map1.get(key), map2.get(key));
  703. check(map2.keySet().contains(key));
  704. }
  705. equal(map1, map2);
  706. equal(map2, map1);
  707. equal(map1.entrySet(), map2.entrySet());
  708. equal(map2.entrySet(), map1.entrySet());
  709. equal(map1.keySet(), map2.keySet());
  710. equal(map2.keySet(), map1.keySet());
  711. equal(map1.hashCode(), map2.hashCode());
  712. equal(map1.entrySet().hashCode(), map2.entrySet().hashCode());
  713. equal(map1.keySet().hashCode(), map2.keySet().hashCode());
  714. } catch (Throwable t) { unexpected(t); }
  715. }
  716. static void checkRedirects(ProcessBuilder pb,
  717. Redirect in, Redirect out, Redirect err) {
  718. equal(pb.redirectInput(), in);
  719. equal(pb.redirectOutput(), out);
  720. equal(pb.redirectError(), err);
  721. }
  722. static void redirectIO(ProcessBuilder pb,
  723. Redirect in, Redirect out, Redirect err) {
  724. pb.redirectInput(in);
  725. pb.redirectOutput(out);
  726. pb.redirectError(err);
  727. }
  728. static void setFileContents(File file, String contents) {
  729. try {
  730. Writer w = new FileWriter(file);
  731. w.write(contents);
  732. w.close();
  733. } catch (Throwable t) { unexpected(t); }
  734. }
  735. static String fileContents(File file) {
  736. try {
  737. Reader r = new FileReader(file);
  738. StringBuilder sb = new StringBuilder();
  739. char[] buffer = new char[1024];
  740. int n;
  741. while ((n = r.read(buffer)) != -1)
  742. sb.append(buffer,0,n);
  743. r.close();
  744. return new String(sb);
  745. } catch (Throwable t) { unexpected(t); return ""; }
  746. }
  747. static void testIORedirection() throws Throwable {
  748. final File ifile = new File("ifile");
  749. final File ofile = new File("ofile");
  750. final File efile = new File("efile");
  751. ifile.delete();
  752. ofile.delete();
  753. efile.delete();
  754. //----------------------------------------------------------------
  755. // Check mutual inequality of different types of Redirect
  756. //----------------------------------------------------------------
  757. Redirect[] redirects =
  758. { PIPE,
  759. INHERIT,
  760. Redirect.from(ifile),
  761. Redirect.to(ifile),
  762. Redirect.appendTo(ifile),
  763. Redirect.from(ofile),
  764. Redirect.to(ofile),
  765. Redirect.appendTo(ofile),
  766. };
  767. for (int i = 0; i < redirects.length; i++)
  768. for (int j = 0; j < redirects.length; j++)
  769. equal(redirects[i].equals(redirects[j]), (i == j));
  770. //----------------------------------------------------------------
  771. // Check basic properties of different types of Redirect
  772. //----------------------------------------------------------------
  773. equal(PIPE.type(), Redirect.Type.PIPE);
  774. equal(PIPE.toString(), "PIPE");
  775. equal(PIPE.file(), null);
  776. equal(INHERIT.type(), Redirect.Type.INHERIT);
  777. equal(INHERIT.toString(), "INHERIT");
  778. equal(INHERIT.file(), null);
  779. equal(Redirect.from(ifile).type(), Redirect.Type.READ);
  780. equal(Redirect.from(ifile).toString(),
  781. "redirect to read from file \"ifile\"");
  782. equal(Redirect.from(ifile).file(), ifile);
  783. equal(Redirect.from(ifile),
  784. Redirect.from(ifile));
  785. equal(Redirect.from(ifile).hashCode(),
  786. Redirect.from(ifile).hashCode());
  787. equal(Redirect.to(ofile).type(), Redirect.Type.WRITE);
  788. equal(Redirect.to(ofile).toString(),
  789. "redirect to write to file \"ofile\"");
  790. equal(Redirect.to(ofile).file(), ofile);
  791. equal(Redirect.to(ofile),
  792. Redirect.to(ofile));
  793. equal(Redirect.to(ofile).hashCode(),
  794. Redirect.to(ofile).hashCode());
  795. equal(Redirect.appendTo(ofile).type(), Redirect.Type.APPEND);
  796. equal(Redirect.appendTo(efile).toString(),
  797. "redirect to append to file \"efile\"");
  798. equal(Redirect.appendTo(efile).file(), efile);
  799. equal(Redirect.appendTo(efile),
  800. Redirect.appendTo(efile));
  801. equal(Redirect.appendTo(efile).hashCode(),
  802. Redirect.appendTo(efile).hashCode());
  803. //----------------------------------------------------------------
  804. // Check initial values of redirects
  805. //----------------------------------------------------------------
  806. List<String> childArgs = new ArrayList<String>(javaChildArgs);
  807. childArgs.add("testIO");
  808. final ProcessBuilder pb = new ProcessBuilder(childArgs);
  809. checkRedirects(pb, PIPE, PIPE, PIPE);
  810. //----------------------------------------------------------------
  811. // Check inheritIO
  812. //----------------------------------------------------------------
  813. pb.inheritIO();
  814. checkRedirects(pb, INHERIT, INHERIT, INHERIT);
  815. //----------------------------------------------------------------
  816. // Check setters and getters agree
  817. //----------------------------------------------------------------
  818. pb.redirectInput(ifile);
  819. equal(pb.redirectInput().file(), ifile);
  820. equal(pb.redirectInput(), Redirect.from(ifile));
  821. pb.redirectOutput(ofile);
  822. equal(pb.redirectOutput().file(), ofile);
  823. equal(pb.redirectOutput(), Redirect.to(ofile));
  824. pb.redirectError(efile);
  825. equal(pb.redirectError().file(), efile);
  826. equal(pb.redirectError(), Redirect.to(efile));
  827. THROWS(IllegalArgumentException.class,
  828. new Fun(){void f() {
  829. pb.redirectInput(Redirect.to(ofile)); }},
  830. new Fun(){void f() {
  831. pb.redirectInput(Redirect.appendTo(ofile)); }},
  832. new Fun(){void f() {
  833. pb.redirectOutput(Redirect.from(ifile)); }},
  834. new Fun(){void f() {
  835. pb.redirectError(Redirect.from(ifile)); }});
  836. THROWS(IOException.class,
  837. // Input file does not exist
  838. new Fun(){void f() throws Throwable { pb.start(); }});
  839. setFileContents(ifile, "standard input");
  840. //----------------------------------------------------------------
  841. // Writing to non-existent files
  842. //----------------------------------------------------------------
  843. {
  844. ProcessResults r = run(pb);
  845. equal(r.exitValue(), 0);
  846. equal(fileContents(ofile), "standard output");
  847. equal(fileContents(efile), "standard error");
  848. equal(r.out(), "");
  849. equal(r.err(), "");
  850. ofile.delete();
  851. efile.delete();
  852. }
  853. //----------------------------------------------------------------
  854. // Both redirectErrorStream + redirectError
  855. //----------------------------------------------------------------
  856. {
  857. pb.redirectErrorStream(true);
  858. ProcessResults r = run(pb);
  859. equal(r.exitValue(), 0);
  860. equal(fileContents(ofile),
  861. "standard error" + "standard output");
  862. equal(fileContents(efile), "");
  863. equal(r.out(), "");
  864. equal(r.err(), "");
  865. ofile.delete();
  866. efile.delete();
  867. }
  868. //----------------------------------------------------------------
  869. // Appending to existing files
  870. //----------------------------------------------------------------
  871. {
  872. setFileContents(ofile, "ofile-contents");
  873. setFileContents(efile, "efile-contents");
  874. pb.redirectOutput(Redirect.appendTo(ofile));
  875. pb.redirectError(Redirect.appendTo(efile));
  876. pb.redirectErrorStream(false);
  877. ProcessResults r = run(pb);
  878. equal(r.exitValue(), 0);
  879. equal(fileContents(ofile),
  880. "ofile-contents" + "standard output");
  881. equal(fileContents(efile),
  882. "efile-contents" + "standard error");
  883. equal(r.out(), "");
  884. equal(r.err(), "");
  885. ofile.delete();
  886. efile.delete();
  887. }
  888. //----------------------------------------------------------------
  889. // Replacing existing files
  890. //----------------------------------------------------------------
  891. {
  892. setFileContents(ofile, "ofile-contents");
  893. setFileContents(efile, "efile-contents");
  894. pb.redirectOutput(ofile);
  895. pb.redirectError(Redirect.to(efile));
  896. ProcessResults r = run(pb);
  897. equal(r.exitValue(), 0);
  898. equal(fileContents(ofile), "standard output");
  899. equal(fileContents(efile), "standard error");
  900. equal(r.out(), "");
  901. equal(r.err(), "");
  902. ofile.delete();
  903. efile.delete();
  904. }
  905. //----------------------------------------------------------------
  906. // Appending twice to the same file?
  907. //----------------------------------------------------------------
  908. {
  909. setFileContents(ofile, "ofile-contents");
  910. setFileContents(efile, "efile-contents");
  911. Redirect appender = Redirect.appendTo(ofile);
  912. pb.redirectOutput(appender);
  913. pb.redirectError(appender);
  914. ProcessResults r = run(pb);
  915. equal(r.exitValue(), 0);
  916. equal(fileContents(ofile),
  917. "ofile-contents" +
  918. "standard error" +
  919. "standard output");
  920. equal(fileContents(efile), "efile-contents");
  921. equal(r.out(), "");
  922. equal(r.err(), "");
  923. ifile.delete();
  924. ofile.delete();
  925. efile.delete();
  926. }
  927. //----------------------------------------------------------------
  928. // Testing INHERIT is harder.
  929. // Note that this requires __FOUR__ nested JVMs involved in one test,
  930. // if you count the harness JVM.
  931. //----------------------------------------------------------------
  932. for (String testName : new String[] { "testInheritIO", "testRedirectInherit" } ) {
  933. redirectIO(pb, PIPE, PIPE, PIPE);
  934. List<String> command = pb.command();
  935. command.set(command.size() - 1, testName);
  936. Process p = pb.start();
  937. new PrintStream(p.getOutputStream()).print("standard input");
  938. p.getOutputStream().close();
  939. ProcessResults r = run(p);
  940. equal(r.exitValue(), 0);
  941. equal(r.out(), "standard output");
  942. equal(r.err(), "standard error");
  943. }
  944. //----------------------------------------------------------------
  945. // Test security implications of I/O redirection
  946. //----------------------------------------------------------------
  947. // Read access to current directory is always granted;
  948. // So create a tmpfile for input instead.
  949. final File tmpFile = File.createTempFile("Basic", "tmp");
  950. setFileContents(tmpFile, "standard input");
  951. final Policy policy = new Policy();
  952. Policy.setPolicy(policy);
  953. System.setSecurityManager(new SecurityManager());
  954. try {
  955. final Permission xPermission
  956. = new FilePermission("<<ALL FILES>>", "execute");
  957. final Permission rxPermission
  958. = new FilePermission("<<ALL FILES>>", "read,execute");
  959. final Permission wxPermission
  960. = new FilePermission("<<ALL FILES>>", "write,execute");
  961. final Permission rwxPermission
  962. = new FilePermission("<<ALL FILES>>", "read,write,execute");
  963. THROWS(SecurityException.class,
  964. new Fun() { void f() throws IOException {
  965. policy.setPermissions(xPermission);
  966. redirectIO(pb, from(tmpFile), PIPE, PIPE);
  967. pb.start();}},
  968. new Fun() { void f() throws IOException {
  969. policy.setPermissions(rxPermission);
  970. redirectIO(pb, PIPE, to(ofile), PIPE);
  971. pb.start();}},
  972. new Fun() { void f() throws IOException {
  973. policy.setPermissions(rxPermission);
  974. redirectIO(pb, PIPE, PIPE, to(efile));
  975. pb.start();}});
  976. {
  977. policy.setPermissions(rxPermission);
  978. redirectIO(pb, from(tmpFile), PIPE, PIPE);
  979. ProcessResults r = run(pb);
  980. equal(r.out(), "standard output");
  981. equal(r.err(), "standard error");
  982. }
  983. {
  984. policy.setPermissions(wxPermission);
  985. redirectIO(pb, PIPE, to(ofile), to(efile));
  986. Process p = pb.start();
  987. new PrintStream(p.getOutputStream()).print("standard input");
  988. p.getOutputStream().close();
  989. ProcessResults r = run(p);
  990. policy.setPermissions(rwxPermission);
  991. equal(fileContents(ofile), "standard output");
  992. equal(fileContents(efile), "standard error");
  993. }
  994. {
  995. policy.setPermissions(rwxPermission);
  996. redirectIO(pb, from(tmpFile), to(ofile), to(efile));
  997. ProcessResults r = run(pb);
  998. policy.setPermissions(rwxPermission);
  999. equal(fileContents(ofile), "standard output");
  1000. equal(fileContents(efile), "standard error");
  1001. }
  1002. } finally {
  1003. policy.setPermissions(new RuntimePermission("setSecurityManager"));
  1004. System.setSecurityManager(null);
  1005. tmpFile.delete();
  1006. ifile.delete();
  1007. ofile.delete();
  1008. efile.delete();
  1009. }
  1010. }
  1011. private static void realMain(String[] args) throws Throwable {
  1012. if (Windows.is())
  1013. System.out.println("This appears to be a Windows system.");
  1014. if (Unix.is())
  1015. System.out.println("This appears to be a Unix system.");
  1016. if (UnicodeOS.is())
  1017. System.out.println("This appears to be a Unicode-based OS.");
  1018. try { testIORedirection(); }
  1019. catch (Throwable t) { unexpected(t); }
  1020. //----------------------------------------------------------------
  1021. // Basic tests for setting, replacing and deleting envvars
  1022. //----------------------------------------------------------------
  1023. try {
  1024. ProcessBuilder pb = new ProcessBuilder();
  1025. Map<String,String> environ = pb.environment();
  1026. // New env var
  1027. environ.put("QUUX", "BAR");
  1028. equal(environ.get("QUUX"), "BAR");
  1029. equal(getenvInChild(pb,"QUUX"), "BAR");
  1030. // Modify env var
  1031. environ.put("QUUX","bear");
  1032. equal(environ.get("QUUX"), "bear");
  1033. equal(getenvInChild(pb,"QUUX"), "bear");
  1034. checkMapSanity(environ);
  1035. // Remove env var
  1036. environ.remove("QUUX");
  1037. equal(environ.get("QUUX"), null);
  1038. equal(getenvInChild(pb,"QUUX"), "null");
  1039. checkMapSanity(environ);
  1040. // Remove non-existent env var
  1041. environ.remove("QUUX");
  1042. equal(environ.get("QUUX"), null);
  1043. equal(getenvInChild(pb,"QUUX"), "null");
  1044. checkMapSanity(environ);
  1045. } catch (Throwable t) { unexpected(t); }
  1046. //----------------------------------------------------------------
  1047. // Pass Empty environment to child
  1048. //----------------------------------------------------------------
  1049. try {
  1050. ProcessBuilder pb = new ProcessBuilder();
  1051. pb.environment().clear();
  1052. String expected = Windows.is() ? "SystemRoot="+systemRoot+",": "";
  1053. expected = AIX.is() ? "LIBPATH="+libpath+",": expected;
  1054. if (Windows.is()) {
  1055. pb.environment().put("SystemRoot", systemRoot);
  1056. }
  1057. if (AIX.is()) {
  1058. pb.environment().put("LIBPATH", libpath);
  1059. }
  1060. String result = getenvInChild(pb);
  1061. if (MacOSX.is()) {
  1062. result = removeMacExpectedVars(result);
  1063. }
  1064. if (AIX.is()) {
  1065. result = removeAixExpectedVars(result);
  1066. }
  1067. equal(result, expected);
  1068. } catch (Throwable t) { unexpected(t); }
  1069. //----------------------------------------------------------------
  1070. // System.getenv() is read-only.
  1071. //----------------------------------------------------------------
  1072. THROWS(UnsupportedOperationException.class,
  1073. new Fun(){void f(){ getenv().put("FOO","BAR");}},
  1074. new Fun(){void f(){ getenv().remove("PATH");}},
  1075. new Fun(){void f(){ getenv().keySet().remove("PATH");}},
  1076. new Fun(){void f(){ getenv().values().remove("someValue");}});
  1077. try {
  1078. Collection<Map.Entry<String,String>> c = getenv().entrySet();
  1079. if (! c.isEmpty())
  1080. try {
  1081. c.iterator().next().setValue("foo");
  1082. fail("Expected UnsupportedOperationException not thrown");
  1083. } catch (UnsupportedOperationException e) {} // OK
  1084. } catch (Throwable t) { unexpected(t); }
  1085. //----------------------------------------------------------------
  1086. // System.getenv() always returns the same object in our implementation.
  1087. //----------------------------------------------------------------
  1088. try {
  1089. check(System.getenv() == System.getenv());
  1090. } catch (Throwable t) { unexpected(t); }
  1091. //----------------------------------------------------------------
  1092. // You can't create an env var name containing "=",
  1093. // or an env var name or value containing NUL.
  1094. //----------------------------------------------------------------
  1095. {
  1096. final Map<String,String> m = new ProcessBuilder().environment();
  1097. THROWS(IllegalArgumentException.class,
  1098. new Fun(){void f(){ m.put("FOO=","BAR");}},
  1099. new Fun()

Large files files are truncated, but you can click here to view the full file