test/java/lang/ProcessBuilder/Basic.java

Print this page
rev 8725 : 8024854: Basic changes and files to build the class library on AIX
Contributed-by: luchsh@linux.vnet.ibm.com, spoole@linux.vnet.ibm.com, thomas.stuefe@sap.com
Reviewed-by: alanb, prr, sla, chegar, michaelm, mullan


  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) {