41 import java.util.*;
42 import java.util.concurrent.CountDownLatch;
43 import java.util.concurrent.TimeUnit;
44 import java.security.*;
45 import sun.misc.Unsafe;
46 import java.util.regex.Pattern;
47 import java.util.regex.Matcher;
48 import static java.lang.System.getenv;
49 import static java.lang.System.out;
50 import static java.lang.Boolean.TRUE;
51 import static java.util.AbstractMap.SimpleImmutableEntry;
52
53 public class Basic {
54
55 /* used for Windows only */
56 static final String systemRoot = System.getenv("SystemRoot");
57
58 /* used for Mac OS X only */
59 static final String cfUserTextEncoding = System.getenv("__CF_USER_TEXT_ENCODING");
60
61 private static String commandOutput(Reader r) throws Throwable {
62 StringBuilder sb = new StringBuilder();
63 int c;
64 while ((c = r.read()) > 0)
65 if (c != '\r')
66 sb.append((char) c);
67 return sb.toString();
68 }
69
70 private static String commandOutput(Process p) throws Throwable {
71 check(p.getInputStream() == p.getInputStream());
72 check(p.getOutputStream() == p.getOutputStream());
73 check(p.getErrorStream() == p.getErrorStream());
74 Reader r = new InputStreamReader(p.getInputStream(),"UTF-8");
75 String output = commandOutput(r);
76 equal(p.waitFor(), 0);
77 equal(p.exitValue(), 0);
78 return output;
79 }
80
81 private static String commandOutput(ProcessBuilder pb) {
82 try {
83 return commandOutput(pb.start());
84 } catch (Throwable t) {
85 String commandline = "";
86 for (String arg : pb.command())
87 commandline += " " + arg;
88 System.out.println("Exception trying to run process: " + commandline);
89 unexpected(t);
90 return "";
91 }
92 }
93
94 private static String commandOutput(String...command) {
95 try {
96 return commandOutput(Runtime.getRuntime().exec(command));
97 } catch (Throwable t) {
98 String commandline = "";
567
568 private static void testEncoding(String encoding, String tested) {
569 try {
570 // If round trip conversion works, should be able to set env vars
571 // correctly in child.
572 if (new String(tested.getBytes()).equals(tested)) {
573 out.println("Testing " + encoding + " environment values");
574 ProcessBuilder pb = new ProcessBuilder();
575 pb.environment().put("ASCIINAME",tested);
576 equal(getenvInChild(pb,"ASCIINAME"), tested);
577 }
578 } catch (Throwable t) { unexpected(t); }
579 }
580
581 static class Windows {
582 public static boolean is() { return is; }
583 private static final boolean is =
584 System.getProperty("os.name").startsWith("Windows");
585 }
586
587 static class Unix {
588 public static boolean is() { return is; }
589 private static final boolean is =
590 (! Windows.is() &&
591 new File("/bin/sh").exists() &&
592 new File("/bin/true").exists() &&
593 new File("/bin/false").exists());
594 }
595
596 static class UnicodeOS {
597 public static boolean is() { return is; }
598 private static final String osName = System.getProperty("os.name");
599 private static final boolean is =
600 // MacOS X would probably also qualify
601 osName.startsWith("Windows") &&
602 ! osName.startsWith("Windows 9") &&
603 ! osName.equals("Windows Me");
604 }
605
606 static class MacOSX {
620 // /bin/false returns an *unspecified* non-zero number.
621 try {
622 if (! Unix.is())
623 return -1;
624 else {
625 int rc = new ProcessBuilder("/bin/false")
626 .start().waitFor();
627 check(rc != 0);
628 return rc;
629 }
630 } catch (Throwable t) { unexpected(t); return -1; }
631 }
632 }
633
634 static class EnglishUnix {
635 private final static Boolean is =
636 (! Windows.is() && isEnglish("LANG") && isEnglish("LC_ALL"));
637
638 private static boolean isEnglish(String envvar) {
639 String val = getenv(envvar);
640 return (val == null) || val.matches("en.*");
641 }
642
643 /** Returns true if we can expect English OS error strings */
644 static boolean is() { return is; }
645 }
646
647 static class DelegatingProcess extends Process {
648 final Process p;
649
650 DelegatingProcess(Process p) {
651 this.p = p;
652 }
653
654 @Override
655 public void destroy() {
656 p.destroy();
657 }
658
659 @Override
660 public int exitValue() {
695 }
696 }
697
698 /* Only used for Mac OS X --
699 * Mac OS X (may) add the variable __CF_USER_TEXT_ENCODING to an empty
700 * environment. The environment variable JAVA_MAIN_CLASS_<pid> may also
701 * be set in Mac OS X.
702 * Remove them both from the list of env variables
703 */
704 private static String removeMacExpectedVars(String vars) {
705 // Check for __CF_USER_TEXT_ENCODING
706 String cleanedVars = vars.replace("__CF_USER_TEXT_ENCODING="
707 +cfUserTextEncoding+",","");
708 // Check for JAVA_MAIN_CLASS_<pid>
709 String javaMainClassStr
710 = matchAndExtract(cleanedVars,
711 "JAVA_MAIN_CLASS_\\d+=Basic.JavaChild,");
712 return cleanedVars.replace(javaMainClassStr,"");
713 }
714
715 private static String sortByLinesWindowsly(String text) {
716 String[] lines = text.split("\n");
717 Arrays.sort(lines, new WindowsComparator());
718 StringBuilder sb = new StringBuilder();
719 for (String line : lines)
720 sb.append(line).append("\n");
721 return sb.toString();
722 }
723
724 private static void checkMapSanity(Map<String,String> map) {
725 try {
726 Set<String> keySet = map.keySet();
727 Collection<String> values = map.values();
728 Set<Map.Entry<String,String>> entrySet = map.entrySet();
729
730 equal(entrySet.size(), keySet.size());
731 equal(entrySet.size(), values.size());
732
733 StringBuilder s1 = new StringBuilder();
734 for (Map.Entry<String,String> e : entrySet)
1143 // Remove env var
1144 environ.remove("QUUX");
1145 equal(environ.get("QUUX"), null);
1146 equal(getenvInChild(pb,"QUUX"), "null");
1147 checkMapSanity(environ);
1148
1149 // Remove non-existent env var
1150 environ.remove("QUUX");
1151 equal(environ.get("QUUX"), null);
1152 equal(getenvInChild(pb,"QUUX"), "null");
1153 checkMapSanity(environ);
1154 } catch (Throwable t) { unexpected(t); }
1155
1156 //----------------------------------------------------------------
1157 // Pass Empty environment to child
1158 //----------------------------------------------------------------
1159 try {
1160 ProcessBuilder pb = new ProcessBuilder();
1161 pb.environment().clear();
1162 String expected = Windows.is() ? "SystemRoot="+systemRoot+",": "";
1163 if (Windows.is()) {
1164 pb.environment().put("SystemRoot", systemRoot);
1165 }
1166 String result = getenvInChild(pb);
1167 if (MacOSX.is()) {
1168 result = removeMacExpectedVars(result);
1169 }
1170 equal(result, expected);
1171 } catch (Throwable t) { unexpected(t); }
1172
1173 //----------------------------------------------------------------
1174 // System.getenv() is read-only.
1175 //----------------------------------------------------------------
1176 THROWS(UnsupportedOperationException.class,
1177 new Fun(){void f(){ getenv().put("FOO","BAR");}},
1178 new Fun(){void f(){ getenv().remove("PATH");}},
1179 new Fun(){void f(){ getenv().keySet().remove("PATH");}},
1180 new Fun(){void f(){ getenv().values().remove("someValue");}});
1181
1182 try {
1183 Collection<Map.Entry<String,String>> c = getenv().entrySet();
1184 if (! c.isEmpty())
1185 try {
1186 c.iterator().next().setValue("foo");
1187 fail("Expected UnsupportedOperationException not thrown");
1188 } catch (UnsupportedOperationException e) {} // OK
1189 } catch (Throwable t) { unexpected(t); }
1664 } catch (Throwable t) { unexpected(t); }
1665
1666
1667 //----------------------------------------------------------------
1668 // Test Runtime.exec(...envp...) with envstrings with initial `='
1669 //----------------------------------------------------------------
1670 try {
1671 List<String> childArgs = new ArrayList<String>(javaChildArgs);
1672 childArgs.add("System.getenv()");
1673 String[] cmdp = childArgs.toArray(new String[childArgs.size()]);
1674 String[] envp;
1675 String[] envpWin = {"=C:=\\", "=ExitValue=3", "SystemRoot="+systemRoot};
1676 String[] envpOth = {"=ExitValue=3", "=C:=\\"};
1677 if (Windows.is()) {
1678 envp = envpWin;
1679 } else {
1680 envp = envpOth;
1681 }
1682 Process p = Runtime.getRuntime().exec(cmdp, envp);
1683 String expected = Windows.is() ? "=C:=\\,=ExitValue=3,SystemRoot="+systemRoot+"," : "=C:=\\,";
1684 String commandOutput = commandOutput(p);
1685 if (MacOSX.is()) {
1686 commandOutput = removeMacExpectedVars(commandOutput);
1687 }
1688 equal(commandOutput, expected);
1689 if (Windows.is()) {
1690 ProcessBuilder pb = new ProcessBuilder(childArgs);
1691 pb.environment().clear();
1692 pb.environment().put("SystemRoot", systemRoot);
1693 pb.environment().put("=ExitValue", "3");
1694 pb.environment().put("=C:", "\\");
1695 equal(commandOutput(pb), expected);
1696 }
1697 } catch (Throwable t) { unexpected(t); }
1698
1699 //----------------------------------------------------------------
1700 // Test Runtime.exec(...envp...) with envstrings without any `='
1701 //----------------------------------------------------------------
1702 try {
1703 String[] cmdp = {"echo"};
1704 String[] envp = {"Hello", "World"}; // Yuck!
1705 Process p = Runtime.getRuntime().exec(cmdp, envp);
1706 equal(commandOutput(p), "\n");
1707 } catch (Throwable t) { unexpected(t); }
1719 "FO\u0000=B\u0000R"};
1720 String[] envp;
1721 if (Windows.is()) {
1722 envp = envpWin;
1723 } else {
1724 envp = envpOth;
1725 }
1726 System.out.println ("cmdp");
1727 for (int i=0; i<cmdp.length; i++) {
1728 System.out.printf ("cmdp %d: %s\n", i, cmdp[i]);
1729 }
1730 System.out.println ("envp");
1731 for (int i=0; i<envp.length; i++) {
1732 System.out.printf ("envp %d: %s\n", i, envp[i]);
1733 }
1734 Process p = Runtime.getRuntime().exec(cmdp, envp);
1735 String commandOutput = commandOutput(p);
1736 if (MacOSX.is()) {
1737 commandOutput = removeMacExpectedVars(commandOutput);
1738 }
1739 check(commandOutput.equals(Windows.is()
1740 ? "LC_ALL=C,SystemRoot="+systemRoot+","
1741 : "LC_ALL=C,"),
1742 "Incorrect handling of envstrings containing NULs");
1743 } catch (Throwable t) { unexpected(t); }
1744
1745 //----------------------------------------------------------------
1746 // Test the redirectErrorStream property
1747 //----------------------------------------------------------------
1748 try {
1749 ProcessBuilder pb = new ProcessBuilder();
1750 equal(pb.redirectErrorStream(), false);
1751 equal(pb.redirectErrorStream(true), pb);
1752 equal(pb.redirectErrorStream(), true);
1753 equal(pb.redirectErrorStream(false), pb);
1754 equal(pb.redirectErrorStream(), false);
1755 } catch (Throwable t) { unexpected(t); }
1756
1757 try {
1758 List<String> childArgs = new ArrayList<String>(javaChildArgs);
1759 childArgs.add("OutErr");
1760 ProcessBuilder pb = new ProcessBuilder(childArgs);
1998
1999 while (unsafe.tryMonitorEnter(s)) {
2000 unsafe.monitorExit(s);
2001 Thread.sleep(1);
2002 }
2003 }
2004 p.destroy();
2005 thread.join();
2006 }
2007 } catch (Throwable t) { unexpected(t); }
2008
2009 //----------------------------------------------------------------
2010 // Check that subprocesses which create subprocesses of their
2011 // own do not cause parent to hang waiting for file
2012 // descriptors to be closed.
2013 //----------------------------------------------------------------
2014 try {
2015 if (Unix.is()
2016 && new File("/bin/bash").exists()
2017 && new File("/bin/sleep").exists()) {
2018 final String[] cmd = { "/bin/bash", "-c", "(/bin/sleep 6666)" };
2019 final ProcessBuilder pb = new ProcessBuilder(cmd);
2020 final Process p = pb.start();
2021 final InputStream stdout = p.getInputStream();
2022 final InputStream stderr = p.getErrorStream();
2023 final OutputStream stdin = p.getOutputStream();
2024 final Thread reader = new Thread() {
2025 public void run() {
2026 try { stdout.read(); }
2027 catch (IOException e) {
2028 // Check that reader failed because stream was
2029 // asynchronously closed.
2030 // e.printStackTrace();
2031 if (EnglishUnix.is() &&
2032 ! (e.getMessage().matches(".*Bad file.*")))
2033 unexpected(e);
2034 }
2035 catch (Throwable t) { unexpected(t); }}};
2036 reader.setDaemon(true);
2037 reader.start();
2038 Thread.sleep(100);
2039 p.destroy();
2040 // Subprocess is now dead, but file descriptors remain open.
2041 check(p.waitFor() != 0);
2042 check(p.exitValue() != 0);
2043 stdout.close();
2044 stderr.close();
2045 stdin.close();
2046 //----------------------------------------------------------
2047 // There remain unsolved issues with asynchronous close.
2048 // Here's a highly non-portable experiment to demonstrate:
2049 //----------------------------------------------------------
2050 if (Boolean.getBoolean("wakeupJeff!")) {
2051 System.out.println("wakeupJeff!");
2052 // Initialize signal handler for INTERRUPT_SIGNAL.
2053 new FileInputStream("/bin/sleep").getChannel().close();
2054 // Send INTERRUPT_SIGNAL to every thread in this java.
2055 String[] wakeupJeff = {
2056 "/bin/bash", "-c",
2057 "/bin/ps --noheaders -Lfp $PPID | " +
2058 "/usr/bin/perl -nale 'print $F[3]' | " +
2059 // INTERRUPT_SIGNAL == 62 on my machine du jour.
2060 "/usr/bin/xargs kill -62"
2061 };
2062 new ProcessBuilder(wakeupJeff).start().waitFor();
2063 // If wakeupJeff worked, reader probably got EBADF.
2064 reader.join();
2065 }
2171 } catch (Throwable t) { unexpected(t); }
2172
2173 // Restore "normal" state without a security manager
2174 policy.setPermissions(new RuntimePermission("setSecurityManager"));
2175 System.setSecurityManager(null);
2176
2177 //----------------------------------------------------------------
2178 // Check that Process.isAlive() &
2179 // Process.waitFor(0, TimeUnit.MILLISECONDS) work as expected.
2180 //----------------------------------------------------------------
2181 try {
2182 List<String> childArgs = new ArrayList<String>(javaChildArgs);
2183 childArgs.add("sleep");
2184 final Process p = new ProcessBuilder(childArgs).start();
2185 long start = System.nanoTime();
2186 if (!p.isAlive() || p.waitFor(0, TimeUnit.MILLISECONDS)) {
2187 fail("Test failed: Process exited prematurely");
2188 }
2189 long end = System.nanoTime();
2190 // give waitFor(timeout) a wide berth (100ms)
2191 if ((end - start) > 100000000)
2192 fail("Test failed: waitFor took too long");
2193
2194 p.destroy();
2195 p.waitFor();
2196
2197 if (p.isAlive() ||
2198 !p.waitFor(0, TimeUnit.MILLISECONDS))
2199 {
2200 fail("Test failed: Process still alive - please terminate " +
2201 p.toString() + " manually");
2202 }
2203 } catch (Throwable t) { unexpected(t); }
2204
2205 //----------------------------------------------------------------
2206 // Check that Process.waitFor(timeout, TimeUnit.MILLISECONDS)
2207 // works as expected.
2208 //----------------------------------------------------------------
2209 try {
2210 List<String> childArgs = new ArrayList<String>(javaChildArgs);
2211 childArgs.add("sleep");
2212 final Process p = new ProcessBuilder(childArgs).start();
2213 long start = System.nanoTime();
2214
2215 p.waitFor(1000, TimeUnit.MILLISECONDS);
2216
2217 long end = System.nanoTime();
2218 if ((end - start) < 500000000)
2219 fail("Test failed: waitFor didn't take long enough");
2220
2221 p.destroy();
2222
2223 start = System.nanoTime();
2224 p.waitFor(1000, TimeUnit.MILLISECONDS);
2225 end = System.nanoTime();
2226 if ((end - start) > 900000000)
2227 fail("Test failed: waitFor took too long on a dead process.");
2228 } catch (Throwable t) { unexpected(t); }
2229
2230 //----------------------------------------------------------------
2231 // Check that Process.waitFor(timeout, TimeUnit.MILLISECONDS)
2232 // interrupt works as expected.
2233 //----------------------------------------------------------------
2234 try {
2235 List<String> childArgs = new ArrayList<String>(javaChildArgs);
2236 childArgs.add("sleep");
2237 final Process p = new ProcessBuilder(childArgs).start();
2238 final long start = System.nanoTime();
2239 final CountDownLatch latch = new CountDownLatch(1);
2240
2241 final Thread thread = new Thread() {
2242 public void run() {
2243 try {
2244 try {
2245 latch.countDown();
2246 p.waitFor(10000, TimeUnit.MILLISECONDS);
2247 } catch (InterruptedException e) {
|
41 import java.util.*;
42 import java.util.concurrent.CountDownLatch;
43 import java.util.concurrent.TimeUnit;
44 import java.security.*;
45 import sun.misc.Unsafe;
46 import java.util.regex.Pattern;
47 import java.util.regex.Matcher;
48 import static java.lang.System.getenv;
49 import static java.lang.System.out;
50 import static java.lang.Boolean.TRUE;
51 import static java.util.AbstractMap.SimpleImmutableEntry;
52
53 public class Basic {
54
55 /* used for Windows only */
56 static final String systemRoot = System.getenv("SystemRoot");
57
58 /* used for Mac OS X only */
59 static final String cfUserTextEncoding = System.getenv("__CF_USER_TEXT_ENCODING");
60
61 /* used for AIX only */
62 static final String libpath = System.getenv("LIBPATH");
63
64 private static String commandOutput(Reader r) throws Throwable {
65 StringBuilder sb = new StringBuilder();
66 int c;
67 while ((c = r.read()) > 0)
68 if (c != '\r')
69 sb.append((char) c);
70 return sb.toString();
71 }
72
73 private static String commandOutput(Process p) throws Throwable {
74 check(p.getInputStream() == p.getInputStream());
75 check(p.getOutputStream() == p.getOutputStream());
76 check(p.getErrorStream() == p.getErrorStream());
77 Reader r = new InputStreamReader(p.getInputStream(),"UTF-8");
78 String output = commandOutput(r);
79 equal(p.waitFor(), 0);
80 equal(p.exitValue(), 0);
81 // The debug/fastdebug versions of the VM may write some warnings to stdout
82 // (i.e. "Warning: Cannot open log file: hotspot.log" if the VM is started
83 // in a directory without write permissions). These warnings will confuse tests
84 // which match the entire output of the child process so better filter them out.
85 return output.replaceAll("Warning:.*\\n", "");
86 }
87
88 private static String commandOutput(ProcessBuilder pb) {
89 try {
90 return commandOutput(pb.start());
91 } catch (Throwable t) {
92 String commandline = "";
93 for (String arg : pb.command())
94 commandline += " " + arg;
95 System.out.println("Exception trying to run process: " + commandline);
96 unexpected(t);
97 return "";
98 }
99 }
100
101 private static String commandOutput(String...command) {
102 try {
103 return commandOutput(Runtime.getRuntime().exec(command));
104 } catch (Throwable t) {
105 String commandline = "";
574
575 private static void testEncoding(String encoding, String tested) {
576 try {
577 // If round trip conversion works, should be able to set env vars
578 // correctly in child.
579 if (new String(tested.getBytes()).equals(tested)) {
580 out.println("Testing " + encoding + " environment values");
581 ProcessBuilder pb = new ProcessBuilder();
582 pb.environment().put("ASCIINAME",tested);
583 equal(getenvInChild(pb,"ASCIINAME"), tested);
584 }
585 } catch (Throwable t) { unexpected(t); }
586 }
587
588 static class Windows {
589 public static boolean is() { return is; }
590 private static final boolean is =
591 System.getProperty("os.name").startsWith("Windows");
592 }
593
594 static class AIX {
595 public static boolean is() { return is; }
596 private static final boolean is =
597 System.getProperty("os.name").equals("AIX");
598 }
599
600 static class Unix {
601 public static boolean is() { return is; }
602 private static final boolean is =
603 (! Windows.is() &&
604 new File("/bin/sh").exists() &&
605 new File("/bin/true").exists() &&
606 new File("/bin/false").exists());
607 }
608
609 static class UnicodeOS {
610 public static boolean is() { return is; }
611 private static final String osName = System.getProperty("os.name");
612 private static final boolean is =
613 // MacOS X would probably also qualify
614 osName.startsWith("Windows") &&
615 ! osName.startsWith("Windows 9") &&
616 ! osName.equals("Windows Me");
617 }
618
619 static class MacOSX {
633 // /bin/false returns an *unspecified* non-zero number.
634 try {
635 if (! Unix.is())
636 return -1;
637 else {
638 int rc = new ProcessBuilder("/bin/false")
639 .start().waitFor();
640 check(rc != 0);
641 return rc;
642 }
643 } catch (Throwable t) { unexpected(t); return -1; }
644 }
645 }
646
647 static class EnglishUnix {
648 private final static Boolean is =
649 (! Windows.is() && isEnglish("LANG") && isEnglish("LC_ALL"));
650
651 private static boolean isEnglish(String envvar) {
652 String val = getenv(envvar);
653 return (val == null) || val.matches("en.*") || val.matches("C");
654 }
655
656 /** Returns true if we can expect English OS error strings */
657 static boolean is() { return is; }
658 }
659
660 static class DelegatingProcess extends Process {
661 final Process p;
662
663 DelegatingProcess(Process p) {
664 this.p = p;
665 }
666
667 @Override
668 public void destroy() {
669 p.destroy();
670 }
671
672 @Override
673 public int exitValue() {
708 }
709 }
710
711 /* Only used for Mac OS X --
712 * Mac OS X (may) add the variable __CF_USER_TEXT_ENCODING to an empty
713 * environment. The environment variable JAVA_MAIN_CLASS_<pid> may also
714 * be set in Mac OS X.
715 * Remove them both from the list of env variables
716 */
717 private static String removeMacExpectedVars(String vars) {
718 // Check for __CF_USER_TEXT_ENCODING
719 String cleanedVars = vars.replace("__CF_USER_TEXT_ENCODING="
720 +cfUserTextEncoding+",","");
721 // Check for JAVA_MAIN_CLASS_<pid>
722 String javaMainClassStr
723 = matchAndExtract(cleanedVars,
724 "JAVA_MAIN_CLASS_\\d+=Basic.JavaChild,");
725 return cleanedVars.replace(javaMainClassStr,"");
726 }
727
728 /* Only used for AIX --
729 * AIX adds the variable AIXTHREAD_GUARDPAGES=0 to the environment.
730 * Remove it from the list of env variables
731 */
732 private static String removeAixExpectedVars(String vars) {
733 return vars.replace("AIXTHREAD_GUARDPAGES=0,","");
734 }
735
736 private static String sortByLinesWindowsly(String text) {
737 String[] lines = text.split("\n");
738 Arrays.sort(lines, new WindowsComparator());
739 StringBuilder sb = new StringBuilder();
740 for (String line : lines)
741 sb.append(line).append("\n");
742 return sb.toString();
743 }
744
745 private static void checkMapSanity(Map<String,String> map) {
746 try {
747 Set<String> keySet = map.keySet();
748 Collection<String> values = map.values();
749 Set<Map.Entry<String,String>> entrySet = map.entrySet();
750
751 equal(entrySet.size(), keySet.size());
752 equal(entrySet.size(), values.size());
753
754 StringBuilder s1 = new StringBuilder();
755 for (Map.Entry<String,String> e : entrySet)
1164 // Remove env var
1165 environ.remove("QUUX");
1166 equal(environ.get("QUUX"), null);
1167 equal(getenvInChild(pb,"QUUX"), "null");
1168 checkMapSanity(environ);
1169
1170 // Remove non-existent env var
1171 environ.remove("QUUX");
1172 equal(environ.get("QUUX"), null);
1173 equal(getenvInChild(pb,"QUUX"), "null");
1174 checkMapSanity(environ);
1175 } catch (Throwable t) { unexpected(t); }
1176
1177 //----------------------------------------------------------------
1178 // Pass Empty environment to child
1179 //----------------------------------------------------------------
1180 try {
1181 ProcessBuilder pb = new ProcessBuilder();
1182 pb.environment().clear();
1183 String expected = Windows.is() ? "SystemRoot="+systemRoot+",": "";
1184 expected = AIX.is() ? "LIBPATH="+libpath+",": expected;
1185 if (Windows.is()) {
1186 pb.environment().put("SystemRoot", systemRoot);
1187 }
1188 if (AIX.is()) {
1189 pb.environment().put("LIBPATH", libpath);
1190 }
1191 String result = getenvInChild(pb);
1192 if (MacOSX.is()) {
1193 result = removeMacExpectedVars(result);
1194 }
1195 if (AIX.is()) {
1196 result = removeAixExpectedVars(result);
1197 }
1198 equal(result, expected);
1199 } catch (Throwable t) { unexpected(t); }
1200
1201 //----------------------------------------------------------------
1202 // System.getenv() is read-only.
1203 //----------------------------------------------------------------
1204 THROWS(UnsupportedOperationException.class,
1205 new Fun(){void f(){ getenv().put("FOO","BAR");}},
1206 new Fun(){void f(){ getenv().remove("PATH");}},
1207 new Fun(){void f(){ getenv().keySet().remove("PATH");}},
1208 new Fun(){void f(){ getenv().values().remove("someValue");}});
1209
1210 try {
1211 Collection<Map.Entry<String,String>> c = getenv().entrySet();
1212 if (! c.isEmpty())
1213 try {
1214 c.iterator().next().setValue("foo");
1215 fail("Expected UnsupportedOperationException not thrown");
1216 } catch (UnsupportedOperationException e) {} // OK
1217 } catch (Throwable t) { unexpected(t); }
1692 } catch (Throwable t) { unexpected(t); }
1693
1694
1695 //----------------------------------------------------------------
1696 // Test Runtime.exec(...envp...) with envstrings with initial `='
1697 //----------------------------------------------------------------
1698 try {
1699 List<String> childArgs = new ArrayList<String>(javaChildArgs);
1700 childArgs.add("System.getenv()");
1701 String[] cmdp = childArgs.toArray(new String[childArgs.size()]);
1702 String[] envp;
1703 String[] envpWin = {"=C:=\\", "=ExitValue=3", "SystemRoot="+systemRoot};
1704 String[] envpOth = {"=ExitValue=3", "=C:=\\"};
1705 if (Windows.is()) {
1706 envp = envpWin;
1707 } else {
1708 envp = envpOth;
1709 }
1710 Process p = Runtime.getRuntime().exec(cmdp, envp);
1711 String expected = Windows.is() ? "=C:=\\,=ExitValue=3,SystemRoot="+systemRoot+"," : "=C:=\\,";
1712 expected = AIX.is() ? expected + "LIBPATH="+libpath+",": expected;
1713 String commandOutput = commandOutput(p);
1714 if (MacOSX.is()) {
1715 commandOutput = removeMacExpectedVars(commandOutput);
1716 }
1717 if (AIX.is()) {
1718 commandOutput = removeAixExpectedVars(commandOutput);
1719 }
1720 equal(commandOutput, expected);
1721 if (Windows.is()) {
1722 ProcessBuilder pb = new ProcessBuilder(childArgs);
1723 pb.environment().clear();
1724 pb.environment().put("SystemRoot", systemRoot);
1725 pb.environment().put("=ExitValue", "3");
1726 pb.environment().put("=C:", "\\");
1727 equal(commandOutput(pb), expected);
1728 }
1729 } catch (Throwable t) { unexpected(t); }
1730
1731 //----------------------------------------------------------------
1732 // Test Runtime.exec(...envp...) with envstrings without any `='
1733 //----------------------------------------------------------------
1734 try {
1735 String[] cmdp = {"echo"};
1736 String[] envp = {"Hello", "World"}; // Yuck!
1737 Process p = Runtime.getRuntime().exec(cmdp, envp);
1738 equal(commandOutput(p), "\n");
1739 } catch (Throwable t) { unexpected(t); }
1751 "FO\u0000=B\u0000R"};
1752 String[] envp;
1753 if (Windows.is()) {
1754 envp = envpWin;
1755 } else {
1756 envp = envpOth;
1757 }
1758 System.out.println ("cmdp");
1759 for (int i=0; i<cmdp.length; i++) {
1760 System.out.printf ("cmdp %d: %s\n", i, cmdp[i]);
1761 }
1762 System.out.println ("envp");
1763 for (int i=0; i<envp.length; i++) {
1764 System.out.printf ("envp %d: %s\n", i, envp[i]);
1765 }
1766 Process p = Runtime.getRuntime().exec(cmdp, envp);
1767 String commandOutput = commandOutput(p);
1768 if (MacOSX.is()) {
1769 commandOutput = removeMacExpectedVars(commandOutput);
1770 }
1771 if (AIX.is()) {
1772 commandOutput = removeAixExpectedVars(commandOutput);
1773 }
1774 check(commandOutput.equals(Windows.is()
1775 ? "LC_ALL=C,SystemRoot="+systemRoot+","
1776 : AIX.is()
1777 ? "LC_ALL=C,LIBPATH="+libpath+","
1778 : "LC_ALL=C,"),
1779 "Incorrect handling of envstrings containing NULs");
1780 } catch (Throwable t) { unexpected(t); }
1781
1782 //----------------------------------------------------------------
1783 // Test the redirectErrorStream property
1784 //----------------------------------------------------------------
1785 try {
1786 ProcessBuilder pb = new ProcessBuilder();
1787 equal(pb.redirectErrorStream(), false);
1788 equal(pb.redirectErrorStream(true), pb);
1789 equal(pb.redirectErrorStream(), true);
1790 equal(pb.redirectErrorStream(false), pb);
1791 equal(pb.redirectErrorStream(), false);
1792 } catch (Throwable t) { unexpected(t); }
1793
1794 try {
1795 List<String> childArgs = new ArrayList<String>(javaChildArgs);
1796 childArgs.add("OutErr");
1797 ProcessBuilder pb = new ProcessBuilder(childArgs);
2035
2036 while (unsafe.tryMonitorEnter(s)) {
2037 unsafe.monitorExit(s);
2038 Thread.sleep(1);
2039 }
2040 }
2041 p.destroy();
2042 thread.join();
2043 }
2044 } catch (Throwable t) { unexpected(t); }
2045
2046 //----------------------------------------------------------------
2047 // Check that subprocesses which create subprocesses of their
2048 // own do not cause parent to hang waiting for file
2049 // descriptors to be closed.
2050 //----------------------------------------------------------------
2051 try {
2052 if (Unix.is()
2053 && new File("/bin/bash").exists()
2054 && new File("/bin/sleep").exists()) {
2055 // Notice that we only destroy the process created by us (i.e.
2056 // our child) but not our grandchild (i.e. '/bin/sleep'). So
2057 // pay attention that the grandchild doesn't run too long to
2058 // avoid polluting the process space with useless processes.
2059 // Running the grandchild for 60s should be more than enough.
2060 final String[] cmd = { "/bin/bash", "-c", "(/bin/sleep 60)" };
2061 final ProcessBuilder pb = new ProcessBuilder(cmd);
2062 final Process p = pb.start();
2063 final InputStream stdout = p.getInputStream();
2064 final InputStream stderr = p.getErrorStream();
2065 final OutputStream stdin = p.getOutputStream();
2066 final Thread reader = new Thread() {
2067 public void run() {
2068 try { stdout.read(); }
2069 catch (IOException e) {
2070 // Check that reader failed because stream was
2071 // asynchronously closed.
2072 // e.printStackTrace();
2073 if (EnglishUnix.is() &&
2074 ! (e.getMessage().matches(".*Bad file.*")))
2075 unexpected(e);
2076 }
2077 catch (Throwable t) { unexpected(t); }}};
2078 reader.setDaemon(true);
2079 reader.start();
2080 Thread.sleep(100);
2081 p.destroy();
2082 check(p.waitFor() != 0);
2083 check(p.exitValue() != 0);
2084 // Subprocess is now dead, but file descriptors remain open.
2085 // Make sure the test will fail if we don't manage to close
2086 // the open streams within 30 seconds. Notice that this time
2087 // must be shorter than the sleep time of the grandchild.
2088 Timer t = new Timer("test/java/lang/ProcessBuilder/Basic.java process reaper", true);
2089 t.schedule(new TimerTask() {
2090 public void run() {
2091 fail("Subprocesses which create subprocesses of " +
2092 "their own caused the parent to hang while " +
2093 "waiting for file descriptors to be closed.");
2094 System.exit(-1);
2095 }
2096 }, 30000);
2097 stdout.close();
2098 stderr.close();
2099 stdin.close();
2100 // All streams successfully closed so we can cancel the timer.
2101 t.cancel();
2102 //----------------------------------------------------------
2103 // There remain unsolved issues with asynchronous close.
2104 // Here's a highly non-portable experiment to demonstrate:
2105 //----------------------------------------------------------
2106 if (Boolean.getBoolean("wakeupJeff!")) {
2107 System.out.println("wakeupJeff!");
2108 // Initialize signal handler for INTERRUPT_SIGNAL.
2109 new FileInputStream("/bin/sleep").getChannel().close();
2110 // Send INTERRUPT_SIGNAL to every thread in this java.
2111 String[] wakeupJeff = {
2112 "/bin/bash", "-c",
2113 "/bin/ps --noheaders -Lfp $PPID | " +
2114 "/usr/bin/perl -nale 'print $F[3]' | " +
2115 // INTERRUPT_SIGNAL == 62 on my machine du jour.
2116 "/usr/bin/xargs kill -62"
2117 };
2118 new ProcessBuilder(wakeupJeff).start().waitFor();
2119 // If wakeupJeff worked, reader probably got EBADF.
2120 reader.join();
2121 }
2227 } catch (Throwable t) { unexpected(t); }
2228
2229 // Restore "normal" state without a security manager
2230 policy.setPermissions(new RuntimePermission("setSecurityManager"));
2231 System.setSecurityManager(null);
2232
2233 //----------------------------------------------------------------
2234 // Check that Process.isAlive() &
2235 // Process.waitFor(0, TimeUnit.MILLISECONDS) work as expected.
2236 //----------------------------------------------------------------
2237 try {
2238 List<String> childArgs = new ArrayList<String>(javaChildArgs);
2239 childArgs.add("sleep");
2240 final Process p = new ProcessBuilder(childArgs).start();
2241 long start = System.nanoTime();
2242 if (!p.isAlive() || p.waitFor(0, TimeUnit.MILLISECONDS)) {
2243 fail("Test failed: Process exited prematurely");
2244 }
2245 long end = System.nanoTime();
2246 // give waitFor(timeout) a wide berth (100ms)
2247 // Old AIX machines my need a little longer.
2248 if ((end - start) > 100000000L * (AIX.is() ? 4 : 1))
2249 fail("Test failed: waitFor took too long (" + (end - start) + "ns)");
2250
2251 p.destroy();
2252 p.waitFor();
2253
2254 if (p.isAlive() ||
2255 !p.waitFor(0, TimeUnit.MILLISECONDS))
2256 {
2257 fail("Test failed: Process still alive - please terminate " +
2258 p.toString() + " manually");
2259 }
2260 } catch (Throwable t) { unexpected(t); }
2261
2262 //----------------------------------------------------------------
2263 // Check that Process.waitFor(timeout, TimeUnit.MILLISECONDS)
2264 // works as expected.
2265 //----------------------------------------------------------------
2266 try {
2267 List<String> childArgs = new ArrayList<String>(javaChildArgs);
2268 childArgs.add("sleep");
2269 final Process p = new ProcessBuilder(childArgs).start();
2270 long start = System.nanoTime();
2271
2272 p.waitFor(1000, TimeUnit.MILLISECONDS);
2273
2274 long end = System.nanoTime();
2275 if ((end - start) < 500000000)
2276 fail("Test failed: waitFor didn't take long enough (" + (end - start) + "ns)");
2277
2278 p.destroy();
2279
2280 start = System.nanoTime();
2281 p.waitFor(1000, TimeUnit.MILLISECONDS);
2282 end = System.nanoTime();
2283 if ((end - start) > 900000000)
2284 fail("Test failed: waitFor took too long on a dead process. (" + (end - start) + "ns)");
2285 } catch (Throwable t) { unexpected(t); }
2286
2287 //----------------------------------------------------------------
2288 // Check that Process.waitFor(timeout, TimeUnit.MILLISECONDS)
2289 // interrupt works as expected.
2290 //----------------------------------------------------------------
2291 try {
2292 List<String> childArgs = new ArrayList<String>(javaChildArgs);
2293 childArgs.add("sleep");
2294 final Process p = new ProcessBuilder(childArgs).start();
2295 final long start = System.nanoTime();
2296 final CountDownLatch latch = new CountDownLatch(1);
2297
2298 final Thread thread = new Thread() {
2299 public void run() {
2300 try {
2301 try {
2302 latch.countDown();
2303 p.waitFor(10000, TimeUnit.MILLISECONDS);
2304 } catch (InterruptedException e) {
|