/* * Copyright (c) 1995, 2022, Oracle and/or its affiliates. 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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.
*/
/* * Shared source for 'java' command line tool. * * If JAVA_ARGS is defined, then acts as a launcher for applications. For * instance, the JDK command line tools such as javac and javadoc (see * makefiles for more details) are built with this program. Any arguments * prefixed with '-J' will be passed directly to the 'java' command.
*/
/* * One job of the launcher is to remove command line options which the * vm does not understand and will not process. These options include * options which select which style of vm is run (e.g. -client and * -server) as well as options which select the data model to use. * Additionally, for tools which invoke an underlying vm "-J-foo" * options are turned into "-foo" options to the vm. This option * filtering is handled in a number of places in the launcher, some of * it in machine-dependent code. In this file, the function * CheckJvmType removes vm style options and TranslateApplicationArgs * removes "-J" prefixes. The CreateExecutionEnvironment function processes * and removes -d<n> options. On unix, there is a possibility that the running * data model may not match to the desired data model, in this case an exec is * required to start the desired model. If the data models match, then * ParseArguments will remove the -d<n> flags. If the data models do not match * the CreateExecutionEnviroment will remove the -d<n> flags.
*/
#include <assert.h>
#include"java.h" #include"jni.h"
/* * A NOTE TO DEVELOPERS: For performance reasons it is important that * the program image remain relatively small until after SelectVersion * CreateExecutionEnvironment have finished their possibly recursive * processing. Watch everything, but resist all temptations to use Java * interfaces.
*/
#define USE_STDERR JNI_TRUE /* we usually print to stderr */ #define USE_STDOUT JNI_FALSE
static jboolean printVersion = JNI_FALSE; /* print and exit */ static jboolean showVersion = JNI_FALSE; /* print but continue */ static jboolean printUsage = JNI_FALSE; /* print and exit*/ static jboolean printTo = USE_STDERR; /* where to print version/usage */ static jboolean printXUsage = JNI_FALSE; /* print and exit*/ static jboolean dryRun = JNI_FALSE; /* initialize VM and exit */ staticchar *showSettings = NULL; /* print but continue */ static jboolean showResolvedModules = JNI_FALSE; static jboolean listModules = JNI_FALSE; staticchar *describeModule = NULL; static jboolean validateModules = JNI_FALSE;
/* * Entries for splash screen environment variables. * putenv is performed in SelectVersion. We need * them in memory until UnsetEnv, so they are made static * global instead of auto local.
*/ staticchar* splash_file_entry = NULL; staticchar* splash_jar_entry = NULL;
/* * List of VM options to be specified when the VM is created.
*/ static JavaVMOption *options; staticint numOptions, maxOptions;
/* * This reports error. VM will not be created and no usage is printed.
*/ #define REPORT_ERROR(AC_ok, AC_failure_message, AC_questionable_arg) \ do { \ if (!AC_ok) { \
JLI_ReportErrorMessage(AC_failure_message, AC_questionable_arg); \
printUsage = JNI_FALSE; \
*pret = 1; \ return JNI_FALSE; \
} \
} while (JNI_FALSE)
/* * Running Java code in primordial thread caused many problems. We will * create a new thread to invoke JVM. See 6316197 for more information.
*/ static jlong threadStackSize = 0; /* stack size of the new thread */ static jlong maxHeapSize = 0; /* max heap size */ static jlong initialHeapSize = 0; /* initial heap size */
/* * A minimum initial-thread stack size suitable for most platforms. * This is the minimum amount of stack needed to load the JVM such * that it can reject a too small -Xss value. If this is too small * JVM initialization would cause a StackOverflowError.
*/ #ifndef STACK_SIZE_MINIMUM #define STACK_SIZE_MINIMUM (64 * KB) #endif
/* * Entry point.
*/
JNIEXPORT int JNICALL
JLI_Launch(int argc, char ** argv, /* main argc, argv */ int jargc, constchar** jargv, /* java args */ int appclassc, constchar** appclassv, /* app classpath */ constchar* fullversion, /* full version defined */ constchar* dotversion, /* UNUSED dot version defined */ constchar* pname, /* program name */ constchar* lname, /* launcher name */
jboolean javaargs, /* JAVA_ARGS */
jboolean cpwildcard, /* classpath wildcard*/
jboolean javaw, /* windows-only javaw */
jint ergo /* unused */
)
{ int mode = LM_UNKNOWN; char *what = NULL; char *main_class = NULL; int ret;
InvocationFunctions ifn;
jlong start = 0, end = 0; char jvmpath[MAXPATHLEN]; char jrepath[MAXPATHLEN]; char jvmcfg[MAXPATHLEN];
InitLauncher(javaw);
DumpState(); if (JLI_IsTraceLauncher()) { int i;
printf("Java args:\n"); for (i = 0; i < jargc ; i++) {
printf("jargv[%d] = %s\n", i, jargv[i]);
}
printf("Command line args:\n"); for (i = 0; i < argc ; i++) {
printf("argv[%d] = %s\n", i, argv[i]);
}
AddOption("-Dsun.java.launcher.diag=true", NULL);
}
/* * SelectVersion() has several responsibilities: * * 1) Disallow specification of another JRE. With 1.9, another * version of the JRE cannot be invoked. * 2) Allow for a JRE version to invoke JDK 1.9 or later. Since * all mJRE directives have been stripped from the request but * the pre 1.9 JRE [ 1.6 thru 1.8 ], it is as if 1.9+ has been * invoked from the command line.
*/
SelectVersion(argc, argv, &main_class);
if (JLI_IsTraceLauncher()) {
start = CurrentTimeMicros();
}
if (!LoadJavaVM(jvmpath, &ifn)) { return(6);
}
if (JLI_IsTraceLauncher()) {
end = CurrentTimeMicros();
}
JLI_TraceLauncher("%ld micro seconds to LoadJavaVM\n", (long)(end-start));
++argv;
--argc;
if (IsJavaArgs()) { /* Preprocess wrapper arguments */
TranslateApplicationArgs(jargc, jargv, &argc, &argv); if (!AddApplicationOptions(appclassc, appclassv)) { return(1);
}
} else { /* Set default CLASSPATH */ char* cpath = getenv("CLASSPATH"); if (cpath != NULL) {
SetClassPath(cpath);
}
}
/* Parse command line options; if the return value of * ParseArguments is false, the program should exit.
*/ if (!ParseArguments(&argc, &argv, &mode, &what, &ret, jrepath)) { return(ret);
}
/* Override class path if -jar flag was specified */ if (mode == LM_JAR) {
SetClassPath(what); /* Override class path */
}
/* set the -Dsun.java.command pseudo property */
SetJavaCommandLineProp(what, argc, argv);
/* Set the -Dsun.java.launcher pseudo property */
SetJavaLauncherProp();
return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret);
} /* * Always detach the main thread so that it appears to have ended when * the application's main method exits. This will invoke the * uncaught exception handler machinery if main threw an * exception. An uncaught exception handler cannot change the * launcher's return code except by calling System.exit. * * Wait for all non-daemon threads to end, then destroy the VM. * This will actually create a trivial new Java waiter thread * named "DestroyJavaVM", but this will be seen as a different * thread from the one that executed main, even though they are * the same C thread. This allows mainThread.join() and * mainThread.isAlive() to work as expected.
*/ #define LEAVE() \ do { \ if ((*vm)->DetachCurrentThread(vm) != JNI_OK) { \
JLI_ReportErrorMessage(JVM_ERROR2); \
ret = 1; \
} \ if (JNI_TRUE) { \
(*vm)->DestroyJavaVM(vm); \ return ret; \
} \
} while (JNI_FALSE)
#define CHECK_EXCEPTION_NULL_LEAVE(CENL_exception) \ do { \ if ((*env)->ExceptionOccurred(env)) { \
JLI_ReportExceptionDescription(env); \
LEAVE(); \
} \ if ((CENL_exception) == NULL) { \
JLI_ReportErrorMessage(JNI_ERROR); \
LEAVE(); \
} \
} while (JNI_FALSE)
#define CHECK_EXCEPTION_LEAVE(CEL_return_value) \ do { \ if ((*env)->ExceptionOccurred(env)) { \
JLI_ReportExceptionDescription(env); \
ret = (CEL_return_value); \
LEAVE(); \
} \
} while (JNI_FALSE)
int
JavaMain(void* _args)
{
JavaMainArgs *args = (JavaMainArgs *)_args; int argc = args->argc; char **argv = args->argv; int mode = args->mode; char *what = args->what;
InvocationFunctions ifn = args->ifn;
JavaVM *vm = 0;
JNIEnv *env = 0;
jclass mainClass = NULL;
jclass appClass = NULL; // actual application class being launched
jmethodID mainID;
jobjectArray mainArgs; int ret = 0;
jlong start = 0, end = 0;
RegisterThread();
/* Initialize the virtual machine */
start = CurrentTimeMicros(); if (!InitializeJVM(&vm, &env, &ifn)) {
JLI_ReportErrorMessage(JVM_ERROR1); exit(1);
}
if (showSettings != NULL) {
ShowSettings(env, showSettings);
CHECK_EXCEPTION_LEAVE(1);
}
// show resolved modules and continue if (showResolvedModules) {
ShowResolvedModules(env);
CHECK_EXCEPTION_LEAVE(1);
}
// list observable modules, then exit if (listModules) {
ListModules(env);
CHECK_EXCEPTION_LEAVE(1);
LEAVE();
}
// describe a module, then exit if (describeModule != NULL) {
DescribeModule(env, describeModule);
CHECK_EXCEPTION_LEAVE(1);
LEAVE();
}
if (printVersion || showVersion) {
PrintJavaVersion(env);
CHECK_EXCEPTION_LEAVE(0); if (printVersion) {
LEAVE();
}
}
// modules have been validated at startup so exit if (validateModules) {
LEAVE();
}
/* If the user specified neither a class name nor a JAR file */ if (printXUsage || printUsage || what == 0 || mode == LM_UNKNOWN) {
PrintUsage(env, printXUsage);
CHECK_EXCEPTION_LEAVE(1);
LEAVE();
}
FreeKnownVMs(); /* after last possible PrintUsage */
if (JLI_IsTraceLauncher()) {
end = CurrentTimeMicros();
JLI_TraceLauncher("%ld micro seconds to InitializeJVM\n", (long)(end-start));
}
/* At this stage, argc/argv have the application's arguments */ if (JLI_IsTraceLauncher()){ int i;
printf("%s is '%s'\n", launchModeNames[mode], what);
printf("App's argc is %d\n", argc); for (i=0; i < argc; i++) {
printf(" argv[%2d] = '%s'\n", i, argv[i]);
}
}
ret = 1;
/* * Get the application's main class. It also checks if the main * method exists. * * See bugid 5030265. The Main-Class name has already been parsed * from the manifest, but not parsed properly for UTF-8 support. * Hence the code here ignores the value previously extracted and * uses the pre-existing code to reextract the value. This is * possibly an end of release cycle expedient. However, it has * also been discovered that passing some character sets through * the environment has "strange" behavior on some variants of * Windows. Hence, maybe the manifest parsing code local to the * launcher should never be enhanced. * * Hence, future work should either: * 1) Correct the local parsing code and verify that the * Main-Class attribute gets properly passed through * all environments, * 2) Remove the vestages of maintaining main_class through * the environment (and remove these comments). * * This method also correctly handles launching existing JavaFX * applications that may or may not have a Main-Class manifest entry.
*/
mainClass = LoadMainClass(env, mode, what);
CHECK_EXCEPTION_NULL_LEAVE(mainClass); /* * In some cases when launching an application that needs a helper, e.g., a * JavaFX application with no main method, the mainClass will not be the * applications own main class but rather a helper class. To keep things * consistent in the UI we need to track and report the application main class.
*/
appClass = GetApplicationClass(env);
NULL_CHECK_RETURN_VALUE(appClass, -1);
/* * PostJVMInit uses the class name as the application name for GUI purposes, * for example, on OSX this sets the application name in the menu bar for * both SWT and JavaFX. So we'll pass the actual application class here * instead of mainClass as that may be a launcher or helper class instead * of the application class.
*/
PostJVMInit(env, appClass, vm);
CHECK_EXCEPTION_LEAVE(1);
/* * The LoadMainClass not only loads the main class, it will also ensure * that the main method's signature is correct, therefore further checking * is not required. The main method is invoked here so that extraneous java * stacks are not in the application stack trace.
*/
mainID = (*env)->GetStaticMethodID(env, mainClass, "main", "([Ljava/lang/String;)V");
CHECK_EXCEPTION_NULL_LEAVE(mainID);
/* Invoke main method. */
(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
/* * The launcher's exit code (in the absence of calls to * System.exit) will be non-zero if main threw an exception.
*/
ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1;
LEAVE();
}
/* * Test if the given name is one of the class path options.
*/ static jboolean
IsClassPathOption(constchar* name) { return JLI_StrCmp(name, "-classpath") == 0 ||
JLI_StrCmp(name, "-cp") == 0 ||
JLI_StrCmp(name, "--class-path") == 0;
}
/* * Test if the given name is a launcher option taking the main entry point.
*/ static jboolean
IsLauncherMainOption(constchar* name) { return JLI_StrCmp(name, "--module") == 0 ||
JLI_StrCmp(name, "-m") == 0;
}
/* * Test if the given name is a white-space launcher option.
*/ static jboolean
IsLauncherOption(constchar* name) { return IsClassPathOption(name) ||
IsLauncherMainOption(name) ||
JLI_StrCmp(name, "--describe-module") == 0 ||
JLI_StrCmp(name, "-d") == 0 ||
JLI_StrCmp(name, "--source") == 0;
}
/* * Test if the given name is a module-system white-space option that * will be passed to the VM with its corresponding long-form option * name and "=" delimiter.
*/ static jboolean
IsModuleOption(constchar* name) { return JLI_StrCmp(name, "--module-path") == 0 ||
JLI_StrCmp(name, "-p") == 0 ||
JLI_StrCmp(name, "--upgrade-module-path") == 0 ||
JLI_StrCmp(name, "--add-modules") == 0 ||
JLI_StrCmp(name, "--enable-native-access") == 0 ||
JLI_StrCmp(name, "--limit-modules") == 0 ||
JLI_StrCmp(name, "--add-exports") == 0 ||
JLI_StrCmp(name, "--add-opens") == 0 ||
JLI_StrCmp(name, "--add-reads") == 0 ||
JLI_StrCmp(name, "--patch-module") == 0;
}
/* * Test if the given name has a white space option.
*/
jboolean
IsWhiteSpaceOption(constchar* name) { return IsModuleOption(name) ||
IsLauncherOption(name);
}
/* * Check if it is OK to set the mode. * If the mode was previously set, and should not be changed, * a fatal error is reported.
*/ staticint
checkMode(int mode, int newMode, constchar *arg) { if (mode == LM_SOURCE) {
JLI_ReportErrorMessage(ARG_ERROR14, arg); exit(1);
} return newMode;
}
/* * Test if an arg identifies a source file.
*/ static jboolean IsSourceFile(constchar *arg) { struct stat st; return (JLI_HasSuffix(arg, ".java") && stat(arg, &st) == 0);
}
/* * Checks the command line options to find which JVM type was * specified. If no command line option was given for the JVM type, * the default type is used. The environment variable * JDK_ALTERNATE_VM and the command line option -XXaltjvm= are also * checked as ways of specifying which JVM type to invoke.
*/ char *
CheckJvmType(int *pargc, char ***argv, jboolean speculative) { int i, argi; int argc; char **newArgv; int newArgvIdx = 0; int isVMType; int jvmidx = -1; char *jvmtype = getenv("JDK_ALTERNATE_VM");
argc = *pargc;
/* To make things simpler we always copy the argv array */
newArgv = JLI_MemAlloc((argc + 1) * sizeof(char *));
/* The program name is always present */
newArgv[newArgvIdx++] = (*argv)[0];
for (argi = 1; argi < argc; argi++) { char *arg = (*argv)[argi];
isVMType = 0;
if (IsJavaArgs()) { if (arg[0] != '-') {
newArgv[newArgvIdx++] = arg; continue;
}
} else { if (IsWhiteSpaceOption(arg)) {
newArgv[newArgvIdx++] = arg;
argi++; if (argi < argc) {
newArgv[newArgvIdx++] = (*argv)[argi];
} continue;
} if (arg[0] != '-') break;
}
/* Did the user pass an explicit VM type? */
i = KnownVMIndex(arg); if (i >= 0) {
jvmtype = knownVMs[jvmidx = i].name + 1; /* skip the - */
isVMType = 1;
*pargc = *pargc - 1;
}
/* Did the user specify an "alternate" VM? */ elseif (JLI_StrCCmp(arg, "-XXaltjvm=") == 0 || JLI_StrCCmp(arg, "-J-XXaltjvm=") == 0) {
isVMType = 1;
jvmtype = arg+((arg[1]=='X')? 10 : 12);
jvmidx = -1;
}
if (!isVMType) {
newArgv[newArgvIdx++] = arg;
}
}
/* * Finish copying the arguments if we aborted the above loop. * NOTE that if we aborted via "break" then we did NOT copy the * last argument above, and in addition argi will be less than * argc.
*/ while (argi < argc) {
newArgv[newArgvIdx++] = (*argv)[argi];
argi++;
}
/* argv is null-terminated */
newArgv[newArgvIdx] = 0;
/* use the default VM type if not specified (no alias processing) */ if (jvmtype == NULL) { char* result = knownVMs[0].name+1;
JLI_TraceLauncher("Default VM: %s\n", result); return result;
}
/* if using an alternate VM, no alias processing */ if (jvmidx < 0) return jvmtype;
/* Resolve aliases first */
{ int loopCount = 0; while (knownVMs[jvmidx].flag == VM_ALIASED_TO) { int nextIdx = KnownVMIndex(knownVMs[jvmidx].alias);
if (loopCount > knownVMsCount) { if (!speculative) {
JLI_ReportErrorMessage(CFG_ERROR1); exit(1);
} else { return"ERROR"; /* break; */
}
}
switch (knownVMs[jvmidx].flag) { case VM_WARN: if (!speculative) {
JLI_ReportErrorMessage(CFG_WARN1, jvmtype, knownVMs[0].name + 1);
} /* fall through */ case VM_IGNORE:
jvmtype = knownVMs[jvmidx=0].name + 1; /* fall through */ case VM_KNOWN: break; case VM_ERROR: if (!speculative) {
JLI_ReportErrorMessage(CFG_ERROR3, jvmtype); exit(1);
} else { return"ERROR";
}
}
return jvmtype;
}
/* copied from HotSpot function "atomll()" */ staticint
parse_size(constchar *s, jlong *result) {
jlong n = 0; int args_read = sscanf(s, JLONG_FORMAT_SPECIFIER, &n); if (args_read != 1) { return 0;
} while (*s != '\0' && *s >= '0' && *s <= '9') {
s++;
} // 4705540: illegal if more characters are found after the first non-digit if (JLI_StrLen(s) > 1) { return 0;
} switch (*s) { case'T': case't':
*result = n * GB * KB; return 1; case'G': case'g':
*result = n * GB; return 1; case'M': case'm':
*result = n * MB; return 1; case'K': case'k':
*result = n * KB; return 1; case'\0':
*result = n; return 1; default: /* Create JVM with default stack and let VM handle malformed -Xss string*/ return 0;
}
}
/* * Adds a new VM option with the given name and value.
*/ void
AddOption(char *str, void *info)
{ /* * Expand options array if needed to accommodate at least one more * VM option.
*/ if (numOptions >= maxOptions) { if (options == 0) {
maxOptions = 4;
options = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption));
} else {
JavaVMOption *tmp;
maxOptions *= 2;
tmp = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption));
memcpy(tmp, options, numOptions * sizeof(JavaVMOption));
JLI_MemFree(options);
options = tmp;
}
}
options[numOptions].optionString = str;
options[numOptions++].extraInfo = info;
/* * -Xss is used both by the JVM and here to establish the stack size of the thread * created to launch the JVM. In the latter case we need to ensure we don't go * below the minimum stack size allowed. If -Xss is zero that tells the JVM to use * 'default' sizes (either from JVM or system configuration, e.g. 'ulimit -s' on linux), * and is not itself a small stack size that will be rejected. So we ignore -Xss0 here.
*/ if (JLI_StrCCmp(str, "-Xss") == 0) {
jlong tmp; if (parse_size(str + 4, &tmp)) {
threadStackSize = tmp; if (threadStackSize > 0 && threadStackSize < (jlong)STACK_SIZE_MINIMUM) {
threadStackSize = STACK_SIZE_MINIMUM;
}
}
}
if (JLI_StrCCmp(str, "-Xmx") == 0) {
jlong tmp; if (parse_size(str + 4, &tmp)) {
maxHeapSize = tmp;
}
}
if (JLI_StrCCmp(str, "-Xms") == 0) {
jlong tmp; if (parse_size(str + 4, &tmp)) {
initialHeapSize = tmp;
}
}
}
staticvoid
SetClassPath(constchar *s)
{ char *def; constchar *orig = s; staticconstchar format[] = "-Djava.class.path=%s"; /* * usually we should not get a null pointer, but there are cases where * we might just get one, in which case we simply ignore it, and let the * caller deal with it
*/ if (s == NULL) return;
s = JLI_WildcardExpandClasspath(s); if (sizeof(format) - 2 + JLI_StrLen(s) < JLI_StrLen(s)) // s is became corrupted after expanding wildcards return;
def = JLI_MemAlloc(sizeof(format)
- 2 /* strlen("%s") */
+ JLI_StrLen(s));
sprintf(def, format, s);
AddOption(def, NULL); if (s != orig)
JLI_MemFree((char *) s);
_have_classpath = JNI_TRUE;
}
/* value may be <module> or <module>/<mainclass> */ if (slash == NULL) {
s_len = JLI_StrLen(s);
} else {
s_len = (size_t) (slash - s);
}
def_len = sizeof(format)
- 2 /* strlen("%s") */
+ s_len;
def = JLI_MemAlloc(def_len);
JLI_Snprintf(def, def_len, format, s);
AddOption(def, NULL);
}
/* * The SelectVersion() routine ensures that an appropriate version of * the JRE is running. The specification for the appropriate version * is obtained from either the manifest of a jar file (preferred) or * from command line options. * The routine also parses splash screen command line options and * passes on their values in private environment variables.
*/ staticvoid
SelectVersion(int argc, char **argv, char **main_class)
{ char *arg; char *operand; int jarflag = 0; int headlessflag = 0;
manifest_info info; char *splash_file_name = NULL; char *splash_jar_name = NULL; char *env_in; int res;
jboolean has_arg;
/* * If the version has already been selected, set *main_class * with the value passed through the environment (if any) and * simply return.
*/
/* * This environmental variable can be set by mJRE capable JREs * [ 1.5 thru 1.8 ]. All other aspects of mJRE processing have been * stripped by those JREs. This environmental variable allows 1.9+ * JREs to be started by these mJRE capable JREs. * Note that mJRE directives in the jar manifest file would have been * ignored for a JRE started by another JRE... * .. skipped for JRE 1.5 and beyond. * .. not even checked for pre 1.5.
*/ if ((env_in = getenv(ENV_ENTRY)) != NULL) { if (*env_in != '\0')
*main_class = JLI_StringDup(env_in); return;
}
/* * Scan through the arguments for options relevant to multiple JRE * support. Multiple JRE support existed in JRE versions 1.5 thru 1.8. * * This capability is no longer available with JRE versions 1.9 and later. * These command line options are reported as errors.
*/
/* * Checking for headless toolkit option in the some way as AWT does: * "true" means true and any other value means false
*/ if (JLI_StrCmp(arg, "-Djava.awt.headless=true") == 0) {
headlessflag = 1;
} elseif (JLI_StrCCmp(arg, "-Djava.awt.headless=") == 0) {
headlessflag = 0;
} elseif (JLI_StrCCmp(arg, "-splash:") == 0) {
splash_file_name = arg+8;
}
}
argc--;
argv++;
} if (argc <= 0) { /* No operand? Possibly legit with -[full]version */
operand = NULL;
} else {
argc--;
operand = *argv++;
}
/* * If there is a jar file, read the manifest. If the jarfile can't be * read, the manifest can't be read from the jar file, or the manifest * is corrupt, issue the appropriate error messages and exit. * * Even if there isn't a jar file, construct a manifest_info structure * containing the command line information. It's a convenient way to carry * this data around.
*/ if (jarflag && operand) { if ((res = JLI_ParseManifest(operand, &info)) != 0) { if (res == -1)
JLI_ReportErrorMessage(JAR_ERROR2, operand); else
JLI_ReportErrorMessage(JAR_ERROR3, operand); exit(1);
}
/* * Command line splash screen option should have precedence * over the manifest, so the manifest data is used only if * splash_file_name has not been initialized above during command * line parsing
*/ if (!headlessflag && !splash_file_name && info.splashscreen_image_file_name) {
splash_file_name = info.splashscreen_image_file_name;
splash_jar_name = operand;
}
} else {
info.manifest_version = NULL;
info.main_class = NULL;
info.jre_version = NULL;
info.jre_restrict_search = 0;
}
/* * Passing on splash screen info in environment variables
*/ if (splash_file_name && !headlessflag) {
splash_file_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_FILE_ENV_ENTRY "=")+JLI_StrLen(splash_file_name)+1);
JLI_StrCpy(splash_file_entry, SPLASH_FILE_ENV_ENTRY "=");
JLI_StrCat(splash_file_entry, splash_file_name);
putenv(splash_file_entry);
} if (splash_jar_name && !headlessflag) {
splash_jar_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_JAR_ENV_ENTRY "=")+JLI_StrLen(splash_jar_name)+1);
JLI_StrCpy(splash_jar_entry, SPLASH_JAR_ENV_ENTRY "=");
JLI_StrCat(splash_jar_entry, splash_jar_name);
putenv(splash_jar_entry);
}
/* * "Valid" returns (other than unrecoverable errors) follow. Set * main_class as a side-effect of this routine.
*/ if (info.main_class != NULL)
*main_class = JLI_StringDup(info.main_class);
if (info.jre_version == NULL) {
JLI_FreeManifest(); return;
}
}
/* * Test if the current argv is an option, i.e. with a leading `-` * and followed with an argument without a leading `-`.
*/ static jboolean
IsOptionWithArgument(int argc, char** argv) { char* option; char* arg;
/* * Gets the option, and its argument if the option has an argument. * It will update *pargc, **pargv to the next option.
*/ staticint
GetOpt(int *pargc, char ***pargv, char **poption, char **pvalue) { int argc = *pargc; char** argv = *pargv; char* arg = *argv;
char* option = arg; char* value = NULL; char* equals = NULL; int kind = LAUNCHER_OPTION;
jboolean has_arg = JNI_FALSE;
// check if this option may be a white-space option with an argument
has_arg = IsOptionWithArgument(argc, argv);
argv++; --argc; if (IsLauncherOption(arg)) { if (has_arg) {
value = *argv;
argv++; --argc;
}
kind = IsLauncherMainOption(arg) ? LAUNCHER_MAIN_OPTION
: LAUNCHER_OPTION_WITH_ARGUMENT;
} elseif (IsModuleOption(arg)) {
kind = VM_LONG_OPTION_WITH_ARGUMENT; if (has_arg) {
value = *argv;
argv++; --argc;
}
/* * Support short form alias
*/ if (JLI_StrCmp(arg, "-p") == 0) {
option = "--module-path";
}
/* * Parses command line arguments. Returns JNI_FALSE if launcher * should exit without starting vm, returns JNI_TRUE if vm needs * to be started to process given options. *pret (the launcher * process return value) is set to 0 for a normal exit.
*/ static jboolean
ParseArguments(int *pargc, char ***pargv, int *pmode, char **pwhat, int *pret, constchar *jrepath)
{ int argc = *pargc; char **argv = *pargv; int mode = LM_UNKNOWN; char *arg;
if (*pwhat == NULL) { /* LM_UNKNOWN okay for options that exit */ if (!listModules && !describeModule && !validateModules) {
*pret = 1;
}
} elseif (mode == LM_UNKNOWN) { /* default to LM_CLASS if -m, -jar and -cp options are
* not specified */ if (!_have_classpath) {
SetClassPath(".");
}
mode = IsSourceFile(arg) ? LM_SOURCE : LM_CLASS;
} elseif (mode == LM_CLASS && IsSourceFile(arg)) { /* override LM_CLASS mode if given a source file */
mode = LM_SOURCE;
}
if (mode == LM_SOURCE) {
AddOption("--add-modules=ALL-DEFAULT", NULL);
*pwhat = SOURCE_LAUNCHER_MAIN_ENTRY; // adjust (argc, argv) so that the name of the source file // is included in the args passed to the source launcher // main entry class
*pargc = argc + 1;
*pargv = argv - 1;
} else { if (argc >= 0) {
*pargc = argc;
*pargv = argv;
}
}
*pmode = mode;
return JNI_TRUE;
}
/* * Initializes the Java Virtual Machine. Also frees options array when * finished.
*/ static jboolean
InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn)
{
JavaVMInitArgs args;
jint r;
if (JLI_IsTraceLauncher()) { int i = 0;
printf("JavaVM args:\n ");
printf("version 0x%08lx, ", (long)args.version);
printf("ignoreUnrecognized is %s, ",
args.ignoreUnrecognized ? "JNI_TRUE" : "JNI_FALSE");
printf("nOptions is %ld\n", (long)args.nOptions); for (i = 0; i < numOptions; i++)
printf(" option[%2d] = '%s'\n",
i, args.options[i].optionString);
}
r = ifn->CreateJavaVM(pvm, (void **)penv, &args);
JLI_MemFree(options); return r == JNI_OK;
}
/* * Returns a new array of Java string objects for the specified * array of platform strings.
*/
jobjectArray
NewPlatformStringArray(JNIEnv *env, char **strv, int strc)
{
jarray cls;
jarray ary; int i;
NULL_CHECK0(cls = FindBootStrapClass(env, "java/lang/String"));
NULL_CHECK0(ary = (*env)->NewObjectArray(env, strc, cls, 0));
CHECK_EXCEPTION_RETURN_VALUE(0); for (i = 0; i < strc; i++) {
jstring str = NewPlatformString(env, *strv++);
NULL_CHECK0(str);
(*env)->SetObjectArrayElement(env, ary, i, str);
(*env)->DeleteLocalRef(env, str);
} return ary;
}
/* * Loads a class and verifies that the main class is present and it is ok to * call it for more details refer to the java implementation.
*/ static jclass
LoadMainClass(JNIEnv *env, int mode, char *name)
{
jmethodID mid;
jstring str;
jobject result;
jlong start = 0, end = 0;
jclass cls = GetLauncherHelperClass(env);
NULL_CHECK0(cls); if (JLI_IsTraceLauncher()) {
start = CurrentTimeMicros();
}
NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls, "checkAndLoadMain", "(ZILjava/lang/String;)Ljava/lang/Class;"));
if (JLI_IsTraceLauncher()) {
end = CurrentTimeMicros();
printf("%ld micro seconds to load main class\n", (long)(end-start));
printf("----%s----\n", JLDEBUG_ENV_ENTRY);
}
/* * For tools, convert command line args thus: * javac -cp foo:foo/"*" -J-ms32m ... * java -ms32m -cp JLI_WildcardExpandClasspath(foo:foo/"*") ... * * Takes 4 parameters, and returns the populated arguments
*/ staticvoid
TranslateApplicationArgs(int jargc, constchar **jargv, int *pargc, char ***pargv)
{ int argc = *pargc; char **argv = *pargv; int nargc = argc + jargc; char **nargv = JLI_MemAlloc((nargc + 1) * sizeof(char *)); int i;
*pargc = nargc;
*pargv = nargv;
/* Copy the VM arguments (i.e. prefixed with -J) */ for (i = 0; i < jargc; i++) { constchar *arg = jargv[i]; if (arg[0] == '-' && arg[1] == 'J') {
assert(arg[2] != '\0' && "Invalid JAVA_ARGS or EXTRA_JAVA_ARGS defined by build");
*nargv++ = JLI_StringDup(arg + 2);
}
}
for (i = 0; i < argc; i++) { char *arg = argv[i]; if (arg[0] == '-' && arg[1] == 'J') { if (arg[2] == '\0') {
JLI_ReportErrorMessage(ARG_ERROR3); exit(1);
}
*nargv++ = arg + 2;
}
}
/* Copy the rest of the arguments */ for (i = 0; i < jargc ; i++) { constchar *arg = jargv[i]; if (arg[0] != '-' || arg[1] != 'J') {
*nargv++ = (arg == NULL) ? NULL : JLI_StringDup(arg);
}
} for (i = 0; i < argc; i++) { char *arg = argv[i]; if (arg[0] == '-') { if (arg[1] == 'J') continue; if (IsWildCardEnabled()) { if (IsClassPathOption(arg) && i < argc - 1) {
*nargv++ = arg;
*nargv++ = (char *) JLI_WildcardExpandClasspath(argv[i+1]);
i++; continue;
} if (JLI_StrCCmp(arg, "--class-path=") == 0) {
*nargv++ = expandWildcardOnLongOpt(arg); continue;
}
}
}
*nargv++ = arg;
}
*nargv = 0;
}
/* * For our tools, we try to add 3 VM options: * -Denv.class.path=<envcp> * -Dapplication.home=<apphome> * -Djava.class.path=<appcp> * <envcp> is the user's setting of CLASSPATH -- for instance the user * tells javac where to find binary classes through this environment * variable. Notice that users will be able to compile against our * tools classes (sun.tools.javac.Main) only if they explicitly add * tools.jar to CLASSPATH. * <apphome> is the directory where the application is installed. * <appcp> is the classpath to where our apps' classfiles are.
*/ static jboolean
AddApplicationOptions(int cpathc, constchar **cpathv)
{ char *envcp, *appcp, *apphome; char home[MAXPATHLEN]; /* application home */ char separator[] = { PATH_SEPARATOR, '\0' }; int size, i;
{ constchar *s = getenv("CLASSPATH"); if (s) {
s = (char *) JLI_WildcardExpandClasspath(s); /* 40 for -Denv.class.path= */ if (JLI_StrLen(s) + 40 > JLI_StrLen(s)) { // Safeguard from overflow
envcp = (char *)JLI_MemAlloc(JLI_StrLen(s) + 40);
sprintf(envcp, "-Denv.class.path=%s", s);
AddOption(envcp, NULL);
}
}
}
if (!GetApplicationHome(home, sizeof(home))) {
JLI_ReportErrorMessage(CFG_ERROR5); return JNI_FALSE;
}
/* How big is the application's classpath? */ if (cpathc > 0) {
size = 40; /* 40: "-Djava.class.path=" */ for (i = 0; i < cpathc; i++) {
size += (int)JLI_StrLen(home) + (int)JLI_StrLen(cpathv[i]) + 1; /* 1: separator */
}
appcp = (char *)JLI_MemAlloc(size + 1);
JLI_StrCpy(appcp, "-Djava.class.path="); for (i = 0; i < cpathc; i++) {
JLI_StrCat(appcp, home); /* c:\program files\myapp */
JLI_StrCat(appcp, cpathv[i]); /* \lib\myapp.jar */
JLI_StrCat(appcp, separator); /* ; */
}
appcp[JLI_StrLen(appcp)-1] = '\0'; /* remove trailing path separator */
AddOption(appcp, NULL);
} return JNI_TRUE;
}
/* * inject the -Dsun.java.command pseudo property into the args structure * this pseudo property is used in the HotSpot VM to expose the * Java class name and arguments to the main method to the VM. The * HotSpot VM uses this pseudo property to store the Java class name * (or jar file name) and the arguments to the class's main method * to the instrumentation memory region. The sun.java.command pseudo * property is not exported by HotSpot to the Java layer.
*/ void
SetJavaCommandLineProp(char *what, int argc, char **argv)
{
int i = 0;
size_t len = 0; char* javaCommand = NULL; char* dashDstr = "-Dsun.java.command=";
if (what == NULL) { /* unexpected, one of these should be set. just return without * setting the property
*/ return;
}
/* determine the amount of memory to allocate assuming * the individual components will be space separated
*/
len = JLI_StrLen(what); for (i = 0; i < argc; i++) {
len += JLI_StrLen(argv[i]) + 1;
}
for (i = 0; i < argc; i++) { /* the components of the string are space separated. In * the case of embedded white space, the relationship of * the white space separated components to their true * positional arguments will be ambiguous. This issue may * be addressed in a future release.
*/
JLI_StrCat(javaCommand, " ");
JLI_StrCat(javaCommand, argv[i]);
}
AddOption(javaCommand, NULL);
}
/* * JVM would like to know if it's created by a standard Sun launcher, or by * user native application, the following property indicates the former.
*/ staticvoid SetJavaLauncherProp() {
AddOption("-Dsun.java.launcher=SUN_STANDARD", NULL);
}
/* * Prints the version information from the java.version and other properties.
*/ staticvoid
PrintJavaVersion(JNIEnv *env)
{
jclass ver;
jmethodID print;
/* Initialize the usage message with the usual preamble */
(*env)->CallStaticVoidMethod(env, cls, initHelp, jprogname);
CHECK_EXCEPTION_RETURN();
/* Assemble the other variant part of the usage */ for (i=1; i<knownVMsCount; i++) { if (knownVMs[i].flag == VM_KNOWN) {
NULL_CHECK(vm1 = (*env)->NewStringUTF(env, knownVMs[i].name));
NULL_CHECK(vm2 = (*env)->NewStringUTF(env, knownVMs[i].name+1));
(*env)->CallStaticVoidMethod(env, cls, vmSelect, vm1, vm2);
CHECK_EXCEPTION_RETURN();
}
} for (i=1; i<knownVMsCount; i++) { if (knownVMs[i].flag == VM_ALIASED_TO) {
NULL_CHECK(vm1 = (*env)->NewStringUTF(env, knownVMs[i].name));
NULL_CHECK(vm2 = (*env)->NewStringUTF(env, knownVMs[i].alias+1));
(*env)->CallStaticVoidMethod(env, cls, vmSynonym, vm1, vm2);
CHECK_EXCEPTION_RETURN();
}
}
/* Complete the usage message and print to stderr*/
(*env)->CallStaticVoidMethod(env, cls, printHelp, printTo);
} return;
}
/* * Read the jvm.cfg file and fill the knownJVMs[] array. * * The functionality of the jvm.cfg file is subject to change without * notice and the mechanism will be removed in the future. * * The lexical structure of the jvm.cfg file is as follows: * * jvmcfg := { vmLine } * vmLine := knownLine * | aliasLine * | warnLine * | ignoreLine * | errorLine * | predicateLine * | commentLine * knownLine := flag "KNOWN" EOL * warnLine := flag "WARN" EOL * ignoreLine := flag "IGNORE" EOL * errorLine := flag "ERROR" EOL * aliasLine := flag "ALIASED_TO" flag EOL * predicateLine := flag "IF_SERVER_CLASS" flag EOL * commentLine := "#" text EOL * flag := "-" identifier * * The semantics are that when someone specifies a flag on the command line: * - if the flag appears on a knownLine, then the identifier is used as * the name of the directory holding the JVM library (the name of the JVM). * - if the flag appears as the first flag on an aliasLine, the identifier * of the second flag is used as the name of the JVM. * - if the flag appears on a warnLine, the identifier is used as the * name of the JVM, but a warning is generated. * - if the flag appears on an ignoreLine, the identifier is recognized as the * name of a JVM, but the identifier is ignored and the default vm used * - if the flag appears on an errorLine, an error is generated. * - if the flag appears as the first flag on a predicateLine, and * the machine on which you are running passes the predicate indicated,
--> --------------------
--> maximum size reached
--> --------------------
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.41Angebot
Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.