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 */
920 //----------------------------------------------------------------
921 pb.inheritIO();
922 checkRedirects(pb, INHERIT, INHERIT, INHERIT);
923
924 //----------------------------------------------------------------
925 // Check setters and getters agree
926 //----------------------------------------------------------------
927 pb.redirectInput(ifile);
928 equal(pb.redirectInput().file(), ifile);
929 equal(pb.redirectInput(), Redirect.from(ifile));
930
931 pb.redirectOutput(ofile);
932 equal(pb.redirectOutput().file(), ofile);
933 equal(pb.redirectOutput(), Redirect.to(ofile));
934
935 pb.redirectError(efile);
936 equal(pb.redirectError().file(), efile);
937 equal(pb.redirectError(), Redirect.to(efile));
938
939 THROWS(IllegalArgumentException.class,
940 new Fun(){void f() {
941 pb.redirectInput(Redirect.to(ofile)); }},
942 new Fun(){void f() {
943 pb.redirectInput(Redirect.appendTo(ofile)); }},
944 new Fun(){void f() {
945 pb.redirectOutput(Redirect.from(ifile)); }},
946 new Fun(){void f() {
947 pb.redirectError(Redirect.from(ifile)); }});
948
949 THROWS(IOException.class,
950 // Input file does not exist
951 new Fun(){void f() throws Throwable { pb.start(); }});
952 setFileContents(ifile, "standard input");
953
954 //----------------------------------------------------------------
955 // Writing to non-existent files
956 //----------------------------------------------------------------
957 {
958 ProcessResults r = run(pb);
959 equal(r.exitValue(), 0);
960 equal(fileContents(ofile), "standard output");
961 equal(fileContents(efile), "standard error");
962 equal(r.out(), "");
963 equal(r.err(), "");
964 ofile.delete();
965 efile.delete();
966 }
967
968 //----------------------------------------------------------------
969 // Both redirectErrorStream + redirectError
970 //----------------------------------------------------------------
971 {
1067
1068 // Read access to current directory is always granted;
1069 // So create a tmpfile for input instead.
1070 final File tmpFile = File.createTempFile("Basic", "tmp");
1071 setFileContents(tmpFile, "standard input");
1072
1073 final Policy policy = new Policy();
1074 Policy.setPolicy(policy);
1075 System.setSecurityManager(new SecurityManager());
1076 try {
1077 final Permission xPermission
1078 = new FilePermission("<<ALL FILES>>", "execute");
1079 final Permission rxPermission
1080 = new FilePermission("<<ALL FILES>>", "read,execute");
1081 final Permission wxPermission
1082 = new FilePermission("<<ALL FILES>>", "write,execute");
1083 final Permission rwxPermission
1084 = new FilePermission("<<ALL FILES>>", "read,write,execute");
1085
1086 THROWS(SecurityException.class,
1087 new Fun() { void f() throws IOException {
1088 policy.setPermissions(xPermission);
1089 redirectIO(pb, from(tmpFile), PIPE, PIPE);
1090 pb.start();}},
1091 new Fun() { void f() throws IOException {
1092 policy.setPermissions(rxPermission);
1093 redirectIO(pb, PIPE, to(ofile), PIPE);
1094 pb.start();}},
1095 new Fun() { void f() throws IOException {
1096 policy.setPermissions(rxPermission);
1097 redirectIO(pb, PIPE, PIPE, to(efile));
1098 pb.start();}});
1099
1100 {
1101 policy.setPermissions(rxPermission);
1102 redirectIO(pb, from(tmpFile), PIPE, PIPE);
1103 ProcessResults r = run(pb);
1104 equal(r.out(), "standard output");
1105 equal(r.err(), "standard error");
1106 }
1107
1108 {
1109 policy.setPermissions(wxPermission);
1110 redirectIO(pb, PIPE, to(ofile), to(efile));
1111 Process p = pb.start();
1112 new PrintStream(p.getOutputStream()).print("standard input");
1113 p.getOutputStream().close();
1114 ProcessResults r = run(p);
1115 policy.setPermissions(rwxPermission);
1116 equal(fileContents(ofile), "standard output");
1117 equal(fileContents(efile), "standard error");
1118 }
1241 if (Windows.is()) {
1242 pb.environment().put("SystemRoot", systemRoot);
1243 }
1244 if (AIX.is()) {
1245 pb.environment().put("LIBPATH", libpath);
1246 }
1247 String result = getenvInChild(pb);
1248 if (MacOSX.is()) {
1249 result = removeMacExpectedVars(result);
1250 }
1251 if (AIX.is()) {
1252 result = removeAixExpectedVars(result);
1253 }
1254 equal(result, expected);
1255 } catch (Throwable t) { unexpected(t); }
1256
1257 //----------------------------------------------------------------
1258 // System.getenv() is read-only.
1259 //----------------------------------------------------------------
1260 THROWS(UnsupportedOperationException.class,
1261 new Fun(){void f(){ getenv().put("FOO","BAR");}},
1262 new Fun(){void f(){ getenv().remove("PATH");}},
1263 new Fun(){void f(){ getenv().keySet().remove("PATH");}},
1264 new Fun(){void f(){ getenv().values().remove("someValue");}});
1265
1266 try {
1267 Collection<Map.Entry<String,String>> c = getenv().entrySet();
1268 if (! c.isEmpty())
1269 try {
1270 c.iterator().next().setValue("foo");
1271 fail("Expected UnsupportedOperationException not thrown");
1272 } catch (UnsupportedOperationException e) {} // OK
1273 } catch (Throwable t) { unexpected(t); }
1274
1275 //----------------------------------------------------------------
1276 // System.getenv() always returns the same object in our implementation.
1277 //----------------------------------------------------------------
1278 try {
1279 check(System.getenv() == System.getenv());
1280 } catch (Throwable t) { unexpected(t); }
1281
1282 //----------------------------------------------------------------
1283 // You can't create an env var name containing "=",
1284 // or an env var name or value containing NUL.
1285 //----------------------------------------------------------------
1286 {
1287 final Map<String,String> m = new ProcessBuilder().environment();
1288 THROWS(IllegalArgumentException.class,
1289 new Fun(){void f(){ m.put("FOO=","BAR");}},
1290 new Fun(){void f(){ m.put("FOO\u0000","BAR");}},
1291 new Fun(){void f(){ m.put("FOO","BAR\u0000");}});
1292 }
1293
1294 //----------------------------------------------------------------
1295 // Commands must never be null.
1296 //----------------------------------------------------------------
1297 THROWS(NullPointerException.class,
1298 new Fun(){void f(){
1299 new ProcessBuilder((List<String>)null);}},
1300 new Fun(){void f(){
1301 new ProcessBuilder().command((List<String>)null);}});
1302
1303 //----------------------------------------------------------------
1304 // Put in a command; get the same one back out.
1305 //----------------------------------------------------------------
1306 try {
1307 List<String> command = new ArrayList<String>();
1308 ProcessBuilder pb = new ProcessBuilder(command);
1309 check(pb.command() == command);
1310 List<String> command2 = new ArrayList<String>(2);
1311 command2.add("foo");
1312 command2.add("bar");
1313 pb.command(command2);
1314 check(pb.command() == command2);
1315 pb.command("foo", "bar");
1316 check(pb.command() != command2 && pb.command().equals(command2));
1317 pb.command(command2);
1318 command2.add("baz");
1319 equal(pb.command().get(2), "baz");
1320 } catch (Throwable t) { unexpected(t); }
1321
1322 //----------------------------------------------------------------
1323 // Commands must contain at least one element.
1324 //----------------------------------------------------------------
1325 THROWS(IndexOutOfBoundsException.class,
1326 new Fun() { void f() throws IOException {
1327 new ProcessBuilder().start();}},
1328 new Fun() { void f() throws IOException {
1329 new ProcessBuilder(new ArrayList<String>()).start();}},
1330 new Fun() { void f() throws IOException {
1331 Runtime.getRuntime().exec(new String[]{});}});
1332
1333 //----------------------------------------------------------------
1334 // Commands must not contain null elements at start() time.
1335 //----------------------------------------------------------------
1336 THROWS(NullPointerException.class,
1337 new Fun() { void f() throws IOException {
1338 new ProcessBuilder("foo",null,"bar").start();}},
1339 new Fun() { void f() throws IOException {
1340 new ProcessBuilder((String)null).start();}},
1341 new Fun() { void f() throws IOException {
1342 new ProcessBuilder(new String[]{null}).start();}},
1343 new Fun() { void f() throws IOException {
1344 new ProcessBuilder(new String[]{"foo",null,"bar"}).start();}});
1345
1346 //----------------------------------------------------------------
1347 // Command lists are growable.
1348 //----------------------------------------------------------------
1349 try {
1350 new ProcessBuilder().command().add("foo");
1351 new ProcessBuilder("bar").command().add("foo");
1352 new ProcessBuilder(new String[]{"1","2"}).command().add("3");
1353 } catch (Throwable t) { unexpected(t); }
1354
1355 //----------------------------------------------------------------
1356 // Nulls in environment updates generate NullPointerException
1357 //----------------------------------------------------------------
1358 try {
1359 final Map<String,String> env = new ProcessBuilder().environment();
1360 THROWS(NullPointerException.class,
1361 new Fun(){void f(){ env.put("foo",null);}},
1362 new Fun(){void f(){ env.put(null,"foo");}},
1363 new Fun(){void f(){ env.remove(null);}},
1364 new Fun(){void f(){
1365 for (Map.Entry<String,String> e : env.entrySet())
1366 e.setValue(null);}},
1367 new Fun() { void f() throws IOException {
1368 Runtime.getRuntime().exec(new String[]{"foo"},
1369 new String[]{null});}});
1370 } catch (Throwable t) { unexpected(t); }
1371
1372 //----------------------------------------------------------------
1373 // Non-String types in environment updates generate ClassCastException
1374 //----------------------------------------------------------------
1375 try {
1376 final Map<String,String> env = new ProcessBuilder().environment();
1377 THROWS(ClassCastException.class,
1378 new Fun(){void f(){ env.remove(TRUE);}},
1379 new Fun(){void f(){ env.keySet().remove(TRUE);}},
1380 new Fun(){void f(){ env.values().remove(TRUE);}},
1381 new Fun(){void f(){ env.entrySet().remove(TRUE);}});
1382 } catch (Throwable t) { unexpected(t); }
1383
1384 //----------------------------------------------------------------
1385 // Check query operations on environment maps
1386 //----------------------------------------------------------------
1387 try {
1388 List<Map<String,String>> envs =
1389 new ArrayList<Map<String,String>>(2);
1390 envs.add(System.getenv());
1391 envs.add(new ProcessBuilder().environment());
1392 for (final Map<String,String> env : envs) {
1393 //----------------------------------------------------------------
1394 // Nulls in environment queries are forbidden.
1395 //----------------------------------------------------------------
1396 THROWS(NullPointerException.class,
1397 new Fun(){void f(){ getenv(null);}},
1398 new Fun(){void f(){ env.get(null);}},
1399 new Fun(){void f(){ env.containsKey(null);}},
1400 new Fun(){void f(){ env.containsValue(null);}},
1401 new Fun(){void f(){ env.keySet().contains(null);}},
1402 new Fun(){void f(){ env.values().contains(null);}});
1403
1404 //----------------------------------------------------------------
1405 // Non-String types in environment queries are forbidden.
1406 //----------------------------------------------------------------
1407 THROWS(ClassCastException.class,
1408 new Fun(){void f(){ env.get(TRUE);}},
1409 new Fun(){void f(){ env.containsKey(TRUE);}},
1410 new Fun(){void f(){ env.containsValue(TRUE);}},
1411 new Fun(){void f(){ env.keySet().contains(TRUE);}},
1412 new Fun(){void f(){ env.values().contains(TRUE);}});
1413
1414 //----------------------------------------------------------------
1415 // Illegal String values in environment queries are (grumble) OK
1416 //----------------------------------------------------------------
1417 equal(env.get("\u0000"), null);
1418 check(! env.containsKey("\u0000"));
1419 check(! env.containsValue("\u0000"));
1420 check(! env.keySet().contains("\u0000"));
1421 check(! env.values().contains("\u0000"));
1422 }
1423
1424 } catch (Throwable t) { unexpected(t); }
1425
1426 try {
1427 final Set<Map.Entry<String,String>> entrySet =
1428 new ProcessBuilder().environment().entrySet();
1429 THROWS(NullPointerException.class,
1430 new Fun(){void f(){ entrySet.contains(null);}});
1431 THROWS(ClassCastException.class,
1432 new Fun(){void f(){ entrySet.contains(TRUE);}},
1433 new Fun(){void f(){
1434 entrySet.contains(
1435 new SimpleImmutableEntry<Boolean,String>(TRUE,""));}});
1436
1437 check(! entrySet.contains
1438 (new SimpleImmutableEntry<String,String>("", "")));
1439 } catch (Throwable t) { unexpected(t); }
1440
1441 //----------------------------------------------------------------
1442 // Put in a directory; get the same one back out.
1443 //----------------------------------------------------------------
1444 try {
1445 ProcessBuilder pb = new ProcessBuilder();
1446 File foo = new File("foo");
1447 equal(pb.directory(), null);
1448 equal(pb.directory(foo).directory(), foo);
1449 equal(pb.directory(null).directory(), null);
1450 } catch (Throwable t) { unexpected(t); }
1451
1452 //----------------------------------------------------------------
1453 // If round-trip conversion works, check envvar pass-through to child
1454 //----------------------------------------------------------------
1455 try {
1885 try {
1886 List<String> childArgs = new ArrayList<String>(javaChildArgs);
1887 childArgs.add("PATH search algorithm");
1888 ProcessBuilder pb = new ProcessBuilder(childArgs);
1889 pb.environment().put("PATH", "dir1:dir2:");
1890 ProcessResults r = run(pb);
1891 equal(r.out(), "");
1892 equal(r.err(), "");
1893 equal(r.exitValue(), True.exitValue());
1894 } catch (Throwable t) { unexpected(t); }
1895
1896 //----------------------------------------------------------------
1897 // Parent's, not child's PATH is used
1898 //----------------------------------------------------------------
1899 try {
1900 new File("suBdiR").mkdirs();
1901 copy("/bin/true", "suBdiR/unliKely");
1902 final ProcessBuilder pb =
1903 new ProcessBuilder(new String[]{"unliKely"});
1904 pb.environment().put("PATH", "suBdiR");
1905 THROWS(IOException.class,
1906 new Fun() {void f() throws Throwable {pb.start();}});
1907 } catch (Throwable t) { unexpected(t);
1908 } finally {
1909 new File("suBdiR/unliKely").delete();
1910 new File("suBdiR").delete();
1911 }
1912 }
1913
1914 //----------------------------------------------------------------
1915 // Attempt to start bogus program ""
1916 //----------------------------------------------------------------
1917 try {
1918 new ProcessBuilder("").start();
1919 fail("Expected IOException not thrown");
1920 } catch (IOException e) {
1921 String m = e.getMessage();
1922 if (EnglishUnix.is() &&
1923 ! matches(m, "No such file or directory"))
1924 unexpected(e);
1925 } catch (Throwable t) { unexpected(t); }
1926
1959
1960 //----------------------------------------------------------------
1961 // Attempt to write 4095 bytes to the pipe buffer without a
1962 // reader to drain it would deadlock, if not for the fact that
1963 // interprocess pipe buffers are at least 4096 bytes.
1964 //
1965 // Also, check that available reports all the bytes expected
1966 // in the pipe buffer, and that I/O operations do the expected
1967 // things.
1968 //----------------------------------------------------------------
1969 try {
1970 List<String> childArgs = new ArrayList<String>(javaChildArgs);
1971 childArgs.add("print4095");
1972 final int SIZE = 4095;
1973 final Process p = new ProcessBuilder(childArgs).start();
1974 print4095(p.getOutputStream(), (byte) '!'); // Might hang!
1975 p.waitFor(); // Might hang!
1976 equal(SIZE, p.getInputStream().available());
1977 equal(SIZE, p.getErrorStream().available());
1978 THROWS(IOException.class,
1979 new Fun(){void f() throws IOException {
1980 p.getOutputStream().write((byte) '!');
1981 p.getOutputStream().flush();
1982 }});
1983
1984 final byte[] bytes = new byte[SIZE + 1];
1985 equal(SIZE, p.getInputStream().read(bytes));
1986 for (int i = 0; i < SIZE; i++)
1987 equal((byte) '!', bytes[i]);
1988 equal((byte) 0, bytes[SIZE]);
1989
1990 equal(SIZE, p.getErrorStream().read(bytes));
1991 for (int i = 0; i < SIZE; i++)
1992 equal((byte) 'E', bytes[i]);
1993 equal((byte) 0, bytes[SIZE]);
1994
1995 equal(0, p.getInputStream().available());
1996 equal(0, p.getErrorStream().available());
1997 equal(-1, p.getErrorStream().read());
1998 equal(-1, p.getInputStream().read());
1999
2000 equal(p.exitValue(), 5);
2001
2002 p.getInputStream().close();
2003 p.getErrorStream().close();
2004 try { p.getOutputStream().close(); } catch (IOException flushFailed) { }
2005
2006 InputStream[] streams = { p.getInputStream(), p.getErrorStream() };
2007 for (final InputStream in : streams) {
2008 Fun[] ops = {
2009 new Fun(){void f() throws IOException {
2010 in.read(); }},
2011 new Fun(){void f() throws IOException {
2012 in.read(bytes); }},
2013 new Fun(){void f() throws IOException {
2014 in.available(); }}
2015 };
2016 for (Fun op : ops) {
2017 try {
2018 op.f();
2019 fail();
2020 } catch (IOException expected) {
2021 check(expected.getMessage()
2022 .matches("[Ss]tream [Cc]losed"));
2023 }
2024 }
2025 }
2026 } catch (Throwable t) { unexpected(t); }
2027
2028 //----------------------------------------------------------------
2029 // Check that reads which are pending when Process.destroy is
2030 // called, get EOF, not IOException("Stream closed").
2031 //----------------------------------------------------------------
2032 try {
2033 final int cases = 4;
2034 for (int i = 0; i < cases; i++) {
2198 } catch (Throwable t) { unexpected(t); }
2199
2200 new File("emptyCommand").delete();
2201
2202 //----------------------------------------------------------------
2203 // Check for correct security permission behavior
2204 //----------------------------------------------------------------
2205 final Policy policy = new Policy();
2206 Policy.setPolicy(policy);
2207 System.setSecurityManager(new SecurityManager());
2208
2209 try {
2210 // No permissions required to CREATE a ProcessBuilder
2211 policy.setPermissions(/* Nothing */);
2212 new ProcessBuilder("env").directory(null).directory();
2213 new ProcessBuilder("env").directory(new File("dir")).directory();
2214 new ProcessBuilder("env").command("??").command();
2215 } catch (Throwable t) { unexpected(t); }
2216
2217 THROWS(SecurityException.class,
2218 new Fun() { void f() throws IOException {
2219 policy.setPermissions(/* Nothing */);
2220 System.getenv("foo");}},
2221 new Fun() { void f() throws IOException {
2222 policy.setPermissions(/* Nothing */);
2223 System.getenv();}},
2224 new Fun() { void f() throws IOException {
2225 policy.setPermissions(/* Nothing */);
2226 new ProcessBuilder("echo").start();}},
2227 new Fun() { void f() throws IOException {
2228 policy.setPermissions(/* Nothing */);
2229 Runtime.getRuntime().exec("echo");}},
2230 new Fun() { void f() throws IOException {
2231 policy.setPermissions(new RuntimePermission("getenv.bar"));
2232 System.getenv("foo");}});
2233
2234 try {
2235 policy.setPermissions(new RuntimePermission("getenv.foo"));
2236 System.getenv("foo");
2237
2238 policy.setPermissions(new RuntimePermission("getenv.*"));
2239 System.getenv("foo");
2240 System.getenv();
2241 new ProcessBuilder().environment();
2242 } catch (Throwable t) { unexpected(t); }
2243
2244
2245 final Permission execPermission
2246 = new FilePermission("<<ALL FILES>>", "execute");
2247
2248 THROWS(SecurityException.class,
2249 new Fun() { void f() throws IOException {
2250 // environment permission by itself insufficient
2251 policy.setPermissions(new RuntimePermission("getenv.*"));
2252 ProcessBuilder pb = new ProcessBuilder("env");
2253 pb.environment().put("foo","bar");
2254 pb.start();}},
2255 new Fun() { void f() throws IOException {
2256 // exec permission by itself insufficient
2257 policy.setPermissions(execPermission);
2258 ProcessBuilder pb = new ProcessBuilder("env");
2259 pb.environment().put("foo","bar");
2260 pb.start();}});
2261
2262 try {
2263 // Both permissions? OK.
2264 policy.setPermissions(new RuntimePermission("getenv.*"),
2265 execPermission);
2266 ProcessBuilder pb = new ProcessBuilder("env");
2267 pb.environment().put("foo","bar");
2268 Process p = pb.start();
2269 closeStreams(p);
2270 } catch (IOException e) { // OK
2271 } catch (Throwable t) { unexpected(t); }
2272
2273 try {
2274 // Don't need environment permission unless READING environment
2275 policy.setPermissions(execPermission);
2276 Runtime.getRuntime().exec("env", new String[]{});
2277 } catch (IOException e) { // OK
2278 } catch (Throwable t) { unexpected(t); }
2279
2280 try {
2568 return sb.toString();
2569 }
2570 }
2571
2572 //--------------------- Infrastructure ---------------------------
2573 static volatile int passed = 0, failed = 0;
2574 static void pass() {passed++;}
2575 static void fail() {failed++; Thread.dumpStack();}
2576 static void fail(String msg) {System.out.println(msg); fail();}
2577 static void unexpected(Throwable t) {failed++; t.printStackTrace();}
2578 static void check(boolean cond) {if (cond) pass(); else fail();}
2579 static void check(boolean cond, String m) {if (cond) pass(); else fail(m);}
2580 static void equal(Object x, Object y) {
2581 if (x == null ? y == null : x.equals(y)) pass();
2582 else fail(">'" + x + "'<" + " not equal to " + "'" + y + "'");}
2583
2584 public static void main(String[] args) throws Throwable {
2585 try {realMain(args);} catch (Throwable t) {unexpected(t);}
2586 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
2587 if (failed > 0) throw new AssertionError("Some tests failed");}
2588 private static abstract class Fun {abstract void f() throws Throwable;}
2589 static void THROWS(Class<? extends Throwable> k, Fun... fs) {
2590 for (Fun f : fs)
2591 try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
2592 catch (Throwable t) {
2593 if (k.isAssignableFrom(t.getClass())) pass();
2594 else unexpected(t);}}
2595 }
|
1 /*
2 * Copyright (c) 2003, 2014, 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 */
920 //----------------------------------------------------------------
921 pb.inheritIO();
922 checkRedirects(pb, INHERIT, INHERIT, INHERIT);
923
924 //----------------------------------------------------------------
925 // Check setters and getters agree
926 //----------------------------------------------------------------
927 pb.redirectInput(ifile);
928 equal(pb.redirectInput().file(), ifile);
929 equal(pb.redirectInput(), Redirect.from(ifile));
930
931 pb.redirectOutput(ofile);
932 equal(pb.redirectOutput().file(), ofile);
933 equal(pb.redirectOutput(), Redirect.to(ofile));
934
935 pb.redirectError(efile);
936 equal(pb.redirectError().file(), efile);
937 equal(pb.redirectError(), Redirect.to(efile));
938
939 THROWS(IllegalArgumentException.class,
940 () -> pb.redirectInput(Redirect.to(ofile)),
941 () -> pb.redirectOutput(Redirect.from(ifile)),
942 () -> pb.redirectError(Redirect.from(ifile)));
943
944 THROWS(IOException.class,
945 // Input file does not exist
946 () -> pb.start());
947 setFileContents(ifile, "standard input");
948
949 //----------------------------------------------------------------
950 // Writing to non-existent files
951 //----------------------------------------------------------------
952 {
953 ProcessResults r = run(pb);
954 equal(r.exitValue(), 0);
955 equal(fileContents(ofile), "standard output");
956 equal(fileContents(efile), "standard error");
957 equal(r.out(), "");
958 equal(r.err(), "");
959 ofile.delete();
960 efile.delete();
961 }
962
963 //----------------------------------------------------------------
964 // Both redirectErrorStream + redirectError
965 //----------------------------------------------------------------
966 {
1062
1063 // Read access to current directory is always granted;
1064 // So create a tmpfile for input instead.
1065 final File tmpFile = File.createTempFile("Basic", "tmp");
1066 setFileContents(tmpFile, "standard input");
1067
1068 final Policy policy = new Policy();
1069 Policy.setPolicy(policy);
1070 System.setSecurityManager(new SecurityManager());
1071 try {
1072 final Permission xPermission
1073 = new FilePermission("<<ALL FILES>>", "execute");
1074 final Permission rxPermission
1075 = new FilePermission("<<ALL FILES>>", "read,execute");
1076 final Permission wxPermission
1077 = new FilePermission("<<ALL FILES>>", "write,execute");
1078 final Permission rwxPermission
1079 = new FilePermission("<<ALL FILES>>", "read,write,execute");
1080
1081 THROWS(SecurityException.class,
1082 () -> { policy.setPermissions(xPermission);
1083 redirectIO(pb, from(tmpFile), PIPE, PIPE);
1084 pb.start();},
1085 () -> { policy.setPermissions(rxPermission);
1086 redirectIO(pb, PIPE, to(ofile), PIPE);
1087 pb.start();},
1088 () -> { policy.setPermissions(rxPermission);
1089 redirectIO(pb, PIPE, PIPE, to(efile));
1090 pb.start();});
1091
1092 {
1093 policy.setPermissions(rxPermission);
1094 redirectIO(pb, from(tmpFile), PIPE, PIPE);
1095 ProcessResults r = run(pb);
1096 equal(r.out(), "standard output");
1097 equal(r.err(), "standard error");
1098 }
1099
1100 {
1101 policy.setPermissions(wxPermission);
1102 redirectIO(pb, PIPE, to(ofile), to(efile));
1103 Process p = pb.start();
1104 new PrintStream(p.getOutputStream()).print("standard input");
1105 p.getOutputStream().close();
1106 ProcessResults r = run(p);
1107 policy.setPermissions(rwxPermission);
1108 equal(fileContents(ofile), "standard output");
1109 equal(fileContents(efile), "standard error");
1110 }
1233 if (Windows.is()) {
1234 pb.environment().put("SystemRoot", systemRoot);
1235 }
1236 if (AIX.is()) {
1237 pb.environment().put("LIBPATH", libpath);
1238 }
1239 String result = getenvInChild(pb);
1240 if (MacOSX.is()) {
1241 result = removeMacExpectedVars(result);
1242 }
1243 if (AIX.is()) {
1244 result = removeAixExpectedVars(result);
1245 }
1246 equal(result, expected);
1247 } catch (Throwable t) { unexpected(t); }
1248
1249 //----------------------------------------------------------------
1250 // System.getenv() is read-only.
1251 //----------------------------------------------------------------
1252 THROWS(UnsupportedOperationException.class,
1253 () -> getenv().put("FOO","BAR"),
1254 () -> getenv().remove("PATH"),
1255 () -> getenv().keySet().remove("PATH"),
1256 () -> getenv().values().remove("someValue"));
1257
1258 try {
1259 Collection<Map.Entry<String,String>> c = getenv().entrySet();
1260 if (! c.isEmpty())
1261 try {
1262 c.iterator().next().setValue("foo");
1263 fail("Expected UnsupportedOperationException not thrown");
1264 } catch (UnsupportedOperationException e) {} // OK
1265 } catch (Throwable t) { unexpected(t); }
1266
1267 //----------------------------------------------------------------
1268 // System.getenv() always returns the same object in our implementation.
1269 //----------------------------------------------------------------
1270 try {
1271 check(System.getenv() == System.getenv());
1272 } catch (Throwable t) { unexpected(t); }
1273
1274 //----------------------------------------------------------------
1275 // You can't create an env var name containing "=",
1276 // or an env var name or value containing NUL.
1277 //----------------------------------------------------------------
1278 {
1279 final Map<String,String> m = new ProcessBuilder().environment();
1280 THROWS(IllegalArgumentException.class,
1281 () -> m.put("FOO=","BAR"),
1282 () -> m.put("FOO\u0000","BAR"),
1283 () -> m.put("FOO","BAR\u0000"));
1284 }
1285
1286 //----------------------------------------------------------------
1287 // Commands must never be null.
1288 //----------------------------------------------------------------
1289 THROWS(NullPointerException.class,
1290 () -> new ProcessBuilder((List<String>)null),
1291 () -> new ProcessBuilder().command((List<String>)null));
1292
1293 //----------------------------------------------------------------
1294 // Put in a command; get the same one back out.
1295 //----------------------------------------------------------------
1296 try {
1297 List<String> command = new ArrayList<String>();
1298 ProcessBuilder pb = new ProcessBuilder(command);
1299 check(pb.command() == command);
1300 List<String> command2 = new ArrayList<String>(2);
1301 command2.add("foo");
1302 command2.add("bar");
1303 pb.command(command2);
1304 check(pb.command() == command2);
1305 pb.command("foo", "bar");
1306 check(pb.command() != command2 && pb.command().equals(command2));
1307 pb.command(command2);
1308 command2.add("baz");
1309 equal(pb.command().get(2), "baz");
1310 } catch (Throwable t) { unexpected(t); }
1311
1312 //----------------------------------------------------------------
1313 // Commands must contain at least one element.
1314 //----------------------------------------------------------------
1315 THROWS(IndexOutOfBoundsException.class,
1316 () -> new ProcessBuilder().start(),
1317 () -> new ProcessBuilder(new ArrayList<String>()).start(),
1318 () -> Runtime.getRuntime().exec(new String[]{}));
1319
1320 //----------------------------------------------------------------
1321 // Commands must not contain null elements at start() time.
1322 //----------------------------------------------------------------
1323 THROWS(NullPointerException.class,
1324 () -> new ProcessBuilder("foo",null,"bar").start(),
1325 () -> new ProcessBuilder((String)null).start(),
1326 () -> new ProcessBuilder(new String[]{null}).start(),
1327 () -> new ProcessBuilder(new String[]{"foo",null,"bar"}).start());
1328
1329 //----------------------------------------------------------------
1330 // Command lists are growable.
1331 //----------------------------------------------------------------
1332 try {
1333 new ProcessBuilder().command().add("foo");
1334 new ProcessBuilder("bar").command().add("foo");
1335 new ProcessBuilder(new String[]{"1","2"}).command().add("3");
1336 } catch (Throwable t) { unexpected(t); }
1337
1338 //----------------------------------------------------------------
1339 // Nulls in environment updates generate NullPointerException
1340 //----------------------------------------------------------------
1341 try {
1342 final Map<String,String> env = new ProcessBuilder().environment();
1343 THROWS(NullPointerException.class,
1344 () -> env.put("foo",null),
1345 () -> env.put(null,"foo"),
1346 () -> env.remove(null),
1347 () -> { for (Map.Entry<String,String> e : env.entrySet())
1348 e.setValue(null);},
1349 () -> Runtime.getRuntime().exec(new String[]{"foo"},
1350 new String[]{null}));
1351 } catch (Throwable t) { unexpected(t); }
1352
1353 //----------------------------------------------------------------
1354 // Non-String types in environment updates generate ClassCastException
1355 //----------------------------------------------------------------
1356 try {
1357 final Map<String,String> env = new ProcessBuilder().environment();
1358 THROWS(ClassCastException.class,
1359 () -> env.remove(TRUE),
1360 () -> env.keySet().remove(TRUE),
1361 () -> env.values().remove(TRUE),
1362 () -> env.entrySet().remove(TRUE));
1363 } catch (Throwable t) { unexpected(t); }
1364
1365 //----------------------------------------------------------------
1366 // Check query operations on environment maps
1367 //----------------------------------------------------------------
1368 try {
1369 List<Map<String,String>> envs =
1370 new ArrayList<Map<String,String>>(2);
1371 envs.add(System.getenv());
1372 envs.add(new ProcessBuilder().environment());
1373 for (final Map<String,String> env : envs) {
1374 //----------------------------------------------------------------
1375 // Nulls in environment queries are forbidden.
1376 //----------------------------------------------------------------
1377 THROWS(NullPointerException.class,
1378 () -> getenv(null),
1379 () -> env.get(null),
1380 () -> env.containsKey(null),
1381 () -> env.containsValue(null),
1382 () -> env.keySet().contains(null),
1383 () -> env.values().contains(null));
1384
1385 //----------------------------------------------------------------
1386 // Non-String types in environment queries are forbidden.
1387 //----------------------------------------------------------------
1388 THROWS(ClassCastException.class,
1389 () -> env.get(TRUE),
1390 () -> env.containsKey(TRUE),
1391 () -> env.containsValue(TRUE),
1392 () -> env.keySet().contains(TRUE),
1393 () -> env.values().contains(TRUE));
1394
1395 //----------------------------------------------------------------
1396 // Illegal String values in environment queries are (grumble) OK
1397 //----------------------------------------------------------------
1398 equal(env.get("\u0000"), null);
1399 check(! env.containsKey("\u0000"));
1400 check(! env.containsValue("\u0000"));
1401 check(! env.keySet().contains("\u0000"));
1402 check(! env.values().contains("\u0000"));
1403 }
1404
1405 } catch (Throwable t) { unexpected(t); }
1406
1407 try {
1408 final Set<Map.Entry<String,String>> entrySet =
1409 new ProcessBuilder().environment().entrySet();
1410 THROWS(NullPointerException.class,
1411 () -> entrySet.contains(null));
1412 THROWS(ClassCastException.class,
1413 () -> entrySet.contains(TRUE),
1414 () -> entrySet.contains(
1415 new SimpleImmutableEntry<Boolean,String>(TRUE,"")));
1416
1417 check(! entrySet.contains
1418 (new SimpleImmutableEntry<String,String>("", "")));
1419 } catch (Throwable t) { unexpected(t); }
1420
1421 //----------------------------------------------------------------
1422 // Put in a directory; get the same one back out.
1423 //----------------------------------------------------------------
1424 try {
1425 ProcessBuilder pb = new ProcessBuilder();
1426 File foo = new File("foo");
1427 equal(pb.directory(), null);
1428 equal(pb.directory(foo).directory(), foo);
1429 equal(pb.directory(null).directory(), null);
1430 } catch (Throwable t) { unexpected(t); }
1431
1432 //----------------------------------------------------------------
1433 // If round-trip conversion works, check envvar pass-through to child
1434 //----------------------------------------------------------------
1435 try {
1865 try {
1866 List<String> childArgs = new ArrayList<String>(javaChildArgs);
1867 childArgs.add("PATH search algorithm");
1868 ProcessBuilder pb = new ProcessBuilder(childArgs);
1869 pb.environment().put("PATH", "dir1:dir2:");
1870 ProcessResults r = run(pb);
1871 equal(r.out(), "");
1872 equal(r.err(), "");
1873 equal(r.exitValue(), True.exitValue());
1874 } catch (Throwable t) { unexpected(t); }
1875
1876 //----------------------------------------------------------------
1877 // Parent's, not child's PATH is used
1878 //----------------------------------------------------------------
1879 try {
1880 new File("suBdiR").mkdirs();
1881 copy("/bin/true", "suBdiR/unliKely");
1882 final ProcessBuilder pb =
1883 new ProcessBuilder(new String[]{"unliKely"});
1884 pb.environment().put("PATH", "suBdiR");
1885 THROWS(IOException.class, () -> pb.start());
1886 } catch (Throwable t) { unexpected(t);
1887 } finally {
1888 new File("suBdiR/unliKely").delete();
1889 new File("suBdiR").delete();
1890 }
1891 }
1892
1893 //----------------------------------------------------------------
1894 // Attempt to start bogus program ""
1895 //----------------------------------------------------------------
1896 try {
1897 new ProcessBuilder("").start();
1898 fail("Expected IOException not thrown");
1899 } catch (IOException e) {
1900 String m = e.getMessage();
1901 if (EnglishUnix.is() &&
1902 ! matches(m, "No such file or directory"))
1903 unexpected(e);
1904 } catch (Throwable t) { unexpected(t); }
1905
1938
1939 //----------------------------------------------------------------
1940 // Attempt to write 4095 bytes to the pipe buffer without a
1941 // reader to drain it would deadlock, if not for the fact that
1942 // interprocess pipe buffers are at least 4096 bytes.
1943 //
1944 // Also, check that available reports all the bytes expected
1945 // in the pipe buffer, and that I/O operations do the expected
1946 // things.
1947 //----------------------------------------------------------------
1948 try {
1949 List<String> childArgs = new ArrayList<String>(javaChildArgs);
1950 childArgs.add("print4095");
1951 final int SIZE = 4095;
1952 final Process p = new ProcessBuilder(childArgs).start();
1953 print4095(p.getOutputStream(), (byte) '!'); // Might hang!
1954 p.waitFor(); // Might hang!
1955 equal(SIZE, p.getInputStream().available());
1956 equal(SIZE, p.getErrorStream().available());
1957 THROWS(IOException.class,
1958 () -> { p.getOutputStream().write((byte) '!');
1959 p.getOutputStream().flush();});
1960
1961 final byte[] bytes = new byte[SIZE + 1];
1962 equal(SIZE, p.getInputStream().read(bytes));
1963 for (int i = 0; i < SIZE; i++)
1964 equal((byte) '!', bytes[i]);
1965 equal((byte) 0, bytes[SIZE]);
1966
1967 equal(SIZE, p.getErrorStream().read(bytes));
1968 for (int i = 0; i < SIZE; i++)
1969 equal((byte) 'E', bytes[i]);
1970 equal((byte) 0, bytes[SIZE]);
1971
1972 equal(0, p.getInputStream().available());
1973 equal(0, p.getErrorStream().available());
1974 equal(-1, p.getErrorStream().read());
1975 equal(-1, p.getInputStream().read());
1976
1977 equal(p.exitValue(), 5);
1978
1979 p.getInputStream().close();
1980 p.getErrorStream().close();
1981 try { p.getOutputStream().close(); } catch (IOException flushFailed) { }
1982
1983 InputStream[] streams = { p.getInputStream(), p.getErrorStream() };
1984 for (final InputStream in : streams) {
1985 Fun[] ops = {
1986 () -> in.read(),
1987 () -> in.read(bytes),
1988 () -> in.available()
1989 };
1990 for (Fun op : ops) {
1991 try {
1992 op.f();
1993 fail();
1994 } catch (IOException expected) {
1995 check(expected.getMessage()
1996 .matches("[Ss]tream [Cc]losed"));
1997 }
1998 }
1999 }
2000 } catch (Throwable t) { unexpected(t); }
2001
2002 //----------------------------------------------------------------
2003 // Check that reads which are pending when Process.destroy is
2004 // called, get EOF, not IOException("Stream closed").
2005 //----------------------------------------------------------------
2006 try {
2007 final int cases = 4;
2008 for (int i = 0; i < cases; i++) {
2172 } catch (Throwable t) { unexpected(t); }
2173
2174 new File("emptyCommand").delete();
2175
2176 //----------------------------------------------------------------
2177 // Check for correct security permission behavior
2178 //----------------------------------------------------------------
2179 final Policy policy = new Policy();
2180 Policy.setPolicy(policy);
2181 System.setSecurityManager(new SecurityManager());
2182
2183 try {
2184 // No permissions required to CREATE a ProcessBuilder
2185 policy.setPermissions(/* Nothing */);
2186 new ProcessBuilder("env").directory(null).directory();
2187 new ProcessBuilder("env").directory(new File("dir")).directory();
2188 new ProcessBuilder("env").command("??").command();
2189 } catch (Throwable t) { unexpected(t); }
2190
2191 THROWS(SecurityException.class,
2192 () -> { policy.setPermissions(/* Nothing */);
2193 System.getenv("foo");},
2194 () -> { policy.setPermissions(/* Nothing */);
2195 System.getenv();},
2196 () -> { policy.setPermissions(/* Nothing */);
2197 new ProcessBuilder("echo").start();},
2198 () -> { policy.setPermissions(/* Nothing */);
2199 Runtime.getRuntime().exec("echo");},
2200 () -> { policy.setPermissions(
2201 new RuntimePermission("getenv.bar"));
2202 System.getenv("foo");});
2203
2204 try {
2205 policy.setPermissions(new RuntimePermission("getenv.foo"));
2206 System.getenv("foo");
2207
2208 policy.setPermissions(new RuntimePermission("getenv.*"));
2209 System.getenv("foo");
2210 System.getenv();
2211 new ProcessBuilder().environment();
2212 } catch (Throwable t) { unexpected(t); }
2213
2214
2215 final Permission execPermission
2216 = new FilePermission("<<ALL FILES>>", "execute");
2217
2218 THROWS(SecurityException.class,
2219 () -> { // environment permission by itself insufficient
2220 policy.setPermissions(new RuntimePermission("getenv.*"));
2221 ProcessBuilder pb = new ProcessBuilder("env");
2222 pb.environment().put("foo","bar");
2223 pb.start();},
2224 () -> { // exec permission by itself insufficient
2225 policy.setPermissions(execPermission);
2226 ProcessBuilder pb = new ProcessBuilder("env");
2227 pb.environment().put("foo","bar");
2228 pb.start();});
2229
2230 try {
2231 // Both permissions? OK.
2232 policy.setPermissions(new RuntimePermission("getenv.*"),
2233 execPermission);
2234 ProcessBuilder pb = new ProcessBuilder("env");
2235 pb.environment().put("foo","bar");
2236 Process p = pb.start();
2237 closeStreams(p);
2238 } catch (IOException e) { // OK
2239 } catch (Throwable t) { unexpected(t); }
2240
2241 try {
2242 // Don't need environment permission unless READING environment
2243 policy.setPermissions(execPermission);
2244 Runtime.getRuntime().exec("env", new String[]{});
2245 } catch (IOException e) { // OK
2246 } catch (Throwable t) { unexpected(t); }
2247
2248 try {
2536 return sb.toString();
2537 }
2538 }
2539
2540 //--------------------- Infrastructure ---------------------------
2541 static volatile int passed = 0, failed = 0;
2542 static void pass() {passed++;}
2543 static void fail() {failed++; Thread.dumpStack();}
2544 static void fail(String msg) {System.out.println(msg); fail();}
2545 static void unexpected(Throwable t) {failed++; t.printStackTrace();}
2546 static void check(boolean cond) {if (cond) pass(); else fail();}
2547 static void check(boolean cond, String m) {if (cond) pass(); else fail(m);}
2548 static void equal(Object x, Object y) {
2549 if (x == null ? y == null : x.equals(y)) pass();
2550 else fail(">'" + x + "'<" + " not equal to " + "'" + y + "'");}
2551
2552 public static void main(String[] args) throws Throwable {
2553 try {realMain(args);} catch (Throwable t) {unexpected(t);}
2554 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
2555 if (failed > 0) throw new AssertionError("Some tests failed");}
2556 @FunctionalInterface interface Fun {void f() throws Throwable;}
2557 static void THROWS(Class<? extends Throwable> k, Fun... fs) {
2558 for (Fun f : fs)
2559 try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
2560 catch (Throwable t) {
2561 if (k.isAssignableFrom(t.getClass())) pass();
2562 else unexpected(t);}}
2563 }
|