1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/tools/launcher/java.c Thu Dec 02 05:45:54 2010 -0800 1.3 @@ -0,0 +1,2078 @@ 1.4 +/* 1.5 + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +/* 1.29 + * Gamma (Hotspot internal engineering test) launcher based on 6.0u22 JDK, 1.30 + * search "GAMMA" for gamma specific changes. 1.31 + * 1.32 + * GAMMA: gamma launcher is much simpler than regular java launcher in that 1.33 + * JVM is either statically linked in or it is installed in the 1.34 + * same directory where the launcher exists, so we don't have to 1.35 + * worry about choosing the right JVM based on command line flag, jar 1.36 + * file and/or ergonomics. Intead of removing unused logic from source 1.37 + * they are commented out with #ifndef GAMMA, hopefully it'll be easier 1.38 + * to maintain this file in sync with regular JDK launcher. 1.39 + */ 1.40 + 1.41 +/* 1.42 + * Shared source for 'java' command line tool. 1.43 + * 1.44 + * If JAVA_ARGS is defined, then acts as a launcher for applications. For 1.45 + * instance, the JDK command line tools such as javac and javadoc (see 1.46 + * makefiles for more details) are built with this program. Any arguments 1.47 + * prefixed with '-J' will be passed directly to the 'java' command. 1.48 + */ 1.49 + 1.50 +#ifdef GAMMA 1.51 +# ifdef JAVA_ARGS 1.52 +# error Do NOT define JAVA_ARGS when building gamma launcher 1.53 +# endif 1.54 +# if !defined(LINK_INTO_AOUT) && !defined(LINK_INTO_LIBJVM) 1.55 +# error Either LINK_INTO_AOUT or LINK_INTO_LIBJVM must be defined 1.56 +# endif 1.57 +#endif 1.58 + 1.59 +/* 1.60 + * One job of the launcher is to remove command line options which the 1.61 + * vm does not understand and will not process. These options include 1.62 + * options which select which style of vm is run (e.g. -client and 1.63 + * -server) as well as options which select the data model to use. 1.64 + * Additionally, for tools which invoke an underlying vm "-J-foo" 1.65 + * options are turned into "-foo" options to the vm. This option 1.66 + * filtering is handled in a number of places in the launcher, some of 1.67 + * it in machine-dependent code. In this file, the function 1.68 + * CheckJVMType removes vm style options and TranslateApplicationArgs 1.69 + * removes "-J" prefixes. On unix platforms, the 1.70 + * CreateExecutionEnvironment function from the unix java_md.c file 1.71 + * processes and removes -d<n> options. However, in case 1.72 + * CreateExecutionEnvironment does not need to exec because 1.73 + * LD_LIBRARY_PATH is set acceptably and the data model does not need 1.74 + * to be changed, ParseArguments will screen out the redundant -d<n> 1.75 + * options and prevent them from being passed to the vm; this is done 1.76 + * by using the machine-dependent call 1.77 + * RemovableMachineDependentOption. 1.78 + */ 1.79 + 1.80 +#include <stdio.h> 1.81 +#include <stdlib.h> 1.82 +#include <string.h> 1.83 + 1.84 +#include <jni.h> 1.85 +#include <jvm.h> 1.86 +#include "java.h" 1.87 +#ifndef GAMMA 1.88 +#include "manifest_info.h" 1.89 +#include "version_comp.h" 1.90 +#include "splashscreen.h" 1.91 +#endif 1.92 +#include "wildcard.h" 1.93 + 1.94 +#ifndef FULL_VERSION 1.95 +#define FULL_VERSION JDK_MAJOR_VERSION "." JDK_MINOR_VERSION 1.96 +#endif 1.97 + 1.98 +/* 1.99 + * The following environment variable is used to influence the behavior 1.100 + * of the jre exec'd through the SelectVersion routine. The command line 1.101 + * options which specify the version are not passed to the exec'd version, 1.102 + * because that jre may be an older version which wouldn't recognize them. 1.103 + * This environment variable is known to this (and later) version and serves 1.104 + * to suppress the version selection code. This is not only for efficiency, 1.105 + * but also for correctness, since any command line options have been 1.106 + * removed which would cause any value found in the manifest to be used. 1.107 + * This would be incorrect because the command line options are defined 1.108 + * to take precedence. 1.109 + * 1.110 + * The value associated with this environment variable is the MainClass 1.111 + * name from within the executable jar file (if any). This is strictly a 1.112 + * performance enhancement to avoid re-reading the jar file manifest. 1.113 + * 1.114 + * A NOTE TO DEVELOPERS: For performance reasons it is important that 1.115 + * the program image remain relatively small until after SelectVersion 1.116 + * CreateExecutionEnvironment have finished their possibly recursive 1.117 + * processing. Watch everything, but resist all temptations to use Java 1.118 + * interfaces. 1.119 + */ 1.120 +#define ENV_ENTRY "_JAVA_VERSION_SET" 1.121 + 1.122 +#ifndef GAMMA 1.123 +#define SPLASH_FILE_ENV_ENTRY "_JAVA_SPLASH_FILE" 1.124 +#define SPLASH_JAR_ENV_ENTRY "_JAVA_SPLASH_JAR" 1.125 +#endif 1.126 + 1.127 +static jboolean printVersion = JNI_FALSE; /* print and exit */ 1.128 +static jboolean showVersion = JNI_FALSE; /* print but continue */ 1.129 +static char *progname; 1.130 +jboolean _launcher_debug = JNI_FALSE; 1.131 + 1.132 +#ifndef GAMMA 1.133 +/* 1.134 + * Entries for splash screen environment variables. 1.135 + * putenv is performed in SelectVersion. We need 1.136 + * them in memory until UnsetEnv, so they are made static 1.137 + * global instead of auto local. 1.138 + */ 1.139 +static char* splash_file_entry = NULL; 1.140 +static char* splash_jar_entry = NULL; 1.141 +#endif 1.142 + 1.143 +/* 1.144 + * List of VM options to be specified when the VM is created. 1.145 + */ 1.146 +static JavaVMOption *options; 1.147 +static int numOptions, maxOptions; 1.148 + 1.149 +/* 1.150 + * Prototypes for functions internal to launcher. 1.151 + */ 1.152 +static void SetClassPath(const char *s); 1.153 +static void SelectVersion(int argc, char **argv, char **main_class); 1.154 +static jboolean ParseArguments(int *pargc, char ***pargv, char **pjarfile, 1.155 + char **pclassname, int *pret, const char *jvmpath); 1.156 +static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv, 1.157 + InvocationFunctions *ifn); 1.158 +static jstring NewPlatformString(JNIEnv *env, char *s); 1.159 +static jobjectArray NewPlatformStringArray(JNIEnv *env, char **strv, int strc); 1.160 +static jclass LoadClass(JNIEnv *env, char *name); 1.161 +static jstring GetMainClassName(JNIEnv *env, char *jarname); 1.162 +static void SetJavaCommandLineProp(char* classname, char* jarfile, int argc, char** argv); 1.163 +static void SetJavaLauncherProp(void); 1.164 + 1.165 +#ifdef JAVA_ARGS 1.166 +static void TranslateApplicationArgs(int *pargc, char ***pargv); 1.167 +static jboolean AddApplicationOptions(void); 1.168 +#endif 1.169 + 1.170 +static void PrintJavaVersion(JNIEnv *env); 1.171 +static void PrintUsage(void); 1.172 +static jint PrintXUsage(const char *jvmpath); 1.173 + 1.174 +static void SetPaths(int argc, char **argv); 1.175 + 1.176 +#ifndef GAMMA 1.177 + 1.178 +/* Maximum supported entries from jvm.cfg. */ 1.179 +#define INIT_MAX_KNOWN_VMS 10 1.180 +/* Values for vmdesc.flag */ 1.181 +#define VM_UNKNOWN -1 1.182 +#define VM_KNOWN 0 1.183 +#define VM_ALIASED_TO 1 1.184 +#define VM_WARN 2 1.185 +#define VM_ERROR 3 1.186 +#define VM_IF_SERVER_CLASS 4 1.187 +#define VM_IGNORE 5 1.188 +struct vmdesc { 1.189 + char *name; 1.190 + int flag; 1.191 + char *alias; 1.192 + char *server_class; 1.193 +}; 1.194 +static struct vmdesc *knownVMs = NULL; 1.195 +static int knownVMsCount = 0; 1.196 +static int knownVMsLimit = 0; 1.197 + 1.198 +static void GrowKnownVMs(); 1.199 +static int KnownVMIndex(const char* name); 1.200 +static void FreeKnownVMs(); 1.201 +static void ShowSplashScreen(); 1.202 + 1.203 +#endif /* ifndef GAMMA */ 1.204 + 1.205 +jboolean ServerClassMachine(); 1.206 + 1.207 +/* flag which if set suppresses error messages from the launcher */ 1.208 +static int noExitErrorMessage = 0; 1.209 + 1.210 +/* 1.211 + * Running Java code in primordial thread caused many problems. We will 1.212 + * create a new thread to invoke JVM. See 6316197 for more information. 1.213 + */ 1.214 +static jlong threadStackSize = 0; /* stack size of the new thread */ 1.215 + 1.216 +int JNICALL JavaMain(void * args); /* entry point */ 1.217 + 1.218 +struct JavaMainArgs { 1.219 + int argc; 1.220 + char ** argv; 1.221 + char * jarfile; 1.222 + char * classname; 1.223 + InvocationFunctions ifn; 1.224 +}; 1.225 + 1.226 +/* 1.227 + * Entry point. 1.228 + */ 1.229 +int 1.230 +main(int argc, char ** argv) 1.231 +{ 1.232 + char *jarfile = 0; 1.233 + char *classname = 0; 1.234 + char *s = 0; 1.235 + char *main_class = NULL; 1.236 + int ret; 1.237 + InvocationFunctions ifn; 1.238 + jlong start, end; 1.239 + char jrepath[MAXPATHLEN], jvmpath[MAXPATHLEN]; 1.240 + char ** original_argv = argv; 1.241 + 1.242 + if (getenv("_JAVA_LAUNCHER_DEBUG") != 0) { 1.243 + _launcher_debug = JNI_TRUE; 1.244 + printf("----_JAVA_LAUNCHER_DEBUG----\n"); 1.245 + } 1.246 + 1.247 +#ifndef GAMMA 1.248 + /* 1.249 + * Make sure the specified version of the JRE is running. 1.250 + * 1.251 + * There are three things to note about the SelectVersion() routine: 1.252 + * 1) If the version running isn't correct, this routine doesn't 1.253 + * return (either the correct version has been exec'd or an error 1.254 + * was issued). 1.255 + * 2) Argc and Argv in this scope are *not* altered by this routine. 1.256 + * It is the responsibility of subsequent code to ignore the 1.257 + * arguments handled by this routine. 1.258 + * 3) As a side-effect, the variable "main_class" is guaranteed to 1.259 + * be set (if it should ever be set). This isn't exactly the 1.260 + * poster child for structured programming, but it is a small 1.261 + * price to pay for not processing a jar file operand twice. 1.262 + * (Note: This side effect has been disabled. See comment on 1.263 + * bugid 5030265 below.) 1.264 + */ 1.265 + SelectVersion(argc, argv, &main_class); 1.266 +#endif /* ifndef GAMMA */ 1.267 + 1.268 + /* copy original argv */ 1.269 + { 1.270 + int i; 1.271 + original_argv = (char**)JLI_MemAlloc(sizeof(char*)*(argc+1)); 1.272 + for(i = 0; i < argc+1; i++) 1.273 + original_argv[i] = argv[i]; 1.274 + } 1.275 + 1.276 + CreateExecutionEnvironment(&argc, &argv, 1.277 + jrepath, sizeof(jrepath), 1.278 + jvmpath, sizeof(jvmpath), 1.279 + original_argv); 1.280 + 1.281 + ifn.CreateJavaVM = 0; 1.282 + ifn.GetDefaultJavaVMInitArgs = 0; 1.283 + 1.284 + if (_launcher_debug) 1.285 + start = CounterGet(); 1.286 + if (!LoadJavaVM(jvmpath, &ifn)) { 1.287 + exit(6); 1.288 + } 1.289 + if (_launcher_debug) { 1.290 + end = CounterGet(); 1.291 + printf("%ld micro seconds to LoadJavaVM\n", 1.292 + (long)(jint)Counter2Micros(end-start)); 1.293 + } 1.294 + 1.295 +#ifdef JAVA_ARGS /* javac, jar and friends. */ 1.296 + progname = "java"; 1.297 +#else /* java, oldjava, javaw and friends */ 1.298 +#ifdef PROGNAME 1.299 + progname = PROGNAME; 1.300 +#else 1.301 + progname = *argv; 1.302 + if ((s = strrchr(progname, FILE_SEPARATOR)) != 0) { 1.303 + progname = s + 1; 1.304 + } 1.305 +#endif /* PROGNAME */ 1.306 +#endif /* JAVA_ARGS */ 1.307 + ++argv; 1.308 + --argc; 1.309 + 1.310 +#ifdef JAVA_ARGS 1.311 + /* Preprocess wrapper arguments */ 1.312 + TranslateApplicationArgs(&argc, &argv); 1.313 + if (!AddApplicationOptions()) { 1.314 + exit(1); 1.315 + } 1.316 +#endif 1.317 + 1.318 + /* Set default CLASSPATH */ 1.319 + if ((s = getenv("CLASSPATH")) == 0) { 1.320 + s = "."; 1.321 + } 1.322 +#ifndef JAVA_ARGS 1.323 + SetClassPath(s); 1.324 +#endif 1.325 + 1.326 + /* 1.327 + * Parse command line options; if the return value of 1.328 + * ParseArguments is false, the program should exit. 1.329 + */ 1.330 + if (!ParseArguments(&argc, &argv, &jarfile, &classname, &ret, jvmpath)) { 1.331 + exit(ret); 1.332 + } 1.333 + 1.334 + /* Override class path if -jar flag was specified */ 1.335 + if (jarfile != 0) { 1.336 + SetClassPath(jarfile); 1.337 + } 1.338 + 1.339 + /* set the -Dsun.java.command pseudo property */ 1.340 + SetJavaCommandLineProp(classname, jarfile, argc, argv); 1.341 + 1.342 + /* Set the -Dsun.java.launcher pseudo property */ 1.343 + SetJavaLauncherProp(); 1.344 + 1.345 + /* set the -Dsun.java.launcher.* platform properties */ 1.346 + SetJavaLauncherPlatformProps(); 1.347 + 1.348 +#ifndef GAMMA 1.349 + /* Show the splash screen if needed */ 1.350 + ShowSplashScreen(); 1.351 +#endif 1.352 + 1.353 + /* 1.354 + * Done with all command line processing and potential re-execs so 1.355 + * clean up the environment. 1.356 + */ 1.357 + (void)UnsetEnv(ENV_ENTRY); 1.358 +#ifndef GAMMA 1.359 + (void)UnsetEnv(SPLASH_FILE_ENV_ENTRY); 1.360 + (void)UnsetEnv(SPLASH_JAR_ENV_ENTRY); 1.361 + 1.362 + JLI_MemFree(splash_jar_entry); 1.363 + JLI_MemFree(splash_file_entry); 1.364 +#endif 1.365 + 1.366 + /* 1.367 + * If user doesn't specify stack size, check if VM has a preference. 1.368 + * Note that HotSpot no longer supports JNI_VERSION_1_1 but it will 1.369 + * return its default stack size through the init args structure. 1.370 + */ 1.371 + if (threadStackSize == 0) { 1.372 + struct JDK1_1InitArgs args1_1; 1.373 + memset((void*)&args1_1, 0, sizeof(args1_1)); 1.374 + args1_1.version = JNI_VERSION_1_1; 1.375 + ifn.GetDefaultJavaVMInitArgs(&args1_1); /* ignore return value */ 1.376 + if (args1_1.javaStackSize > 0) { 1.377 + threadStackSize = args1_1.javaStackSize; 1.378 + } 1.379 + } 1.380 + 1.381 + { /* Create a new thread to create JVM and invoke main method */ 1.382 + struct JavaMainArgs args; 1.383 + 1.384 + args.argc = argc; 1.385 + args.argv = argv; 1.386 + args.jarfile = jarfile; 1.387 + args.classname = classname; 1.388 + args.ifn = ifn; 1.389 + 1.390 + return ContinueInNewThread(JavaMain, threadStackSize, (void*)&args); 1.391 + } 1.392 +} 1.393 + 1.394 +int JNICALL 1.395 +JavaMain(void * _args) 1.396 +{ 1.397 + struct JavaMainArgs *args = (struct JavaMainArgs *)_args; 1.398 + int argc = args->argc; 1.399 + char **argv = args->argv; 1.400 + char *jarfile = args->jarfile; 1.401 + char *classname = args->classname; 1.402 + InvocationFunctions ifn = args->ifn; 1.403 + 1.404 + JavaVM *vm = 0; 1.405 + JNIEnv *env = 0; 1.406 + jstring mainClassName; 1.407 + jclass mainClass; 1.408 + jmethodID mainID; 1.409 + jobjectArray mainArgs; 1.410 + int ret = 0; 1.411 + jlong start, end; 1.412 + 1.413 + /* 1.414 + * Error message to print or display; by default the message will 1.415 + * only be displayed in a window. 1.416 + */ 1.417 + char * message = "Fatal exception occurred. Program will exit."; 1.418 + jboolean messageDest = JNI_FALSE; 1.419 + 1.420 + /* Initialize the virtual machine */ 1.421 + 1.422 + if (_launcher_debug) 1.423 + start = CounterGet(); 1.424 + if (!InitializeJVM(&vm, &env, &ifn)) { 1.425 + ReportErrorMessage("Could not create the Java virtual machine.", 1.426 + JNI_TRUE); 1.427 + exit(1); 1.428 + } 1.429 + 1.430 + if (printVersion || showVersion) { 1.431 + PrintJavaVersion(env); 1.432 + if ((*env)->ExceptionOccurred(env)) { 1.433 + ReportExceptionDescription(env); 1.434 + goto leave; 1.435 + } 1.436 + if (printVersion) { 1.437 + ret = 0; 1.438 + message = NULL; 1.439 + goto leave; 1.440 + } 1.441 + if (showVersion) { 1.442 + fprintf(stderr, "\n"); 1.443 + } 1.444 + } 1.445 + 1.446 + /* If the user specified neither a class name nor a JAR file */ 1.447 + if (jarfile == 0 && classname == 0) { 1.448 + PrintUsage(); 1.449 + message = NULL; 1.450 + goto leave; 1.451 + } 1.452 + 1.453 +#ifndef GAMMA 1.454 + FreeKnownVMs(); /* after last possible PrintUsage() */ 1.455 +#endif 1.456 + 1.457 + if (_launcher_debug) { 1.458 + end = CounterGet(); 1.459 + printf("%ld micro seconds to InitializeJVM\n", 1.460 + (long)(jint)Counter2Micros(end-start)); 1.461 + } 1.462 + 1.463 + /* At this stage, argc/argv have the applications' arguments */ 1.464 + if (_launcher_debug) { 1.465 + int i = 0; 1.466 + printf("Main-Class is '%s'\n", classname ? classname : ""); 1.467 + printf("Apps' argc is %d\n", argc); 1.468 + for (; i < argc; i++) { 1.469 + printf(" argv[%2d] = '%s'\n", i, argv[i]); 1.470 + } 1.471 + } 1.472 + 1.473 + ret = 1; 1.474 + 1.475 + /* 1.476 + * Get the application's main class. 1.477 + * 1.478 + * See bugid 5030265. The Main-Class name has already been parsed 1.479 + * from the manifest, but not parsed properly for UTF-8 support. 1.480 + * Hence the code here ignores the value previously extracted and 1.481 + * uses the pre-existing code to reextract the value. This is 1.482 + * possibly an end of release cycle expedient. However, it has 1.483 + * also been discovered that passing some character sets through 1.484 + * the environment has "strange" behavior on some variants of 1.485 + * Windows. Hence, maybe the manifest parsing code local to the 1.486 + * launcher should never be enhanced. 1.487 + * 1.488 + * Hence, future work should either: 1.489 + * 1) Correct the local parsing code and verify that the 1.490 + * Main-Class attribute gets properly passed through 1.491 + * all environments, 1.492 + * 2) Remove the vestages of maintaining main_class through 1.493 + * the environment (and remove these comments). 1.494 + */ 1.495 + if (jarfile != 0) { 1.496 + mainClassName = GetMainClassName(env, jarfile); 1.497 + if ((*env)->ExceptionOccurred(env)) { 1.498 + ReportExceptionDescription(env); 1.499 + goto leave; 1.500 + } 1.501 + if (mainClassName == NULL) { 1.502 + const char * format = "Failed to load Main-Class manifest " 1.503 + "attribute from\n%s"; 1.504 + message = (char*)JLI_MemAlloc((strlen(format) + strlen(jarfile)) * 1.505 + sizeof(char)); 1.506 + sprintf(message, format, jarfile); 1.507 + messageDest = JNI_TRUE; 1.508 + goto leave; 1.509 + } 1.510 + classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); 1.511 + if (classname == NULL) { 1.512 + ReportExceptionDescription(env); 1.513 + goto leave; 1.514 + } 1.515 + mainClass = LoadClass(env, classname); 1.516 + if(mainClass == NULL) { /* exception occured */ 1.517 + const char * format = "Could not find the main class: %s. Program will exit."; 1.518 + ReportExceptionDescription(env); 1.519 + message = (char *)JLI_MemAlloc((strlen(format) + 1.520 + strlen(classname)) * sizeof(char) ); 1.521 + messageDest = JNI_TRUE; 1.522 + sprintf(message, format, classname); 1.523 + goto leave; 1.524 + } 1.525 + (*env)->ReleaseStringUTFChars(env, mainClassName, classname); 1.526 + } else { 1.527 + mainClassName = NewPlatformString(env, classname); 1.528 + if (mainClassName == NULL) { 1.529 + const char * format = "Failed to load Main Class: %s"; 1.530 + message = (char *)JLI_MemAlloc((strlen(format) + strlen(classname)) * 1.531 + sizeof(char) ); 1.532 + sprintf(message, format, classname); 1.533 + messageDest = JNI_TRUE; 1.534 + goto leave; 1.535 + } 1.536 + classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); 1.537 + if (classname == NULL) { 1.538 + ReportExceptionDescription(env); 1.539 + goto leave; 1.540 + } 1.541 + mainClass = LoadClass(env, classname); 1.542 + if(mainClass == NULL) { /* exception occured */ 1.543 + const char * format = "Could not find the main class: %s. Program will exit."; 1.544 + ReportExceptionDescription(env); 1.545 + message = (char *)JLI_MemAlloc((strlen(format) + 1.546 + strlen(classname)) * sizeof(char) ); 1.547 + messageDest = JNI_TRUE; 1.548 + sprintf(message, format, classname); 1.549 + goto leave; 1.550 + } 1.551 + (*env)->ReleaseStringUTFChars(env, mainClassName, classname); 1.552 + } 1.553 + 1.554 + /* Get the application's main method */ 1.555 + mainID = (*env)->GetStaticMethodID(env, mainClass, "main", 1.556 + "([Ljava/lang/String;)V"); 1.557 + if (mainID == NULL) { 1.558 + if ((*env)->ExceptionOccurred(env)) { 1.559 + ReportExceptionDescription(env); 1.560 + } else { 1.561 + message = "No main method found in specified class."; 1.562 + messageDest = JNI_TRUE; 1.563 + } 1.564 + goto leave; 1.565 + } 1.566 + 1.567 + { /* Make sure the main method is public */ 1.568 + jint mods; 1.569 + jmethodID mid; 1.570 + jobject obj = (*env)->ToReflectedMethod(env, mainClass, 1.571 + mainID, JNI_TRUE); 1.572 + 1.573 + if( obj == NULL) { /* exception occurred */ 1.574 + ReportExceptionDescription(env); 1.575 + goto leave; 1.576 + } 1.577 + 1.578 + mid = 1.579 + (*env)->GetMethodID(env, 1.580 + (*env)->GetObjectClass(env, obj), 1.581 + "getModifiers", "()I"); 1.582 + if ((*env)->ExceptionOccurred(env)) { 1.583 + ReportExceptionDescription(env); 1.584 + goto leave; 1.585 + } 1.586 + 1.587 + mods = (*env)->CallIntMethod(env, obj, mid); 1.588 + if ((mods & 1) == 0) { /* if (!Modifier.isPublic(mods)) ... */ 1.589 + message = "Main method not public."; 1.590 + messageDest = JNI_TRUE; 1.591 + goto leave; 1.592 + } 1.593 + } 1.594 + 1.595 + /* Build argument array */ 1.596 + mainArgs = NewPlatformStringArray(env, argv, argc); 1.597 + if (mainArgs == NULL) { 1.598 + ReportExceptionDescription(env); 1.599 + goto leave; 1.600 + } 1.601 + 1.602 + /* Invoke main method. */ 1.603 + (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); 1.604 + 1.605 + /* 1.606 + * The launcher's exit code (in the absence of calls to 1.607 + * System.exit) will be non-zero if main threw an exception. 1.608 + */ 1.609 + ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1; 1.610 + 1.611 + /* 1.612 + * Detach the main thread so that it appears to have ended when 1.613 + * the application's main method exits. This will invoke the 1.614 + * uncaught exception handler machinery if main threw an 1.615 + * exception. An uncaught exception handler cannot change the 1.616 + * launcher's return code except by calling System.exit. 1.617 + */ 1.618 + if ((*vm)->DetachCurrentThread(vm) != 0) { 1.619 + message = "Could not detach main thread."; 1.620 + messageDest = JNI_TRUE; 1.621 + ret = 1; 1.622 + goto leave; 1.623 + } 1.624 + 1.625 + message = NULL; 1.626 + 1.627 + leave: 1.628 + /* 1.629 + * Wait for all non-daemon threads to end, then destroy the VM. 1.630 + * This will actually create a trivial new Java waiter thread 1.631 + * named "DestroyJavaVM", but this will be seen as a different 1.632 + * thread from the one that executed main, even though they are 1.633 + * the same C thread. This allows mainThread.join() and 1.634 + * mainThread.isAlive() to work as expected. 1.635 + */ 1.636 + (*vm)->DestroyJavaVM(vm); 1.637 + 1.638 + if(message != NULL && !noExitErrorMessage) 1.639 + ReportErrorMessage(message, messageDest); 1.640 + return ret; 1.641 +} 1.642 + 1.643 +#ifndef GAMMA 1.644 +/* 1.645 + * Checks the command line options to find which JVM type was 1.646 + * specified. If no command line option was given for the JVM type, 1.647 + * the default type is used. The environment variable 1.648 + * JDK_ALTERNATE_VM and the command line option -XXaltjvm= are also 1.649 + * checked as ways of specifying which JVM type to invoke. 1.650 + */ 1.651 +char * 1.652 +CheckJvmType(int *pargc, char ***argv, jboolean speculative) { 1.653 + int i, argi; 1.654 + int argc; 1.655 + char **newArgv; 1.656 + int newArgvIdx = 0; 1.657 + int isVMType; 1.658 + int jvmidx = -1; 1.659 + char *jvmtype = getenv("JDK_ALTERNATE_VM"); 1.660 + 1.661 + argc = *pargc; 1.662 + 1.663 + /* To make things simpler we always copy the argv array */ 1.664 + newArgv = JLI_MemAlloc((argc + 1) * sizeof(char *)); 1.665 + 1.666 + /* The program name is always present */ 1.667 + newArgv[newArgvIdx++] = (*argv)[0]; 1.668 + 1.669 + for (argi = 1; argi < argc; argi++) { 1.670 + char *arg = (*argv)[argi]; 1.671 + isVMType = 0; 1.672 + 1.673 +#ifdef JAVA_ARGS 1.674 + if (arg[0] != '-') { 1.675 + newArgv[newArgvIdx++] = arg; 1.676 + continue; 1.677 + } 1.678 +#else 1.679 + if (strcmp(arg, "-classpath") == 0 || 1.680 + strcmp(arg, "-cp") == 0) { 1.681 + newArgv[newArgvIdx++] = arg; 1.682 + argi++; 1.683 + if (argi < argc) { 1.684 + newArgv[newArgvIdx++] = (*argv)[argi]; 1.685 + } 1.686 + continue; 1.687 + } 1.688 + if (arg[0] != '-') break; 1.689 +#endif 1.690 + 1.691 + /* Did the user pass an explicit VM type? */ 1.692 + i = KnownVMIndex(arg); 1.693 + if (i >= 0) { 1.694 + jvmtype = knownVMs[jvmidx = i].name + 1; /* skip the - */ 1.695 + isVMType = 1; 1.696 + *pargc = *pargc - 1; 1.697 + } 1.698 + 1.699 + /* Did the user specify an "alternate" VM? */ 1.700 + else if (strncmp(arg, "-XXaltjvm=", 10) == 0 || strncmp(arg, "-J-XXaltjvm=", 12) == 0) { 1.701 + isVMType = 1; 1.702 + jvmtype = arg+((arg[1]=='X')? 10 : 12); 1.703 + jvmidx = -1; 1.704 + } 1.705 + 1.706 + if (!isVMType) { 1.707 + newArgv[newArgvIdx++] = arg; 1.708 + } 1.709 + } 1.710 + 1.711 + /* 1.712 + * Finish copying the arguments if we aborted the above loop. 1.713 + * NOTE that if we aborted via "break" then we did NOT copy the 1.714 + * last argument above, and in addition argi will be less than 1.715 + * argc. 1.716 + */ 1.717 + while (argi < argc) { 1.718 + newArgv[newArgvIdx++] = (*argv)[argi]; 1.719 + argi++; 1.720 + } 1.721 + 1.722 + /* argv is null-terminated */ 1.723 + newArgv[newArgvIdx] = 0; 1.724 + 1.725 + /* Copy back argv */ 1.726 + *argv = newArgv; 1.727 + *pargc = newArgvIdx; 1.728 + 1.729 + /* use the default VM type if not specified (no alias processing) */ 1.730 + if (jvmtype == NULL) { 1.731 + char* result = knownVMs[0].name+1; 1.732 + /* Use a different VM type if we are on a server class machine? */ 1.733 + if ((knownVMs[0].flag == VM_IF_SERVER_CLASS) && 1.734 + (ServerClassMachine() == JNI_TRUE)) { 1.735 + result = knownVMs[0].server_class+1; 1.736 + } 1.737 + if (_launcher_debug) { 1.738 + printf("Default VM: %s\n", result); 1.739 + } 1.740 + return result; 1.741 + } 1.742 + 1.743 + /* if using an alternate VM, no alias processing */ 1.744 + if (jvmidx < 0) 1.745 + return jvmtype; 1.746 + 1.747 + /* Resolve aliases first */ 1.748 + { 1.749 + int loopCount = 0; 1.750 + while (knownVMs[jvmidx].flag == VM_ALIASED_TO) { 1.751 + int nextIdx = KnownVMIndex(knownVMs[jvmidx].alias); 1.752 + 1.753 + if (loopCount > knownVMsCount) { 1.754 + if (!speculative) { 1.755 + ReportErrorMessage("Error: Corrupt jvm.cfg file; cycle in alias list.", 1.756 + JNI_TRUE); 1.757 + exit(1); 1.758 + } else { 1.759 + return "ERROR"; 1.760 + /* break; */ 1.761 + } 1.762 + } 1.763 + 1.764 + if (nextIdx < 0) { 1.765 + if (!speculative) { 1.766 + ReportErrorMessage2("Error: Unable to resolve VM alias %s", 1.767 + knownVMs[jvmidx].alias, JNI_TRUE); 1.768 + exit(1); 1.769 + } else { 1.770 + return "ERROR"; 1.771 + } 1.772 + } 1.773 + jvmidx = nextIdx; 1.774 + jvmtype = knownVMs[jvmidx].name+1; 1.775 + loopCount++; 1.776 + } 1.777 + } 1.778 + 1.779 + switch (knownVMs[jvmidx].flag) { 1.780 + case VM_WARN: 1.781 + if (!speculative) { 1.782 + fprintf(stderr, "Warning: %s VM not supported; %s VM will be used\n", 1.783 + jvmtype, knownVMs[0].name + 1); 1.784 + } 1.785 + /* fall through */ 1.786 + case VM_IGNORE: 1.787 + jvmtype = knownVMs[jvmidx=0].name + 1; 1.788 + /* fall through */ 1.789 + case VM_KNOWN: 1.790 + break; 1.791 + case VM_ERROR: 1.792 + if (!speculative) { 1.793 + ReportErrorMessage2("Error: %s VM not supported", jvmtype, JNI_TRUE); 1.794 + exit(1); 1.795 + } else { 1.796 + return "ERROR"; 1.797 + } 1.798 + } 1.799 + 1.800 + return jvmtype; 1.801 +} 1.802 +#endif /* ifndef GAMMA */ 1.803 + 1.804 +# define KB (1024UL) 1.805 +# define MB (1024UL * KB) 1.806 +# define GB (1024UL * MB) 1.807 + 1.808 +/* copied from HotSpot function "atomll()" */ 1.809 +static int 1.810 +parse_stack_size(const char *s, jlong *result) { 1.811 + jlong n = 0; 1.812 + int args_read = sscanf(s, jlong_format_specifier(), &n); 1.813 + if (args_read != 1) { 1.814 + return 0; 1.815 + } 1.816 + while (*s != '\0' && *s >= '0' && *s <= '9') { 1.817 + s++; 1.818 + } 1.819 + // 4705540: illegal if more characters are found after the first non-digit 1.820 + if (strlen(s) > 1) { 1.821 + return 0; 1.822 + } 1.823 + switch (*s) { 1.824 + case 'T': case 't': 1.825 + *result = n * GB * KB; 1.826 + return 1; 1.827 + case 'G': case 'g': 1.828 + *result = n * GB; 1.829 + return 1; 1.830 + case 'M': case 'm': 1.831 + *result = n * MB; 1.832 + return 1; 1.833 + case 'K': case 'k': 1.834 + *result = n * KB; 1.835 + return 1; 1.836 + case '\0': 1.837 + *result = n; 1.838 + return 1; 1.839 + default: 1.840 + /* Create JVM with default stack and let VM handle malformed -Xss string*/ 1.841 + return 0; 1.842 + } 1.843 +} 1.844 + 1.845 +/* 1.846 + * Adds a new VM option with the given given name and value. 1.847 + */ 1.848 +void 1.849 +AddOption(char *str, void *info) 1.850 +{ 1.851 + /* 1.852 + * Expand options array if needed to accommodate at least one more 1.853 + * VM option. 1.854 + */ 1.855 + if (numOptions >= maxOptions) { 1.856 + if (options == 0) { 1.857 + maxOptions = 4; 1.858 + options = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption)); 1.859 + } else { 1.860 + JavaVMOption *tmp; 1.861 + maxOptions *= 2; 1.862 + tmp = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption)); 1.863 + memcpy(tmp, options, numOptions * sizeof(JavaVMOption)); 1.864 + JLI_MemFree(options); 1.865 + options = tmp; 1.866 + } 1.867 + } 1.868 + options[numOptions].optionString = str; 1.869 + options[numOptions++].extraInfo = info; 1.870 + 1.871 + if (strncmp(str, "-Xss", 4) == 0) { 1.872 + jlong tmp; 1.873 + if (parse_stack_size(str + 4, &tmp)) { 1.874 + threadStackSize = tmp; 1.875 + } 1.876 + } 1.877 +} 1.878 + 1.879 +static void 1.880 +SetClassPath(const char *s) 1.881 +{ 1.882 + char *def; 1.883 + s = JLI_WildcardExpandClasspath(s); 1.884 + def = JLI_MemAlloc(strlen(s) + 40); 1.885 + sprintf(def, "-Djava.class.path=%s", s); 1.886 + AddOption(def, NULL); 1.887 +} 1.888 + 1.889 +#ifndef GAMMA 1.890 +/* 1.891 + * The SelectVersion() routine ensures that an appropriate version of 1.892 + * the JRE is running. The specification for the appropriate version 1.893 + * is obtained from either the manifest of a jar file (preferred) or 1.894 + * from command line options. 1.895 + * The routine also parses splash screen command line options and 1.896 + * passes on their values in private environment variables. 1.897 + */ 1.898 +static void 1.899 +SelectVersion(int argc, char **argv, char **main_class) 1.900 +{ 1.901 + char *arg; 1.902 + char **new_argv; 1.903 + char **new_argp; 1.904 + char *operand; 1.905 + char *version = NULL; 1.906 + char *jre = NULL; 1.907 + int jarflag = 0; 1.908 + int headlessflag = 0; 1.909 + int restrict_search = -1; /* -1 implies not known */ 1.910 + manifest_info info; 1.911 + char env_entry[MAXNAMELEN + 24] = ENV_ENTRY "="; 1.912 + char *splash_file_name = NULL; 1.913 + char *splash_jar_name = NULL; 1.914 + char *env_in; 1.915 + int res; 1.916 + 1.917 + /* 1.918 + * If the version has already been selected, set *main_class 1.919 + * with the value passed through the environment (if any) and 1.920 + * simply return. 1.921 + */ 1.922 + if ((env_in = getenv(ENV_ENTRY)) != NULL) { 1.923 + if (*env_in != '\0') 1.924 + *main_class = JLI_StringDup(env_in); 1.925 + return; 1.926 + } 1.927 + 1.928 + /* 1.929 + * Scan through the arguments for options relevant to multiple JRE 1.930 + * support. For reference, the command line syntax is defined as: 1.931 + * 1.932 + * SYNOPSIS 1.933 + * java [options] class [argument...] 1.934 + * 1.935 + * java [options] -jar file.jar [argument...] 1.936 + * 1.937 + * As the scan is performed, make a copy of the argument list with 1.938 + * the version specification options (new to 1.5) removed, so that 1.939 + * a version less than 1.5 can be exec'd. 1.940 + * 1.941 + * Note that due to the syntax of the native Windows interface 1.942 + * CreateProcess(), processing similar to the following exists in 1.943 + * the Windows platform specific routine ExecJRE (in java_md.c). 1.944 + * Changes here should be reproduced there. 1.945 + */ 1.946 + new_argv = JLI_MemAlloc((argc + 1) * sizeof(char*)); 1.947 + new_argv[0] = argv[0]; 1.948 + new_argp = &new_argv[1]; 1.949 + argc--; 1.950 + argv++; 1.951 + while ((arg = *argv) != 0 && *arg == '-') { 1.952 + if (strncmp(arg, "-version:", 9) == 0) { 1.953 + version = arg + 9; 1.954 + } else if (strcmp(arg, "-jre-restrict-search") == 0) { 1.955 + restrict_search = 1; 1.956 + } else if (strcmp(arg, "-no-jre-restrict-search") == 0) { 1.957 + restrict_search = 0; 1.958 + } else { 1.959 + if (strcmp(arg, "-jar") == 0) 1.960 + jarflag = 1; 1.961 + /* deal with "unfortunate" classpath syntax */ 1.962 + if ((strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) && 1.963 + (argc >= 2)) { 1.964 + *new_argp++ = arg; 1.965 + argc--; 1.966 + argv++; 1.967 + arg = *argv; 1.968 + } 1.969 + 1.970 + /* 1.971 + * Checking for headless toolkit option in the some way as AWT does: 1.972 + * "true" means true and any other value means false 1.973 + */ 1.974 + if (strcmp(arg, "-Djava.awt.headless=true") == 0) { 1.975 + headlessflag = 1; 1.976 + } else if (strncmp(arg, "-Djava.awt.headless=", 20) == 0) { 1.977 + headlessflag = 0; 1.978 + } else if (strncmp(arg, "-splash:", 8) == 0) { 1.979 + splash_file_name = arg+8; 1.980 + } 1.981 + *new_argp++ = arg; 1.982 + } 1.983 + argc--; 1.984 + argv++; 1.985 + } 1.986 + if (argc <= 0) { /* No operand? Possibly legit with -[full]version */ 1.987 + operand = NULL; 1.988 + } else { 1.989 + argc--; 1.990 + *new_argp++ = operand = *argv++; 1.991 + } 1.992 + while (argc-- > 0) /* Copy over [argument...] */ 1.993 + *new_argp++ = *argv++; 1.994 + *new_argp = NULL; 1.995 + 1.996 + /* 1.997 + * If there is a jar file, read the manifest. If the jarfile can't be 1.998 + * read, the manifest can't be read from the jar file, or the manifest 1.999 + * is corrupt, issue the appropriate error messages and exit. 1.1000 + * 1.1001 + * Even if there isn't a jar file, construct a manifest_info structure 1.1002 + * containing the command line information. It's a convenient way to carry 1.1003 + * this data around. 1.1004 + */ 1.1005 + if (jarflag && operand) { 1.1006 + if ((res = JLI_ParseManifest(operand, &info)) != 0) { 1.1007 + if (res == -1) 1.1008 + ReportErrorMessage2("Unable to access jarfile %s", 1.1009 + operand, JNI_TRUE); 1.1010 + else 1.1011 + ReportErrorMessage2("Invalid or corrupt jarfile %s", 1.1012 + operand, JNI_TRUE); 1.1013 + exit(1); 1.1014 + } 1.1015 + 1.1016 + /* 1.1017 + * Command line splash screen option should have precedence 1.1018 + * over the manifest, so the manifest data is used only if 1.1019 + * splash_file_name has not been initialized above during command 1.1020 + * line parsing 1.1021 + */ 1.1022 + if (!headlessflag && !splash_file_name && info.splashscreen_image_file_name) { 1.1023 + splash_file_name = info.splashscreen_image_file_name; 1.1024 + splash_jar_name = operand; 1.1025 + } 1.1026 + } else { 1.1027 + info.manifest_version = NULL; 1.1028 + info.main_class = NULL; 1.1029 + info.jre_version = NULL; 1.1030 + info.jre_restrict_search = 0; 1.1031 + } 1.1032 + 1.1033 + /* 1.1034 + * Passing on splash screen info in environment variables 1.1035 + */ 1.1036 + if (splash_file_name && !headlessflag) { 1.1037 + char* splash_file_entry = JLI_MemAlloc(strlen(SPLASH_FILE_ENV_ENTRY "=")+strlen(splash_file_name)+1); 1.1038 + strcpy(splash_file_entry, SPLASH_FILE_ENV_ENTRY "="); 1.1039 + strcat(splash_file_entry, splash_file_name); 1.1040 + putenv(splash_file_entry); 1.1041 + } 1.1042 + if (splash_jar_name && !headlessflag) { 1.1043 + char* splash_jar_entry = JLI_MemAlloc(strlen(SPLASH_JAR_ENV_ENTRY "=")+strlen(splash_jar_name)+1); 1.1044 + strcpy(splash_jar_entry, SPLASH_JAR_ENV_ENTRY "="); 1.1045 + strcat(splash_jar_entry, splash_jar_name); 1.1046 + putenv(splash_jar_entry); 1.1047 + } 1.1048 + 1.1049 + /* 1.1050 + * The JRE-Version and JRE-Restrict-Search values (if any) from the 1.1051 + * manifest are overwritten by any specified on the command line. 1.1052 + */ 1.1053 + if (version != NULL) 1.1054 + info.jre_version = version; 1.1055 + if (restrict_search != -1) 1.1056 + info.jre_restrict_search = restrict_search; 1.1057 + 1.1058 + /* 1.1059 + * "Valid" returns (other than unrecoverable errors) follow. Set 1.1060 + * main_class as a side-effect of this routine. 1.1061 + */ 1.1062 + if (info.main_class != NULL) 1.1063 + *main_class = JLI_StringDup(info.main_class); 1.1064 + 1.1065 + /* 1.1066 + * If no version selection information is found either on the command 1.1067 + * line or in the manifest, simply return. 1.1068 + */ 1.1069 + if (info.jre_version == NULL) { 1.1070 + JLI_FreeManifest(); 1.1071 + JLI_MemFree(new_argv); 1.1072 + return; 1.1073 + } 1.1074 + 1.1075 + /* 1.1076 + * Check for correct syntax of the version specification (JSR 56). 1.1077 + */ 1.1078 + if (!JLI_ValidVersionString(info.jre_version)) { 1.1079 + ReportErrorMessage2("Syntax error in version specification \"%s\"", 1.1080 + info.jre_version, JNI_TRUE); 1.1081 + exit(1); 1.1082 + } 1.1083 + 1.1084 + /* 1.1085 + * Find the appropriate JVM on the system. Just to be as forgiving as 1.1086 + * possible, if the standard algorithms don't locate an appropriate 1.1087 + * jre, check to see if the one running will satisfy the requirements. 1.1088 + * This can happen on systems which haven't been set-up for multiple 1.1089 + * JRE support. 1.1090 + */ 1.1091 + jre = LocateJRE(&info); 1.1092 + if (_launcher_debug) 1.1093 + printf("JRE-Version = %s, JRE-Restrict-Search = %s Selected = %s\n", 1.1094 + (info.jre_version?info.jre_version:"null"), 1.1095 + (info.jre_restrict_search?"true":"false"), (jre?jre:"null")); 1.1096 + if (jre == NULL) { 1.1097 + if (JLI_AcceptableRelease(FULL_VERSION, info.jre_version)) { 1.1098 + JLI_FreeManifest(); 1.1099 + JLI_MemFree(new_argv); 1.1100 + return; 1.1101 + } else { 1.1102 + ReportErrorMessage2( 1.1103 + "Unable to locate JRE meeting specification \"%s\"", 1.1104 + info.jre_version, JNI_TRUE); 1.1105 + exit(1); 1.1106 + } 1.1107 + } 1.1108 + 1.1109 + /* 1.1110 + * If I'm not the chosen one, exec the chosen one. Returning from 1.1111 + * ExecJRE indicates that I am indeed the chosen one. 1.1112 + * 1.1113 + * The private environment variable _JAVA_VERSION_SET is used to 1.1114 + * prevent the chosen one from re-reading the manifest file and 1.1115 + * using the values found within to override the (potential) command 1.1116 + * line flags stripped from argv (because the target may not 1.1117 + * understand them). Passing the MainClass value is an optimization 1.1118 + * to avoid locating, expanding and parsing the manifest extra 1.1119 + * times. 1.1120 + */ 1.1121 + if (info.main_class != NULL) { 1.1122 + if (strlen(info.main_class) <= MAXNAMELEN) { 1.1123 + (void)strcat(env_entry, info.main_class); 1.1124 + } else { 1.1125 + ReportErrorMessage("Error: main-class: attribute exceeds system limits\n", JNI_TRUE); 1.1126 + exit(1); 1.1127 + } 1.1128 + } 1.1129 + (void)putenv(env_entry); 1.1130 + ExecJRE(jre, new_argv); 1.1131 + JLI_FreeManifest(); 1.1132 + JLI_MemFree(new_argv); 1.1133 + return; 1.1134 +} 1.1135 +#endif /* ifndef GAMMA */ 1.1136 + 1.1137 +/* 1.1138 + * Parses command line arguments. Returns JNI_FALSE if launcher 1.1139 + * should exit without starting vm (e.g. certain version and usage 1.1140 + * options); returns JNI_TRUE if vm needs to be started to process 1.1141 + * given options. *pret (the launcher process return value) is set to 1.1142 + * 0 for a normal exit. 1.1143 + */ 1.1144 +static jboolean 1.1145 +ParseArguments(int *pargc, char ***pargv, char **pjarfile, 1.1146 + char **pclassname, int *pret, const char *jvmpath) 1.1147 +{ 1.1148 + int argc = *pargc; 1.1149 + char **argv = *pargv; 1.1150 + jboolean jarflag = JNI_FALSE; 1.1151 + char *arg; 1.1152 + 1.1153 + *pret = 1; 1.1154 + while ((arg = *argv) != 0 && *arg == '-') { 1.1155 + argv++; --argc; 1.1156 + if (strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) { 1.1157 + if (argc < 1) { 1.1158 + ReportErrorMessage2("%s requires class path specification", 1.1159 + arg, JNI_TRUE); 1.1160 + PrintUsage(); 1.1161 + return JNI_FALSE; 1.1162 + } 1.1163 + SetClassPath(*argv); 1.1164 + argv++; --argc; 1.1165 + } else if (strcmp(arg, "-jar") == 0) { 1.1166 + jarflag = JNI_TRUE; 1.1167 + } else if (strcmp(arg, "-help") == 0 || 1.1168 + strcmp(arg, "-h") == 0 || 1.1169 + strcmp(arg, "-?") == 0) { 1.1170 + PrintUsage(); 1.1171 + *pret = 0; 1.1172 + return JNI_FALSE; 1.1173 + } else if (strcmp(arg, "-version") == 0) { 1.1174 + printVersion = JNI_TRUE; 1.1175 + return JNI_TRUE; 1.1176 + } else if (strcmp(arg, "-showversion") == 0) { 1.1177 + showVersion = JNI_TRUE; 1.1178 + } else if (strcmp(arg, "-X") == 0) { 1.1179 + *pret = PrintXUsage(jvmpath); 1.1180 + return JNI_FALSE; 1.1181 +/* 1.1182 + * The following case provide backward compatibility with old-style 1.1183 + * command line options. 1.1184 + */ 1.1185 + } else if (strcmp(arg, "-fullversion") == 0) { 1.1186 + fprintf(stderr, "%s full version \"%s\"\n", progname, 1.1187 + FULL_VERSION); 1.1188 + *pret = 0; 1.1189 + return JNI_FALSE; 1.1190 + } else if (strcmp(arg, "-verbosegc") == 0) { 1.1191 + AddOption("-verbose:gc", NULL); 1.1192 + } else if (strcmp(arg, "-t") == 0) { 1.1193 + AddOption("-Xt", NULL); 1.1194 + } else if (strcmp(arg, "-tm") == 0) { 1.1195 + AddOption("-Xtm", NULL); 1.1196 + } else if (strcmp(arg, "-debug") == 0) { 1.1197 + AddOption("-Xdebug", NULL); 1.1198 + } else if (strcmp(arg, "-noclassgc") == 0) { 1.1199 + AddOption("-Xnoclassgc", NULL); 1.1200 + } else if (strcmp(arg, "-Xfuture") == 0) { 1.1201 + AddOption("-Xverify:all", NULL); 1.1202 + } else if (strcmp(arg, "-verify") == 0) { 1.1203 + AddOption("-Xverify:all", NULL); 1.1204 + } else if (strcmp(arg, "-verifyremote") == 0) { 1.1205 + AddOption("-Xverify:remote", NULL); 1.1206 + } else if (strcmp(arg, "-noverify") == 0) { 1.1207 + AddOption("-Xverify:none", NULL); 1.1208 + } else if (strcmp(arg, "-XXsuppressExitMessage") == 0) { 1.1209 + noExitErrorMessage = 1; 1.1210 + } else if (strncmp(arg, "-prof", 5) == 0) { 1.1211 + char *p = arg + 5; 1.1212 + char *tmp = JLI_MemAlloc(strlen(arg) + 50); 1.1213 + if (*p) { 1.1214 + sprintf(tmp, "-Xrunhprof:cpu=old,file=%s", p + 1); 1.1215 + } else { 1.1216 + sprintf(tmp, "-Xrunhprof:cpu=old,file=java.prof"); 1.1217 + } 1.1218 + AddOption(tmp, NULL); 1.1219 + } else if (strncmp(arg, "-ss", 3) == 0 || 1.1220 + strncmp(arg, "-oss", 4) == 0 || 1.1221 + strncmp(arg, "-ms", 3) == 0 || 1.1222 + strncmp(arg, "-mx", 3) == 0) { 1.1223 + char *tmp = JLI_MemAlloc(strlen(arg) + 6); 1.1224 + sprintf(tmp, "-X%s", arg + 1); /* skip '-' */ 1.1225 + AddOption(tmp, NULL); 1.1226 + } else if (strcmp(arg, "-checksource") == 0 || 1.1227 + strcmp(arg, "-cs") == 0 || 1.1228 + strcmp(arg, "-noasyncgc") == 0) { 1.1229 + /* No longer supported */ 1.1230 + fprintf(stderr, 1.1231 + "Warning: %s option is no longer supported.\n", 1.1232 + arg); 1.1233 + } else if (strncmp(arg, "-version:", 9) == 0 || 1.1234 + strcmp(arg, "-no-jre-restrict-search") == 0 || 1.1235 + strcmp(arg, "-jre-restrict-search") == 0 || 1.1236 + strncmp(arg, "-splash:", 8) == 0) { 1.1237 + ; /* Ignore machine independent options already handled */ 1.1238 + } else if (RemovableMachineDependentOption(arg) ) { 1.1239 + ; /* Do not pass option to vm. */ 1.1240 + } 1.1241 + else { 1.1242 + AddOption(arg, NULL); 1.1243 + } 1.1244 + } 1.1245 + 1.1246 + if (--argc >= 0) { 1.1247 + if (jarflag) { 1.1248 + *pjarfile = *argv++; 1.1249 + *pclassname = 0; 1.1250 + } else { 1.1251 + *pjarfile = 0; 1.1252 + *pclassname = *argv++; 1.1253 + } 1.1254 + *pargc = argc; 1.1255 + *pargv = argv; 1.1256 + } 1.1257 + 1.1258 + return JNI_TRUE; 1.1259 +} 1.1260 + 1.1261 +/* 1.1262 + * Initializes the Java Virtual Machine. Also frees options array when 1.1263 + * finished. 1.1264 + */ 1.1265 +static jboolean 1.1266 +InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn) 1.1267 +{ 1.1268 + JavaVMInitArgs args; 1.1269 + jint r; 1.1270 + 1.1271 + memset(&args, 0, sizeof(args)); 1.1272 + args.version = JNI_VERSION_1_2; 1.1273 + args.nOptions = numOptions; 1.1274 + args.options = options; 1.1275 + args.ignoreUnrecognized = JNI_FALSE; 1.1276 + 1.1277 + if (_launcher_debug) { 1.1278 + int i = 0; 1.1279 + printf("JavaVM args:\n "); 1.1280 + printf("version 0x%08lx, ", (long)args.version); 1.1281 + printf("ignoreUnrecognized is %s, ", 1.1282 + args.ignoreUnrecognized ? "JNI_TRUE" : "JNI_FALSE"); 1.1283 + printf("nOptions is %ld\n", (long)args.nOptions); 1.1284 + for (i = 0; i < numOptions; i++) 1.1285 + printf(" option[%2d] = '%s'\n", 1.1286 + i, args.options[i].optionString); 1.1287 + } 1.1288 + 1.1289 + r = ifn->CreateJavaVM(pvm, (void **)penv, &args); 1.1290 + JLI_MemFree(options); 1.1291 + return r == JNI_OK; 1.1292 +} 1.1293 + 1.1294 + 1.1295 +#define NULL_CHECK0(e) if ((e) == 0) return 0 1.1296 +#define NULL_CHECK(e) if ((e) == 0) return 1.1297 + 1.1298 +static jstring platformEncoding = NULL; 1.1299 +static jstring getPlatformEncoding(JNIEnv *env) { 1.1300 + if (platformEncoding == NULL) { 1.1301 + jstring propname = (*env)->NewStringUTF(env, "sun.jnu.encoding"); 1.1302 + if (propname) { 1.1303 + jclass cls; 1.1304 + jmethodID mid; 1.1305 + NULL_CHECK0 (cls = (*env)->FindClass(env, "java/lang/System")); 1.1306 + NULL_CHECK0 (mid = (*env)->GetStaticMethodID( 1.1307 + env, cls, 1.1308 + "getProperty", 1.1309 + "(Ljava/lang/String;)Ljava/lang/String;")); 1.1310 + platformEncoding = (*env)->CallStaticObjectMethod ( 1.1311 + env, cls, mid, propname); 1.1312 + } 1.1313 + } 1.1314 + return platformEncoding; 1.1315 +} 1.1316 + 1.1317 +static jboolean isEncodingSupported(JNIEnv *env, jstring enc) { 1.1318 + jclass cls; 1.1319 + jmethodID mid; 1.1320 + NULL_CHECK0 (cls = (*env)->FindClass(env, "java/nio/charset/Charset")); 1.1321 + NULL_CHECK0 (mid = (*env)->GetStaticMethodID( 1.1322 + env, cls, 1.1323 + "isSupported", 1.1324 + "(Ljava/lang/String;)Z")); 1.1325 + return (*env)->CallStaticBooleanMethod(env, cls, mid, enc); 1.1326 +} 1.1327 + 1.1328 +/* 1.1329 + * Returns a new Java string object for the specified platform string. 1.1330 + */ 1.1331 +static jstring 1.1332 +NewPlatformString(JNIEnv *env, char *s) 1.1333 +{ 1.1334 + int len = (int)strlen(s); 1.1335 + jclass cls; 1.1336 + jmethodID mid; 1.1337 + jbyteArray ary; 1.1338 + jstring enc; 1.1339 + 1.1340 + if (s == NULL) 1.1341 + return 0; 1.1342 + enc = getPlatformEncoding(env); 1.1343 + 1.1344 + ary = (*env)->NewByteArray(env, len); 1.1345 + if (ary != 0) { 1.1346 + jstring str = 0; 1.1347 + (*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s); 1.1348 + if (!(*env)->ExceptionOccurred(env)) { 1.1349 + if (isEncodingSupported(env, enc) == JNI_TRUE) { 1.1350 + NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String")); 1.1351 + NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", 1.1352 + "([BLjava/lang/String;)V")); 1.1353 + str = (*env)->NewObject(env, cls, mid, ary, enc); 1.1354 + } else { 1.1355 + /*If the encoding specified in sun.jnu.encoding is not 1.1356 + endorsed by "Charset.isSupported" we have to fall back 1.1357 + to use String(byte[]) explicitly here without specifying 1.1358 + the encoding name, in which the StringCoding class will 1.1359 + pickup the iso-8859-1 as the fallback converter for us. 1.1360 + */ 1.1361 + NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String")); 1.1362 + NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", 1.1363 + "([B)V")); 1.1364 + str = (*env)->NewObject(env, cls, mid, ary); 1.1365 + } 1.1366 + (*env)->DeleteLocalRef(env, ary); 1.1367 + return str; 1.1368 + } 1.1369 + } 1.1370 + return 0; 1.1371 +} 1.1372 + 1.1373 +/* 1.1374 + * Returns a new array of Java string objects for the specified 1.1375 + * array of platform strings. 1.1376 + */ 1.1377 +static jobjectArray 1.1378 +NewPlatformStringArray(JNIEnv *env, char **strv, int strc) 1.1379 +{ 1.1380 + jarray cls; 1.1381 + jarray ary; 1.1382 + int i; 1.1383 + 1.1384 + NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String")); 1.1385 + NULL_CHECK0(ary = (*env)->NewObjectArray(env, strc, cls, 0)); 1.1386 + for (i = 0; i < strc; i++) { 1.1387 + jstring str = NewPlatformString(env, *strv++); 1.1388 + NULL_CHECK0(str); 1.1389 + (*env)->SetObjectArrayElement(env, ary, i, str); 1.1390 + (*env)->DeleteLocalRef(env, str); 1.1391 + } 1.1392 + return ary; 1.1393 +} 1.1394 + 1.1395 +/* 1.1396 + * Loads a class, convert the '.' to '/'. 1.1397 + */ 1.1398 +static jclass 1.1399 +LoadClass(JNIEnv *env, char *name) 1.1400 +{ 1.1401 + char *buf = JLI_MemAlloc(strlen(name) + 1); 1.1402 + char *s = buf, *t = name, c; 1.1403 + jclass cls; 1.1404 + jlong start, end; 1.1405 + 1.1406 + if (_launcher_debug) 1.1407 + start = CounterGet(); 1.1408 + 1.1409 + do { 1.1410 + c = *t++; 1.1411 + *s++ = (c == '.') ? '/' : c; 1.1412 + } while (c != '\0'); 1.1413 + cls = (*env)->FindClass(env, buf); 1.1414 + JLI_MemFree(buf); 1.1415 + 1.1416 + if (_launcher_debug) { 1.1417 + end = CounterGet(); 1.1418 + printf("%ld micro seconds to load main class\n", 1.1419 + (long)(jint)Counter2Micros(end-start)); 1.1420 + printf("----_JAVA_LAUNCHER_DEBUG----\n"); 1.1421 + } 1.1422 + 1.1423 + return cls; 1.1424 +} 1.1425 + 1.1426 + 1.1427 +/* 1.1428 + * Returns the main class name for the specified jar file. 1.1429 + */ 1.1430 +static jstring 1.1431 +GetMainClassName(JNIEnv *env, char *jarname) 1.1432 +{ 1.1433 +#define MAIN_CLASS "Main-Class" 1.1434 + jclass cls; 1.1435 + jmethodID mid; 1.1436 + jobject jar, man, attr; 1.1437 + jstring str, result = 0; 1.1438 + 1.1439 + NULL_CHECK0(cls = (*env)->FindClass(env, "java/util/jar/JarFile")); 1.1440 + NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", 1.1441 + "(Ljava/lang/String;)V")); 1.1442 + NULL_CHECK0(str = NewPlatformString(env, jarname)); 1.1443 + NULL_CHECK0(jar = (*env)->NewObject(env, cls, mid, str)); 1.1444 + NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "getManifest", 1.1445 + "()Ljava/util/jar/Manifest;")); 1.1446 + man = (*env)->CallObjectMethod(env, jar, mid); 1.1447 + if (man != 0) { 1.1448 + NULL_CHECK0(mid = (*env)->GetMethodID(env, 1.1449 + (*env)->GetObjectClass(env, man), 1.1450 + "getMainAttributes", 1.1451 + "()Ljava/util/jar/Attributes;")); 1.1452 + attr = (*env)->CallObjectMethod(env, man, mid); 1.1453 + if (attr != 0) { 1.1454 + NULL_CHECK0(mid = (*env)->GetMethodID(env, 1.1455 + (*env)->GetObjectClass(env, attr), 1.1456 + "getValue", 1.1457 + "(Ljava/lang/String;)Ljava/lang/String;")); 1.1458 + NULL_CHECK0(str = NewPlatformString(env, MAIN_CLASS)); 1.1459 + result = (*env)->CallObjectMethod(env, attr, mid, str); 1.1460 + } 1.1461 + } 1.1462 + return result; 1.1463 +} 1.1464 + 1.1465 +#ifdef JAVA_ARGS 1.1466 +static char *java_args[] = JAVA_ARGS; 1.1467 +static char *app_classpath[] = APP_CLASSPATH; 1.1468 + 1.1469 +/* 1.1470 + * For tools, convert command line args thus: 1.1471 + * javac -cp foo:foo/"*" -J-ms32m ... 1.1472 + * java -ms32m -cp JLI_WildcardExpandClasspath(foo:foo/"*") ... 1.1473 + */ 1.1474 +static void 1.1475 +TranslateApplicationArgs(int *pargc, char ***pargv) 1.1476 +{ 1.1477 + const int NUM_ARGS = (sizeof(java_args) / sizeof(char *)); 1.1478 + int argc = *pargc; 1.1479 + char **argv = *pargv; 1.1480 + int nargc = argc + NUM_ARGS; 1.1481 + char **nargv = JLI_MemAlloc((nargc + 1) * sizeof(char *)); 1.1482 + int i; 1.1483 + 1.1484 + *pargc = nargc; 1.1485 + *pargv = nargv; 1.1486 + 1.1487 + /* Copy the VM arguments (i.e. prefixed with -J) */ 1.1488 + for (i = 0; i < NUM_ARGS; i++) { 1.1489 + char *arg = java_args[i]; 1.1490 + if (arg[0] == '-' && arg[1] == 'J') { 1.1491 + *nargv++ = arg + 2; 1.1492 + } 1.1493 + } 1.1494 + 1.1495 + for (i = 0; i < argc; i++) { 1.1496 + char *arg = argv[i]; 1.1497 + if (arg[0] == '-' && arg[1] == 'J') { 1.1498 + if (arg[2] == '\0') { 1.1499 + ReportErrorMessage("Error: the -J option should not be " 1.1500 + "followed by a space.", JNI_TRUE); 1.1501 + exit(1); 1.1502 + } 1.1503 + *nargv++ = arg + 2; 1.1504 + } 1.1505 + } 1.1506 + 1.1507 + /* Copy the rest of the arguments */ 1.1508 + for (i = 0; i < NUM_ARGS; i++) { 1.1509 + char *arg = java_args[i]; 1.1510 + if (arg[0] != '-' || arg[1] != 'J') { 1.1511 + *nargv++ = arg; 1.1512 + } 1.1513 + } 1.1514 + for (i = 0; i < argc; i++) { 1.1515 + char *arg = argv[i]; 1.1516 + if (arg[0] == '-') { 1.1517 + if (arg[1] == 'J') 1.1518 + continue; 1.1519 +#ifdef EXPAND_CLASSPATH_WILDCARDS 1.1520 + if (arg[1] == 'c' 1.1521 + && (strcmp(arg, "-cp") == 0 || 1.1522 + strcmp(arg, "-classpath") == 0) 1.1523 + && i < argc - 1) { 1.1524 + *nargv++ = arg; 1.1525 + *nargv++ = (char *) JLI_WildcardExpandClasspath(argv[i+1]); 1.1526 + i++; 1.1527 + continue; 1.1528 + } 1.1529 +#endif 1.1530 + } 1.1531 + *nargv++ = arg; 1.1532 + } 1.1533 + *nargv = 0; 1.1534 +} 1.1535 + 1.1536 +/* 1.1537 + * For our tools, we try to add 3 VM options: 1.1538 + * -Denv.class.path=<envcp> 1.1539 + * -Dapplication.home=<apphome> 1.1540 + * -Djava.class.path=<appcp> 1.1541 + * <envcp> is the user's setting of CLASSPATH -- for instance the user 1.1542 + * tells javac where to find binary classes through this environment 1.1543 + * variable. Notice that users will be able to compile against our 1.1544 + * tools classes (sun.tools.javac.Main) only if they explicitly add 1.1545 + * tools.jar to CLASSPATH. 1.1546 + * <apphome> is the directory where the application is installed. 1.1547 + * <appcp> is the classpath to where our apps' classfiles are. 1.1548 + */ 1.1549 +static jboolean 1.1550 +AddApplicationOptions() 1.1551 +{ 1.1552 + const int NUM_APP_CLASSPATH = (sizeof(app_classpath) / sizeof(char *)); 1.1553 + char *envcp, *appcp, *apphome; 1.1554 + char home[MAXPATHLEN]; /* application home */ 1.1555 + char separator[] = { PATH_SEPARATOR, '\0' }; 1.1556 + int size, i; 1.1557 + int strlenHome; 1.1558 + 1.1559 + { 1.1560 + const char *s = getenv("CLASSPATH"); 1.1561 + if (s) { 1.1562 + s = (char *) JLI_WildcardExpandClasspath(s); 1.1563 + /* 40 for -Denv.class.path= */ 1.1564 + envcp = (char *)JLI_MemAlloc(strlen(s) + 40); 1.1565 + sprintf(envcp, "-Denv.class.path=%s", s); 1.1566 + AddOption(envcp, NULL); 1.1567 + } 1.1568 + } 1.1569 + 1.1570 + if (!GetApplicationHome(home, sizeof(home))) { 1.1571 + ReportErrorMessage("Can't determine application home", JNI_TRUE); 1.1572 + return JNI_FALSE; 1.1573 + } 1.1574 + 1.1575 + /* 40 for '-Dapplication.home=' */ 1.1576 + apphome = (char *)JLI_MemAlloc(strlen(home) + 40); 1.1577 + sprintf(apphome, "-Dapplication.home=%s", home); 1.1578 + AddOption(apphome, NULL); 1.1579 + 1.1580 + /* How big is the application's classpath? */ 1.1581 + size = 40; /* 40: "-Djava.class.path=" */ 1.1582 + strlenHome = (int)strlen(home); 1.1583 + for (i = 0; i < NUM_APP_CLASSPATH; i++) { 1.1584 + size += strlenHome + (int)strlen(app_classpath[i]) + 1; /* 1: separator */ 1.1585 + } 1.1586 + appcp = (char *)JLI_MemAlloc(size + 1); 1.1587 + strcpy(appcp, "-Djava.class.path="); 1.1588 + for (i = 0; i < NUM_APP_CLASSPATH; i++) { 1.1589 + strcat(appcp, home); /* c:\program files\myapp */ 1.1590 + strcat(appcp, app_classpath[i]); /* \lib\myapp.jar */ 1.1591 + strcat(appcp, separator); /* ; */ 1.1592 + } 1.1593 + appcp[strlen(appcp)-1] = '\0'; /* remove trailing path separator */ 1.1594 + AddOption(appcp, NULL); 1.1595 + return JNI_TRUE; 1.1596 +} 1.1597 +#endif /* JAVA_ARGS */ 1.1598 + 1.1599 +/* 1.1600 + * inject the -Dsun.java.command pseudo property into the args structure 1.1601 + * this pseudo property is used in the HotSpot VM to expose the 1.1602 + * Java class name and arguments to the main method to the VM. The 1.1603 + * HotSpot VM uses this pseudo property to store the Java class name 1.1604 + * (or jar file name) and the arguments to the class's main method 1.1605 + * to the instrumentation memory region. The sun.java.command pseudo 1.1606 + * property is not exported by HotSpot to the Java layer. 1.1607 + */ 1.1608 +void 1.1609 +SetJavaCommandLineProp(char *classname, char *jarfile, 1.1610 + int argc, char **argv) 1.1611 +{ 1.1612 + 1.1613 + int i = 0; 1.1614 + size_t len = 0; 1.1615 + char* javaCommand = NULL; 1.1616 + char* dashDstr = "-Dsun.java.command="; 1.1617 + 1.1618 + if (classname == NULL && jarfile == NULL) { 1.1619 + /* unexpected, one of these should be set. just return without 1.1620 + * setting the property 1.1621 + */ 1.1622 + return; 1.1623 + } 1.1624 + 1.1625 + /* if the class name is not set, then use the jarfile name */ 1.1626 + if (classname == NULL) { 1.1627 + classname = jarfile; 1.1628 + } 1.1629 + 1.1630 + /* determine the amount of memory to allocate assuming 1.1631 + * the individual components will be space separated 1.1632 + */ 1.1633 + len = strlen(classname); 1.1634 + for (i = 0; i < argc; i++) { 1.1635 + len += strlen(argv[i]) + 1; 1.1636 + } 1.1637 + 1.1638 + /* allocate the memory */ 1.1639 + javaCommand = (char*) JLI_MemAlloc(len + strlen(dashDstr) + 1); 1.1640 + 1.1641 + /* build the -D string */ 1.1642 + *javaCommand = '\0'; 1.1643 + strcat(javaCommand, dashDstr); 1.1644 + strcat(javaCommand, classname); 1.1645 + 1.1646 + for (i = 0; i < argc; i++) { 1.1647 + /* the components of the string are space separated. In 1.1648 + * the case of embedded white space, the relationship of 1.1649 + * the white space separated components to their true 1.1650 + * positional arguments will be ambiguous. This issue may 1.1651 + * be addressed in a future release. 1.1652 + */ 1.1653 + strcat(javaCommand, " "); 1.1654 + strcat(javaCommand, argv[i]); 1.1655 + } 1.1656 + 1.1657 + AddOption(javaCommand, NULL); 1.1658 +} 1.1659 + 1.1660 +/* 1.1661 + * JVM would like to know if it's created by a standard Sun launcher, or by 1.1662 + * user native application, the following property indicates the former. 1.1663 + */ 1.1664 +void SetJavaLauncherProp() { 1.1665 + AddOption("-Dsun.java.launcher=" LAUNCHER_TYPE, NULL); 1.1666 +} 1.1667 + 1.1668 +/* 1.1669 + * Prints the version information from the java.version and other properties. 1.1670 + */ 1.1671 +static void 1.1672 +PrintJavaVersion(JNIEnv *env) 1.1673 +{ 1.1674 + jclass ver; 1.1675 + jmethodID print; 1.1676 + 1.1677 + NULL_CHECK(ver = (*env)->FindClass(env, "sun/misc/Version")); 1.1678 + NULL_CHECK(print = (*env)->GetStaticMethodID(env, ver, "print", "()V")); 1.1679 + 1.1680 + (*env)->CallStaticVoidMethod(env, ver, print); 1.1681 +} 1.1682 + 1.1683 +/* 1.1684 + * Prints default usage message. 1.1685 + */ 1.1686 +static void 1.1687 +PrintUsage(void) 1.1688 +{ 1.1689 +#ifndef GAMMA 1.1690 + int i; 1.1691 +#endif 1.1692 + 1.1693 + fprintf(stdout, 1.1694 + "Usage: %s [-options] class [args...]\n" 1.1695 + " (to execute a class)\n" 1.1696 + " or %s [-options] -jar jarfile [args...]\n" 1.1697 + " (to execute a jar file)\n" 1.1698 + "\n" 1.1699 + "where options include:\n", 1.1700 + progname, 1.1701 + progname); 1.1702 + 1.1703 +#ifndef GAMMA 1.1704 + PrintMachineDependentOptions(); 1.1705 + 1.1706 + if ((knownVMs[0].flag == VM_KNOWN) || 1.1707 + (knownVMs[0].flag == VM_IF_SERVER_CLASS)) { 1.1708 + fprintf(stdout, " %s\t to select the \"%s\" VM\n", 1.1709 + knownVMs[0].name, knownVMs[0].name+1); 1.1710 + } 1.1711 + for (i=1; i<knownVMsCount; i++) { 1.1712 + if (knownVMs[i].flag == VM_KNOWN) 1.1713 + fprintf(stdout, " %s\t to select the \"%s\" VM\n", 1.1714 + knownVMs[i].name, knownVMs[i].name+1); 1.1715 + } 1.1716 + for (i=1; i<knownVMsCount; i++) { 1.1717 + if (knownVMs[i].flag == VM_ALIASED_TO) 1.1718 + fprintf(stdout, " %s\t is a synonym for " 1.1719 + "the \"%s\" VM [deprecated]\n", 1.1720 + knownVMs[i].name, knownVMs[i].alias+1); 1.1721 + } 1.1722 + /* The first known VM is the default */ 1.1723 + { 1.1724 + const char* defaultVM = knownVMs[0].name+1; 1.1725 + const char* punctuation = "."; 1.1726 + const char* reason = ""; 1.1727 + if ((knownVMs[0].flag == VM_IF_SERVER_CLASS) && 1.1728 + (ServerClassMachine() == JNI_TRUE)) { 1.1729 + defaultVM = knownVMs[0].server_class+1; 1.1730 + punctuation = ", "; 1.1731 + reason = "because you are running on a server-class machine.\n"; 1.1732 + } 1.1733 + fprintf(stdout, " The default VM is %s%s\n", 1.1734 + defaultVM, punctuation); 1.1735 + fprintf(stdout, " %s\n", 1.1736 + reason); 1.1737 + } 1.1738 +#endif /* ifndef GAMMA */ 1.1739 + 1.1740 + fprintf(stdout, 1.1741 +" -cp <class search path of directories and zip/jar files>\n" 1.1742 +" -classpath <class search path of directories and zip/jar files>\n" 1.1743 +" A %c separated list of directories, JAR archives,\n" 1.1744 +" and ZIP archives to search for class files.\n" 1.1745 +" -D<name>=<value>\n" 1.1746 +" set a system property\n" 1.1747 +" -verbose[:class|gc|jni]\n" 1.1748 +" enable verbose output\n" 1.1749 +" -version print product version and exit\n" 1.1750 +" -version:<value>\n" 1.1751 +" require the specified version to run\n" 1.1752 +" -showversion print product version and continue\n" 1.1753 +" -jre-restrict-search | -jre-no-restrict-search\n" 1.1754 +" include/exclude user private JREs in the version search\n" 1.1755 +" -? -help print this help message\n" 1.1756 +" -X print help on non-standard options\n" 1.1757 +" -ea[:<packagename>...|:<classname>]\n" 1.1758 +" -enableassertions[:<packagename>...|:<classname>]\n" 1.1759 +" enable assertions\n" 1.1760 +" -da[:<packagename>...|:<classname>]\n" 1.1761 +" -disableassertions[:<packagename>...|:<classname>]\n" 1.1762 +" disable assertions\n" 1.1763 +" -esa | -enablesystemassertions\n" 1.1764 +" enable system assertions\n" 1.1765 +" -dsa | -disablesystemassertions\n" 1.1766 +" disable system assertions\n" 1.1767 +" -agentlib:<libname>[=<options>]\n" 1.1768 +" load native agent library <libname>, e.g. -agentlib:hprof\n" 1.1769 +" see also, -agentlib:jdwp=help and -agentlib:hprof=help\n" 1.1770 +" -agentpath:<pathname>[=<options>]\n" 1.1771 +" load native agent library by full pathname\n" 1.1772 +" -javaagent:<jarpath>[=<options>]\n" 1.1773 +" load Java programming language agent, see java.lang.instrument\n" 1.1774 +" -splash:<imagepath>\n" 1.1775 +" show splash screen with specified image\n" 1.1776 + 1.1777 + ,PATH_SEPARATOR); 1.1778 +} 1.1779 + 1.1780 +/* 1.1781 + * Print usage message for -X options. 1.1782 + */ 1.1783 +static jint 1.1784 +PrintXUsage(const char *jvmpath) 1.1785 +{ 1.1786 + /* 1.1787 + A 32 bit cushion to prevent buffer overrun, noting that 1.1788 + fopen(3C) may fail if the buffer exceeds MAXPATHLEN. 1.1789 + */ 1.1790 + char path[MAXPATHLEN+32]; 1.1791 + char buf[128]; 1.1792 + size_t n; 1.1793 + FILE *fp; 1.1794 + static const char Xusage_txt[] = "/Xusage.txt"; 1.1795 + 1.1796 + strcpy(path, jvmpath); 1.1797 + /* Note the FILE_SEPARATOR is platform dependent */ 1.1798 + strcpy(strrchr(path, FILE_SEPARATOR), Xusage_txt); 1.1799 + fp = fopen(path, "r"); 1.1800 + if (fp == 0) { 1.1801 + fprintf(stderr, "Can't open %s\n", path); 1.1802 + return 1; 1.1803 + } 1.1804 + while ((n = fread(buf, 1, sizeof(buf), fp)) != 0) { 1.1805 + fwrite(buf, 1, n, stdout); 1.1806 + } 1.1807 + fclose(fp); 1.1808 + return 0; 1.1809 +} 1.1810 + 1.1811 +#ifndef GAMMA 1.1812 +/* 1.1813 + * Read the jvm.cfg file and fill the knownJVMs[] array. 1.1814 + * 1.1815 + * The functionality of the jvm.cfg file is subject to change without 1.1816 + * notice and the mechanism will be removed in the future. 1.1817 + * 1.1818 + * The lexical structure of the jvm.cfg file is as follows: 1.1819 + * 1.1820 + * jvmcfg := { vmLine } 1.1821 + * vmLine := knownLine 1.1822 + * | aliasLine 1.1823 + * | warnLine 1.1824 + * | ignoreLine 1.1825 + * | errorLine 1.1826 + * | predicateLine 1.1827 + * | commentLine 1.1828 + * knownLine := flag "KNOWN" EOL 1.1829 + * warnLine := flag "WARN" EOL 1.1830 + * ignoreLine := flag "IGNORE" EOL 1.1831 + * errorLine := flag "ERROR" EOL 1.1832 + * aliasLine := flag "ALIASED_TO" flag EOL 1.1833 + * predicateLine := flag "IF_SERVER_CLASS" flag EOL 1.1834 + * commentLine := "#" text EOL 1.1835 + * flag := "-" identifier 1.1836 + * 1.1837 + * The semantics are that when someone specifies a flag on the command line: 1.1838 + * - if the flag appears on a knownLine, then the identifier is used as 1.1839 + * the name of the directory holding the JVM library (the name of the JVM). 1.1840 + * - if the flag appears as the first flag on an aliasLine, the identifier 1.1841 + * of the second flag is used as the name of the JVM. 1.1842 + * - if the flag appears on a warnLine, the identifier is used as the 1.1843 + * name of the JVM, but a warning is generated. 1.1844 + * - if the flag appears on an ignoreLine, the identifier is recognized as the 1.1845 + * name of a JVM, but the identifier is ignored and the default vm used 1.1846 + * - if the flag appears on an errorLine, an error is generated. 1.1847 + * - if the flag appears as the first flag on a predicateLine, and 1.1848 + * the machine on which you are running passes the predicate indicated, 1.1849 + * then the identifier of the second flag is used as the name of the JVM, 1.1850 + * otherwise the identifier of the first flag is used as the name of the JVM. 1.1851 + * If no flag is given on the command line, the first vmLine of the jvm.cfg 1.1852 + * file determines the name of the JVM. 1.1853 + * PredicateLines are only interpreted on first vmLine of a jvm.cfg file, 1.1854 + * since they only make sense if someone hasn't specified the name of the 1.1855 + * JVM on the command line. 1.1856 + * 1.1857 + * The intent of the jvm.cfg file is to allow several JVM libraries to 1.1858 + * be installed in different subdirectories of a single JRE installation, 1.1859 + * for space-savings and convenience in testing. 1.1860 + * The intent is explicitly not to provide a full aliasing or predicate 1.1861 + * mechanism. 1.1862 + */ 1.1863 +jint 1.1864 +ReadKnownVMs(const char *jrepath, char * arch, jboolean speculative) 1.1865 +{ 1.1866 + FILE *jvmCfg; 1.1867 + char jvmCfgName[MAXPATHLEN+20]; 1.1868 + char line[MAXPATHLEN+20]; 1.1869 + int cnt = 0; 1.1870 + int lineno = 0; 1.1871 + jlong start, end; 1.1872 + int vmType; 1.1873 + char *tmpPtr; 1.1874 + char *altVMName = NULL; 1.1875 + char *serverClassVMName = NULL; 1.1876 + static char *whiteSpace = " \t"; 1.1877 + if (_launcher_debug) { 1.1878 + start = CounterGet(); 1.1879 + } 1.1880 + 1.1881 + strcpy(jvmCfgName, jrepath); 1.1882 + strcat(jvmCfgName, FILESEP "lib" FILESEP); 1.1883 + strcat(jvmCfgName, arch); 1.1884 + strcat(jvmCfgName, FILESEP "jvm.cfg"); 1.1885 + 1.1886 + jvmCfg = fopen(jvmCfgName, "r"); 1.1887 + if (jvmCfg == NULL) { 1.1888 + if (!speculative) { 1.1889 + ReportErrorMessage2("Error: could not open `%s'", jvmCfgName, 1.1890 + JNI_TRUE); 1.1891 + exit(1); 1.1892 + } else { 1.1893 + return -1; 1.1894 + } 1.1895 + } 1.1896 + while (fgets(line, sizeof(line), jvmCfg) != NULL) { 1.1897 + vmType = VM_UNKNOWN; 1.1898 + lineno++; 1.1899 + if (line[0] == '#') 1.1900 + continue; 1.1901 + if (line[0] != '-') { 1.1902 + fprintf(stderr, "Warning: no leading - on line %d of `%s'\n", 1.1903 + lineno, jvmCfgName); 1.1904 + } 1.1905 + if (cnt >= knownVMsLimit) { 1.1906 + GrowKnownVMs(cnt); 1.1907 + } 1.1908 + line[strlen(line)-1] = '\0'; /* remove trailing newline */ 1.1909 + tmpPtr = line + strcspn(line, whiteSpace); 1.1910 + if (*tmpPtr == 0) { 1.1911 + fprintf(stderr, "Warning: missing VM type on line %d of `%s'\n", 1.1912 + lineno, jvmCfgName); 1.1913 + } else { 1.1914 + /* Null-terminate this string for JLI_StringDup below */ 1.1915 + *tmpPtr++ = 0; 1.1916 + tmpPtr += strspn(tmpPtr, whiteSpace); 1.1917 + if (*tmpPtr == 0) { 1.1918 + fprintf(stderr, "Warning: missing VM type on line %d of `%s'\n", 1.1919 + lineno, jvmCfgName); 1.1920 + } else { 1.1921 + if (!strncmp(tmpPtr, "KNOWN", strlen("KNOWN"))) { 1.1922 + vmType = VM_KNOWN; 1.1923 + } else if (!strncmp(tmpPtr, "ALIASED_TO", strlen("ALIASED_TO"))) { 1.1924 + tmpPtr += strcspn(tmpPtr, whiteSpace); 1.1925 + if (*tmpPtr != 0) { 1.1926 + tmpPtr += strspn(tmpPtr, whiteSpace); 1.1927 + } 1.1928 + if (*tmpPtr == 0) { 1.1929 + fprintf(stderr, "Warning: missing VM alias on line %d of `%s'\n", 1.1930 + lineno, jvmCfgName); 1.1931 + } else { 1.1932 + /* Null terminate altVMName */ 1.1933 + altVMName = tmpPtr; 1.1934 + tmpPtr += strcspn(tmpPtr, whiteSpace); 1.1935 + *tmpPtr = 0; 1.1936 + vmType = VM_ALIASED_TO; 1.1937 + } 1.1938 + } else if (!strncmp(tmpPtr, "WARN", strlen("WARN"))) { 1.1939 + vmType = VM_WARN; 1.1940 + } else if (!strncmp(tmpPtr, "IGNORE", strlen("IGNORE"))) { 1.1941 + vmType = VM_IGNORE; 1.1942 + } else if (!strncmp(tmpPtr, "ERROR", strlen("ERROR"))) { 1.1943 + vmType = VM_ERROR; 1.1944 + } else if (!strncmp(tmpPtr, 1.1945 + "IF_SERVER_CLASS", 1.1946 + strlen("IF_SERVER_CLASS"))) { 1.1947 + tmpPtr += strcspn(tmpPtr, whiteSpace); 1.1948 + if (*tmpPtr != 0) { 1.1949 + tmpPtr += strspn(tmpPtr, whiteSpace); 1.1950 + } 1.1951 + if (*tmpPtr == 0) { 1.1952 + fprintf(stderr, "Warning: missing server class VM on line %d of `%s'\n", 1.1953 + lineno, jvmCfgName); 1.1954 + } else { 1.1955 + /* Null terminate server class VM name */ 1.1956 + serverClassVMName = tmpPtr; 1.1957 + tmpPtr += strcspn(tmpPtr, whiteSpace); 1.1958 + *tmpPtr = 0; 1.1959 + vmType = VM_IF_SERVER_CLASS; 1.1960 + } 1.1961 + } else { 1.1962 + fprintf(stderr, "Warning: unknown VM type on line %d of `%s'\n", 1.1963 + lineno, &jvmCfgName[0]); 1.1964 + vmType = VM_KNOWN; 1.1965 + } 1.1966 + } 1.1967 + } 1.1968 + 1.1969 + if (_launcher_debug) 1.1970 + printf("jvm.cfg[%d] = ->%s<-\n", cnt, line); 1.1971 + if (vmType != VM_UNKNOWN) { 1.1972 + knownVMs[cnt].name = JLI_StringDup(line); 1.1973 + knownVMs[cnt].flag = vmType; 1.1974 + switch (vmType) { 1.1975 + default: 1.1976 + break; 1.1977 + case VM_ALIASED_TO: 1.1978 + knownVMs[cnt].alias = JLI_StringDup(altVMName); 1.1979 + if (_launcher_debug) { 1.1980 + printf(" name: %s vmType: %s alias: %s\n", 1.1981 + knownVMs[cnt].name, "VM_ALIASED_TO", knownVMs[cnt].alias); 1.1982 + } 1.1983 + break; 1.1984 + case VM_IF_SERVER_CLASS: 1.1985 + knownVMs[cnt].server_class = JLI_StringDup(serverClassVMName); 1.1986 + if (_launcher_debug) { 1.1987 + printf(" name: %s vmType: %s server_class: %s\n", 1.1988 + knownVMs[cnt].name, "VM_IF_SERVER_CLASS", knownVMs[cnt].server_class); 1.1989 + } 1.1990 + break; 1.1991 + } 1.1992 + cnt++; 1.1993 + } 1.1994 + } 1.1995 + fclose(jvmCfg); 1.1996 + knownVMsCount = cnt; 1.1997 + 1.1998 + if (_launcher_debug) { 1.1999 + end = CounterGet(); 1.2000 + printf("%ld micro seconds to parse jvm.cfg\n", 1.2001 + (long)(jint)Counter2Micros(end-start)); 1.2002 + } 1.2003 + 1.2004 + return cnt; 1.2005 +} 1.2006 + 1.2007 + 1.2008 +static void 1.2009 +GrowKnownVMs(int minimum) 1.2010 +{ 1.2011 + struct vmdesc* newKnownVMs; 1.2012 + int newMax; 1.2013 + 1.2014 + newMax = (knownVMsLimit == 0 ? INIT_MAX_KNOWN_VMS : (2 * knownVMsLimit)); 1.2015 + if (newMax <= minimum) { 1.2016 + newMax = minimum; 1.2017 + } 1.2018 + newKnownVMs = (struct vmdesc*) JLI_MemAlloc(newMax * sizeof(struct vmdesc)); 1.2019 + if (knownVMs != NULL) { 1.2020 + memcpy(newKnownVMs, knownVMs, knownVMsLimit * sizeof(struct vmdesc)); 1.2021 + } 1.2022 + JLI_MemFree(knownVMs); 1.2023 + knownVMs = newKnownVMs; 1.2024 + knownVMsLimit = newMax; 1.2025 +} 1.2026 + 1.2027 + 1.2028 +/* Returns index of VM or -1 if not found */ 1.2029 +static int 1.2030 +KnownVMIndex(const char* name) 1.2031 +{ 1.2032 + int i; 1.2033 + if (strncmp(name, "-J", 2) == 0) name += 2; 1.2034 + for (i = 0; i < knownVMsCount; i++) { 1.2035 + if (!strcmp(name, knownVMs[i].name)) { 1.2036 + return i; 1.2037 + } 1.2038 + } 1.2039 + return -1; 1.2040 +} 1.2041 + 1.2042 +static void 1.2043 +FreeKnownVMs() 1.2044 +{ 1.2045 + int i; 1.2046 + for (i = 0; i < knownVMsCount; i++) { 1.2047 + JLI_MemFree(knownVMs[i].name); 1.2048 + knownVMs[i].name = NULL; 1.2049 + } 1.2050 + JLI_MemFree(knownVMs); 1.2051 +} 1.2052 + 1.2053 + 1.2054 +/* 1.2055 + * Displays the splash screen according to the jar file name 1.2056 + * and image file names stored in environment variables 1.2057 + */ 1.2058 +static void 1.2059 +ShowSplashScreen() 1.2060 +{ 1.2061 + const char *jar_name = getenv(SPLASH_JAR_ENV_ENTRY); 1.2062 + const char *file_name = getenv(SPLASH_FILE_ENV_ENTRY); 1.2063 + int data_size; 1.2064 + void *image_data; 1.2065 + if (jar_name) { 1.2066 + image_data = JLI_JarUnpackFile(jar_name, file_name, &data_size); 1.2067 + if (image_data) { 1.2068 + DoSplashInit(); 1.2069 + DoSplashLoadMemory(image_data, data_size); 1.2070 + JLI_MemFree(image_data); 1.2071 + } 1.2072 + } else if (file_name) { 1.2073 + DoSplashInit(); 1.2074 + DoSplashLoadFile(file_name); 1.2075 + } else { 1.2076 + return; 1.2077 + } 1.2078 + DoSplashSetFileJarName(file_name, jar_name); 1.2079 +} 1.2080 + 1.2081 +#endif /* ifndef GAMMA */