blob: 8f93df67198ff8922d776f6b64e4dbb7e0fe8c2b [file] [log] [blame]
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
/*
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
public class Arrrghs{
/**
* A group of tests to ensure that arguments are passed correctly to
* a child java process upon a re-exec, this typically happens when
* a version other than the one being executed is requested by the user.
*
* History: these set of tests were part of Arrrghs.sh. The MKS shell
* implementations are notoriously buggy. Implementing these tests purely
* in Java is not only portable but also robust.
*
*/
/* Do not instantiate */
private Arrrghs() {}
static String javaCmd;
// The version string to force a re-exec
final static String VersionStr = "-version:1.1+";
// The Cookie or the pattern we match in the debug output.
final static String Cookie = "ReExec Args: ";
private static boolean _debug = Boolean.getBoolean("Arrrghs.Debug");
private static boolean isWindows = System.getProperty("os.name", "unknown").startsWith("Windows");
private static int exitValue = 0;
private static void doUsage(String message) {
if (message != null) System.out.println("Error: " + message);
System.out.println("Usage: Arrrghs path_to_java");
System.exit(1);
}
/*
* SIGH, On Windows all strings are quoted, we need to unwrap it
*/
private static String removeExtraQuotes(String in) {
if (isWindows) {
// Trim the string and remove the enclosed quotes if any.
in = in.trim();
if (in.startsWith("\"") && in.endsWith("\"")) {
return in.substring(1, in.length()-1);
}
}
return in;
}
/*
* This method detects the cookie in the output stream of the process.
*/
private static boolean detectCookie(InputStream istream, String expectedArguments) throws IOException {
BufferedReader rd = new BufferedReader(new InputStreamReader(istream));
boolean retval = false;
String in = rd.readLine();
while (in != null) {
if (_debug) System.out.println(in);
if (in.startsWith(Cookie)) {
String detectedArgument = removeExtraQuotes(in.substring(Cookie.length()));
if (expectedArguments.equals(detectedArgument)) {
retval = true;
} else {
System.out.println("Error: Expected Arguments\t:'" + expectedArguments + "'");
System.out.println(" Detected Arguments\t:'" + detectedArgument + "'");
}
// Return the value asap if not in debug mode.
if (!_debug) {
rd.close();
istream.close();
return retval;
}
}
in = rd.readLine();
}
return retval;
}
private static boolean doExec0(ProcessBuilder pb, String expectedArguments) {
boolean retval = false;
try {
pb.redirectErrorStream(_debug);
Process p = pb.start();
retval = detectCookie(p.getInputStream(), expectedArguments);
p.waitFor();
p.destroy();
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex.getMessage());
}
return retval;
}
/**
* This method return true if the expected and detected arguments are the same.
* Quoting could cause dissimilar testArguments and expected arguments.
*/
static boolean doExec(String testArguments, String expectedPattern) {
ProcessBuilder pb = new ProcessBuilder(javaCmd, VersionStr, testArguments);
Map<String, String> env = pb.environment();
env.put("_JAVA_LAUNCHER_DEBUG", "true");
return doExec0(pb, testArguments);
}
/**
* A convenience method for identical test pattern and expected arguments
*/
static boolean doExec(String testPattern) {
return doExec(testPattern, testPattern);
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
if (args.length < 1 && args[0] == null) {
doUsage("Invalid number of arguments");
}
javaCmd = args[0];
if (!new File(javaCmd).canExecute()) {
if (isWindows && new File(javaCmd + ".exe").canExecute()) {
javaCmd = javaCmd + ".exe";
} else {
doUsage("The java executable must exist");
}
}
if (_debug) System.out.println("Starting Arrrghs tests");
// Basic test
if (!doExec("-a -b -c -d")) exitValue++;
// Basic test with many spaces
if (!doExec("-a -b -c -d")) exitValue++;
// Quoted whitespace does matter ?
if (!doExec("-a \"\"-b -c\"\" -d")) exitValue++;
// Escaped quotes outside of quotes as literals
if (!doExec("-a \\\"-b -c\\\" -d")) exitValue++;
// Check for escaped quotes inside of quotes as literal
if (!doExec("-a \"-b \\\"stuff\\\"\" -c -d")) exitValue++;
// A quote preceeded by an odd number of slashes is a literal quote
if (!doExec("-a -b\\\\\\\" -c -d")) exitValue++;
// A quote preceeded by an even number of slashes is a literal quote
// see 6214916.
if (!doExec("-a -b\\\\\\\\\" -c -d")) exitValue++;
// Make sure that whitespace doesn't interfere with the removal of the
// appropriate tokens. (space-tab-space preceeds -jre-restict-search).
if (!doExec("-a -b \t -jre-restrict-search -c -d","-a -b -c -d")) exitValue++;
// Make sure that the mJRE tokens being stripped, aren't stripped if
// they happen to appear as arguments to the main class.
if (!doExec("foo -version:1.1+")) exitValue++;
System.out.println("Completed Arrrghs arguments quoting/matching tests with " + exitValue + " errors");
System.exit(exitValue);
}
}