/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689
* 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313
* 6464154 6523983 6206031 4960438 6631352 6631966 6850957 6850958
* 4947220 7018606 7034570
* @summary Basic tests for Process and Environment Variable code
* @author Martin Buchholz
*/
public class Basic {
/* used for Windows only */
/* used for Mac OS X only */
int c;
while ((c = r.read()) > 0)
if (c != '\r')
}
return output;
}
try {
} catch (Throwable t) {
unexpected(t);
return "";
}
}
try {
} catch (Throwable t) {
unexpected(t);
return "";
}
}
String failureMsg) {
failureMsg + "\n" +
}
}
}
// compare windows-style, by canonicalizing to upper case,
// not lower case as String.compareToIgnoreCase does
private static class WindowsComparator
implements Comparator<String> {
}
}
}
"-----------------------------------------------------";
fail("Sorted string contents differ");
}
}
}
}
try {
return winEnvFilter
} else {
}
}
try {
} else {
return commandOutput(pb);
}
}
try {
} catch (Throwable t) { unexpected(t); }
}
private interface EnvironmentFrobber {
}
try {
} catch (Throwable t) { unexpected(t); }
}
try {
} catch (Throwable t) { unexpected(t); }
}
try {
} catch (Throwable t) { unexpected(t); }
}
}
// Ignore magic environment variables added by the launcher
.append('=')
.append(',');
}
byte[] bytes = new byte[4095];
}
try {
fail("Expected IOException not thrown");
} catch (IOException e) {
String m = e.getMessage();
if (EnglishUnix.is() &&
! matches(m, "Permission denied"))
unexpected(e);
} catch (Throwable t) { unexpected(t); }
}
public static class JavaChild {
if (r.exitValue() != 0)
default: throw new InternalError();
}
.getCanonicalPath());
// You might think the system streams would be
// buffered, and in fact they are implemented using
// BufferedOutputStream, but each and every print
// causes immediate operating system I/O.
for (final ProcessBuilder pb :
}
for (final ProcessBuilder pb :
try {
// Not on PATH at all; directories don't exist
try {
fail("Expected IOException not thrown");
} catch (IOException e) {
String m = e.getMessage();
if (EnglishUnix.is() &&
! matches(m, "No such file"))
unexpected(e);
} catch (Throwable t) { unexpected(t); }
// Not on PATH at all; directories exist
try {
fail("Expected IOException not thrown");
} catch (IOException e) {
String m = e.getMessage();
if (EnglishUnix.is() &&
! matches(m, "No such file"))
unexpected(e);
} catch (Throwable t) { unexpected(t); }
// Can't execute a directory -- permission denied
// Report EACCES errno
// continue searching if EACCES
// Check empty PATH component means current directory.
//
// While we're here, let's test different kinds of
// Unix executables, and PATH vs explicit searching.
new String[][] {
new String[] {"./prog"},
cmd}) {
// "Normal" binaries
// Interpreter scripts with #!
prog.setExecutable(true);
prog.setExecutable(true);
// Traditional shell scripts without #!
prog.setExecutable(true);
prog.setExecutable(true);
}
// Test Unix interpreter scripts
dir1Prog.setExecutable(true);
// Test traditional shell scripts without #!
dir1Prog.setExecutable(true);
// If prog found on both parent and child's PATH,
// parent's is used.
} finally {
// cleanup
}
}
}
else throw new Error("JavaChild invocation error");
}
}
}
try {
} catch (Throwable t) { unexpected(t); }
}
return commandOutput(pb);
}
}
}
}
}
"Basic$JavaChild"});
try {
// If round trip conversion works, should be able to set env vars
// correctly in child.
}
} catch (Throwable t) { unexpected(t); }
}
static class Windows {
private static final boolean is =
}
static class Unix {
private static final boolean is =
}
static class UnicodeOS {
private static final boolean is =
// MacOS X would probably also qualify
}
static class MacOSX {
}
static class True {
}
private static class False {
private static int exitValue0() {
try {
return -1;
else {
return rc;
}
}
}
static class EnglishUnix {
}
/** Returns true if we can expect English OS error strings */
}
}
} else {
return "";
}
}
/* Only used for Mac OS X --
* Mac OS X adds the variable __CF_USER_TEXT_ENCODING to an empty
* environment. The environment variable JAVA_MAIN_CLASS_<pid> should also
* be set in Mac OS X.
* Check for both by removing them both from the list of env variables.
*/
// Check for __CF_USER_TEXT_ENCODING
fail("Environment variable __CF_USER_TEXT_ENCODING not set. "
+ "MAC OS X should set __CF_USER_TEXT_ENCODING in "
+ "an empty environment.");
}
// Check for JAVA_MAIN_CLASS_<pid>
"JAVA_MAIN_CLASS_\\d+=Basic.JavaChild,");
fail("JAVA_MAIN_CLASS_<pid> not set. "
+ "Should be set in Mac OS X env.");
}
}
}
try {
}
} catch (Throwable t) { unexpected(t); }
}
try {
}
} catch (Throwable t) { unexpected(t); }
}
}
}
try {
w.close();
} catch (Throwable t) { unexpected(t); }
}
try {
char[] buffer = new char[1024];
int n;
r.close();
}
//----------------------------------------------------------------
// Check mutual inequality of different types of Redirect
//----------------------------------------------------------------
{ PIPE,
};
//----------------------------------------------------------------
// Check basic properties of different types of Redirect
//----------------------------------------------------------------
"redirect to read from file \"ifile\"");
"redirect to write to file \"ofile\"");
"redirect to append to file \"efile\"");
//----------------------------------------------------------------
// Check initial values of redirects
//----------------------------------------------------------------
//----------------------------------------------------------------
// Check inheritIO
//----------------------------------------------------------------
//----------------------------------------------------------------
// Check setters and getters agree
//----------------------------------------------------------------
THROWS(IllegalArgumentException.class,
new Fun(){void f() {
new Fun(){void f() {
new Fun(){void f() {
new Fun(){void f() {
THROWS(IOException.class,
// Input file does not exist
//----------------------------------------------------------------
// Writing to non-existent files
//----------------------------------------------------------------
{
}
//----------------------------------------------------------------
// Both redirectErrorStream + redirectError
//----------------------------------------------------------------
{
pb.redirectErrorStream(true);
"standard error" + "standard output");
}
//----------------------------------------------------------------
// Appending to existing files
//----------------------------------------------------------------
{
pb.redirectErrorStream(false);
"ofile-contents" + "standard output");
"efile-contents" + "standard error");
}
//----------------------------------------------------------------
// Replacing existing files
//----------------------------------------------------------------
{
}
//----------------------------------------------------------------
// Appending twice to the same file?
//----------------------------------------------------------------
{
"ofile-contents" +
"standard error" +
"standard output");
}
//----------------------------------------------------------------
// Testing INHERIT is harder.
// Note that this requires __FOUR__ nested JVMs involved in one test,
// if you count the harness JVM.
//----------------------------------------------------------------
{
p.getOutputStream().close();
ProcessResults r = run(p);
}
//----------------------------------------------------------------
// Test security implications of I/O redirection
//----------------------------------------------------------------
// Read access to current directory is always granted;
// So create a tmpfile for input instead.
try {
final Permission xPermission
final Permission rxPermission
final Permission wxPermission
final Permission rwxPermission
THROWS(SecurityException.class,
new Fun() { void f() throws IOException {
new Fun() { void f() throws IOException {
new Fun() { void f() throws IOException {
{
}
{
p.getOutputStream().close();
ProcessResults r = run(p);
}
{
}
} finally {
}
}
try { testIORedirection(); }
catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Basic tests for setting, replacing and deleting envvars
//----------------------------------------------------------------
try {
// New env var
// Modify env var
// Remove env var
// Remove non-existent env var
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Pass Empty environment to child
//----------------------------------------------------------------
try {
}
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// System.getenv() is read-only.
//----------------------------------------------------------------
try {
if (! c.isEmpty())
try {
fail("Expected UnsupportedOperationException not thrown");
} catch (UnsupportedOperationException e) {} // OK
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// System.getenv() always returns the same object in our implementation.
//----------------------------------------------------------------
try {
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// You can't create an env var name containing "=",
// or an env var name or value containing NUL.
//----------------------------------------------------------------
{
THROWS(IllegalArgumentException.class,
}
//----------------------------------------------------------------
// Commands must never be null.
//----------------------------------------------------------------
THROWS(NullPointerException.class,
new Fun(){void f(){
new Fun(){void f(){
//----------------------------------------------------------------
// Put in a command; get the same one back out.
//----------------------------------------------------------------
try {
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Commands must contain at least one element.
//----------------------------------------------------------------
THROWS(IndexOutOfBoundsException.class,
new Fun() { void f() throws IOException {
new ProcessBuilder().start();}},
new Fun() { void f() throws IOException {
new Fun() { void f() throws IOException {
//----------------------------------------------------------------
// Commands must not contain null elements at start() time.
//----------------------------------------------------------------
THROWS(NullPointerException.class,
new Fun() { void f() throws IOException {
new Fun() { void f() throws IOException {
new Fun() { void f() throws IOException {
new Fun() { void f() throws IOException {
//----------------------------------------------------------------
// Command lists are growable.
//----------------------------------------------------------------
try {
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Nulls in environment updates generate NullPointerException
//----------------------------------------------------------------
try {
THROWS(NullPointerException.class,
new Fun(){void f(){
new Fun() { void f() throws IOException {
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Non-String types in environment updates generate ClassCastException
//----------------------------------------------------------------
try {
THROWS(ClassCastException.class,
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Check query operations on environment maps
//----------------------------------------------------------------
try {
//----------------------------------------------------------------
// Nulls in environment queries are forbidden.
//----------------------------------------------------------------
THROWS(NullPointerException.class,
//----------------------------------------------------------------
// Non-String types in environment queries are forbidden.
//----------------------------------------------------------------
THROWS(ClassCastException.class,
//----------------------------------------------------------------
// Illegal String values in environment queries are (grumble) OK
//----------------------------------------------------------------
}
} catch (Throwable t) { unexpected(t); }
try {
THROWS(NullPointerException.class,
THROWS(ClassCastException.class,
new Fun(){void f(){
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Put in a directory; get the same one back out.
//----------------------------------------------------------------
try {
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// If round-trip conversion works, check envvar pass-through to child
//----------------------------------------------------------------
try {
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// A surprisingly large number of ways to delete an environment var.
//----------------------------------------------------------------
// Legally fabricate a ProcessEnvironment.StringEntry,
// even though it's private.
= new ProcessBuilder().environment();
// Subtlety alert.
victim = e;
//----------------------------------------------------------------
// A surprisingly small number of ways to add an environment var.
//----------------------------------------------------------------
testVariableAdder(new EnvironmentFrobber() {
//----------------------------------------------------------------
// A few ways to modify an environment var.
//----------------------------------------------------------------
e.setValue("NewValue");}});
//----------------------------------------------------------------
// Fiddle with environment sizes
//----------------------------------------------------------------
try {
// Check for environment independence
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Check that various map invariants hold
//----------------------------------------------------------------
new ProcessBuilder().environment());
//----------------------------------------------------------------
// Check effects on external "env" command.
//----------------------------------------------------------------
try {
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Test Runtime.exec(...envp...)
// Check for sort order of environment variables on Windows.
//----------------------------------------------------------------
try {
// '+' < 'A' < 'Z' < '_' < 'a' < 'z' < '~'
// On Windows, Java must keep the environment sorted.
// Order is random on Unix, so this test does the sort.
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Test Runtime.exec(...envp...)
// and check SystemRoot gets set automatically on Windows
//----------------------------------------------------------------
try {
"+=+", "_=_", "~=~"};
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// System.getenv() must be consistent with System.getenv(String)
//----------------------------------------------------------------
try {
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Fiddle with working directory in child
//----------------------------------------------------------------
try {
{".", "..", "/", "/bin",
"C:", "c:", "C:/", "c:\\", "\\", "\\bin",
"c:\\windows ", "c:\\Program Files", "c:\\Program Files\\" };
continue;
//dir = new File(dir.getCanonicalPath());
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Working directory with Unicode in child
//----------------------------------------------------------------
try {
"ProcessBuilderDir\u4e00\u4e02");
try {
} finally {
}
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// OOME in child allocating maximally sized array
//----------------------------------------------------------------
try {
javaExe));
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Windows has tricky semi-case-insensitive semantics
//----------------------------------------------------------------
try {
new String[][]
||
"Windows environment variables are not case insensitive");
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Test proper Unicode child environment transfer
//----------------------------------------------------------------
try {
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Test Runtime.exec(...envp...) with envstrings with initial `='
//----------------------------------------------------------------
try {
} else {
}
}
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Test Runtime.exec(...envp...) with envstrings without any `='
//----------------------------------------------------------------
try {
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Test Runtime.exec(...envp...) with envstrings containing NULs
//----------------------------------------------------------------
try {
"FO\u0000=B\u0000R"};
"FO\u0000=B\u0000R"};
} else {
}
}
}
}
: "LC_ALL=C,"),
"Incorrect handling of envstrings containing NULs");
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Test the redirectErrorStream property
//----------------------------------------------------------------
try {
} catch (Throwable t) { unexpected(t); }
try {
{
}
{
pb.redirectErrorStream(true);
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// We can find true and false when PATH is null
//----------------------------------------------------------------
try {
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// PATH search algorithm on Unix
//----------------------------------------------------------------
try {
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Parent's, not child's PATH is used
//----------------------------------------------------------------
try {
final ProcessBuilder pb =
THROWS(IOException.class,
} catch (Throwable t) { unexpected(t);
} finally {
}
}
//----------------------------------------------------------------
// Attempt to start bogus program ""
//----------------------------------------------------------------
try {
fail("Expected IOException not thrown");
} catch (IOException e) {
String m = e.getMessage();
if (EnglishUnix.is() &&
! matches(m, "No such file or directory"))
unexpected(e);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Check that attempt to execute program name with funny
// characters throws an exception containing those characters.
//----------------------------------------------------------------
try {
fail("Expected IOException not thrown");
} catch (IOException e) {
String m = e.getMessage();
if (! matches(m, programName)
|| (EnglishUnix.is()
&& ! matches(m, "No such file or directory")))
unexpected(e);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Attempt to start process in nonexistent directory fails.
//----------------------------------------------------------------
try {
new ProcessBuilder("echo")
.start();
fail("Expected IOException not thrown");
} catch (IOException e) {
String m = e.getMessage();
if (! matches(m, "in directory")
|| (EnglishUnix.is() &&
! matches(m, "No such file or directory")))
unexpected(e);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Attempt to write 4095 bytes to the pipe buffer without a
// reader to drain it would deadlock, if not for the fact that
// interprocess pipe buffers are at least 4096 bytes.
//
// Also, check that available reports all the bytes expected
// in the pipe buffer, and that I/O operations do the expected
// things.
//----------------------------------------------------------------
try {
final int SIZE = 4095;
p.waitFor(); // Might hang!
THROWS(IOException.class,
new Fun(){void f() throws IOException {
p.getOutputStream().flush();
}});
for (int i = 0; i < SIZE; i++)
for (int i = 0; i < SIZE; i++)
p.getInputStream().close();
p.getErrorStream().close();
p.getOutputStream().close();
new Fun(){void f() throws IOException {
new Fun(){void f() throws IOException {
new Fun(){void f() throws IOException {
};
try {
op.f();
fail();
} catch (IOException expected) {
.matches("[Ss]tream [Cc]losed"));
}
}
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Check that reads which are pending when Process.destroy is
// called, get EOF, not IOException("Stream closed").
//----------------------------------------------------------------
try {
final int cases = 4;
for (int i = 0; i < cases; i++) {
final int action = i;
final byte[] bytes = new byte[10];
final InputStream s;
switch (action & 0x1) {
case 0: s = p.getInputStream(); break;
case 1: s = p.getErrorStream(); break;
default: throw new Error();
}
public void run() {
try {
int r;
switch (action & 0x2) {
case 0: r = s.read(); break;
default: throw new Error();
}
equal(-1, r);
} catch (Throwable t) { unexpected(t); }}};
{
"java.lang.UNIXProcess$DeferredCloseInputStream"))
{
deferred = s;
} else {
getDeclaredField("stdout_inner_stream");
deferredField.setAccessible(true);
}
getDeclaredField("useCount");
useCountField.setAccessible(true);
}
} else if (s instanceof BufferedInputStream) {
f.setAccessible(true);
while (unsafe.tryMonitorEnter(s)) {
unsafe.monitorExit(s);
}
}
p.destroy();
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Check that subprocesses which create subprocesses of their
// own do not cause parent to hang waiting for file
// descriptors to be closed.
//----------------------------------------------------------------
try {
public void run() {
catch (IOException e) {
// Check that reader failed because stream was
// asynchronously closed.
// e.printStackTrace();
if (EnglishUnix.is() &&
unexpected(e);
}
catch (Throwable t) { unexpected(t); }}};
p.destroy();
// Subprocess is now dead, but file descriptors remain open.
//----------------------------------------------------------
// There remain unsolved issues with asynchronous close.
// Here's a highly non-portable experiment to demonstrate:
//----------------------------------------------------------
// Initialize signal handler for INTERRUPT_SIGNAL.
// Send INTERRUPT_SIGNAL to every thread in this java.
String[] wakeupJeff = {
// INTERRUPT_SIGNAL == 62 on my machine du jour.
};
// If wakeupJeff worked, reader probably got EBADF.
}
}
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Attempt to start process with insufficient permissions fails.
//----------------------------------------------------------------
try {
fail("Expected IOException not thrown");
} catch (IOException e) {
String m = e.getMessage();
if (EnglishUnix.is() &&
! matches(m, "Permission denied"))
unexpected(e);
} catch (Throwable t) { unexpected(t); }
//----------------------------------------------------------------
// Check for correct security permission behavior
//----------------------------------------------------------------
try {
// No permissions required to CREATE a ProcessBuilder
} catch (Throwable t) { unexpected(t); }
THROWS(SecurityException.class,
new Fun() { void f() throws IOException {
new Fun() { void f() throws IOException {
new Fun() { void f() throws IOException {
new Fun() { void f() throws IOException {
new Fun() { void f() throws IOException {
try {
new ProcessBuilder().environment();
} catch (Throwable t) { unexpected(t); }
final Permission execPermission
THROWS(SecurityException.class,
new Fun() { void f() throws IOException {
// environment permission by itself insufficient
new Fun() { void f() throws IOException {
// exec permission by itself insufficient
try {
// Both permissions? OK.
closeStreams(p);
} catch (IOException e) { // OK
} catch (Throwable t) { unexpected(t); }
try {
// Don't need environment permission unless READING environment
} catch (IOException e) { // OK
} catch (Throwable t) { unexpected(t); }
try {
// Don't need environment permission unless READING environment
} catch (IOException e) { // OK
} catch (Throwable t) { unexpected(t); }
// Restore "normal" state without a security manager
}
try {
p.getOutputStream().close();
p.getInputStream().close();
p.getErrorStream().close();
} catch (Throwable t) { unexpected(t); }
}
//----------------------------------------------------------------
// A Policy class designed to make permissions fiddling very easy.
//----------------------------------------------------------------
perms = new Permissions();
}
return perms;
}
return perms;
}
}
public void refresh() {}
}
throw throwable;
}
}
public void run() {
try {
char[] buf = new char[4096];
int n;
}
} catch (Throwable t) {
throwable = t;
} finally {
}
}
}
try {
}
int exitValue = -1;
new StreamAccumulator(p.getInputStream());
new StreamAccumulator(p.getErrorStream());
try {
} catch (Throwable t) {
throwable = t;
}
}
//----------------------------------------------------------------
// Results of a command
//----------------------------------------------------------------
private static class ProcessResults {
private final int exitValue;
int exitValue,
}
}
}
//--------------------- Infrastructure ---------------------------
else fail(x + " not equal to " + y);}
catch (Throwable t) {
else unexpected(t);}}
}