src/share/bin/java.c
author ohair
Fri Jan 30 17:20:38 2009 -0800 (3 years ago)
changeset 82 586feec8273d
parent 34cb639980ca20
child 354ffa98eed5766
permissions -rw-r--r--
6775264: Changes for openjdk6 build 14
6592792: Add com.sun.xml.internal to the "package.access" property in $JAVA_HOME/lib/security/java.security
6484091: FileSystemView leaks directory info
6766136: corrupted gif image may cause crash in java splashscreen library.
6755943: Java JAR Pack200 Decompression should enforce stricter header checks
6751322: Vulnerability report: Sun Java JRE TrueType Font Parsing Heap Overflow
4486841: UTF8 decoder should adhere to corrigendum to Unicode 3.0.1
6721753: File.createTempFile produces guessable file names
6734167: Calendar.readObject allows elevation of privileges
6733336: Crash on malformed font
6726779: ConvolveOp on USHORT raster can cause the JVM crash.
6588160: jaas krb5 client leaks OS-level UDP sockets (all platforms) 6733959 Insufficient checks for "Main-Class" manifest entry in JAR files
6497740: Limit the size of RSA public keys
6775851: Fix README-builds.html to document the use of Solaris 8
Summary: Final b14 state (as defined by the source bundle)
Reviewed-by: darcy
        1 /*
        2  * Copyright 1995-2008 Sun Microsystems, Inc.  All Rights Reserved.
        3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        4  *
        5  * This code is free software; you can redistribute it and/or modify it
        6  * under the terms of the GNU General Public License version 2 only, as
        7  * published by the Free Software Foundation.  Sun designates this
        8  * particular file as subject to the "Classpath" exception as provided
        9  * by Sun in the LICENSE file that accompanied this code.
       10  *
       11  * This code is distributed in the hope that it will be useful, but WITHOUT
       12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       14  * version 2 for more details (a copy is included in the LICENSE file that
       15  * accompanied this code).
       16  *
       17  * You should have received a copy of the GNU General Public License version
       18  * 2 along with this work; if not, write to the Free Software Foundation,
       19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       20  *
       21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       22  * CA 95054 USA or visit www.sun.com if you need additional information or
       23  * have any questions.
       24  */
       25 
       26 /*
       27  * Shared source for 'java' command line tool.
       28  *
       29  * If JAVA_ARGS is defined, then acts as a launcher for applications. For
       30  * instance, the JDK command line tools such as javac and javadoc (see
       31  * makefiles for more details) are built with this program.  Any arguments
       32  * prefixed with '-J' will be passed directly to the 'java' command.
       33  */
       34 
       35 /*
       36  * One job of the launcher is to remove command line options which the
       37  * vm does not understand and will not process.  These options include
       38  * options which select which style of vm is run (e.g. -client and
       39  * -server) as well as options which select the data model to use.
       40  * Additionally, for tools which invoke an underlying vm "-J-foo"
       41  * options are turned into "-foo" options to the vm.  This option
       42  * filtering is handled in a number of places in the launcher, some of
       43  * it in machine-dependent code.  In this file, the function
       44  * CheckJVMType removes vm style options and TranslateApplicationArgs
       45  * removes "-J" prefixes.  On unix platforms, the
       46  * CreateExecutionEnvironment function from the unix java_md.c file
       47  * processes and removes -d<n> options.  However, in case
       48  * CreateExecutionEnvironment does not need to exec because
       49  * LD_LIBRARY_PATH is set acceptably and the data model does not need
       50  * to be changed, ParseArguments will screen out the redundant -d<n>
       51  * options and prevent them from being passed to the vm; this is done
       52  * by using the machine-dependent call
       53  * RemovableMachineDependentOption.
       54  */
       55 
       56 #include <stdio.h>
       57 #include <stdlib.h>
       58 #include <string.h>
       59 
       60 #include <jni.h>
       61 #include <jvm.h>
       62 #include "java.h"
       63 #include "manifest_info.h"
       64 #include "version_comp.h"
       65 #include "wildcard.h"
       66 #include "splashscreen.h"
       67 
       68 #ifndef FULL_VERSION
       69 #define FULL_VERSION JDK_MAJOR_VERSION "." JDK_MINOR_VERSION
       70 #endif
       71 
       72 /*
       73  * The following environment variable is used to influence the behavior
       74  * of the jre exec'd through the SelectVersion routine.  The command line
       75  * options which specify the version are not passed to the exec'd version,
       76  * because that jre may be an older version which wouldn't recognize them.
       77  * This environment variable is known to this (and later) version and serves
       78  * to suppress the version selection code.  This is not only for efficiency,
       79  * but also for correctness, since any command line options have been
       80  * removed which would cause any value found in the manifest to be used.
       81  * This would be incorrect because the command line options are defined
       82  * to take precedence.
       83  *
       84  * The value associated with this environment variable is the MainClass
       85  * name from within the executable jar file (if any). This is strictly a
       86  * performance enhancement to avoid re-reading the jar file manifest.
       87  *
       88  * A NOTE TO DEVELOPERS: For performance reasons it is important that
       89  * the program image remain relatively small until after SelectVersion
       90  * CreateExecutionEnvironment have finished their possibly recursive
       91  * processing. Watch everything, but resist all temptations to use Java
       92  * interfaces.
       93  */
       94 #define ENV_ENTRY "_JAVA_VERSION_SET"
       95 
       96 #define SPLASH_FILE_ENV_ENTRY "_JAVA_SPLASH_FILE"
       97 #define SPLASH_JAR_ENV_ENTRY "_JAVA_SPLASH_JAR"
       98 
       99 static jboolean printVersion = JNI_FALSE; /* print and exit */
      100 static jboolean showVersion = JNI_FALSE;  /* print but continue */
      101 static jboolean printUsage = JNI_FALSE;   /* print and exit*/
      102 static jboolean printXUsage = JNI_FALSE;  /* print and exit*/
      103 static char *progname;
      104 static char *launchername;
      105 jboolean _launcher_debug = JNI_FALSE;
      106 
      107 /*
      108  * Entries for splash screen environment variables.
      109  * putenv is performed in SelectVersion. We need
      110  * them in memory until UnsetEnv, so they are made static
      111  * global instead of auto local.
      112  */
      113 static char* splash_file_entry = NULL;
      114 static char* splash_jar_entry = NULL;
      115 
      116 /*
      117  * List of VM options to be specified when the VM is created.
      118  */
      119 static JavaVMOption *options;
      120 static int numOptions, maxOptions;
      121 
      122 /*
      123  * Prototypes for functions internal to launcher.
      124  */
      125 static void SetClassPath(const char *s);
      126 static void SelectVersion(int argc, char **argv, char **main_class);
      127 static jboolean ParseArguments(int *pargc, char ***pargv, char **pjarfile,
      128                                char **pclassname, int *pret, const char *jvmpath);
      129 static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv,
      130                               InvocationFunctions *ifn);
      131 static jstring NewPlatformString(JNIEnv *env, char *s);
      132 static jobjectArray NewPlatformStringArray(JNIEnv *env, char **strv, int strc);
      133 static jclass LoadClass(JNIEnv *env, char *name);
      134 static jstring GetMainClassName(JNIEnv *env, char *jarname);
      135 static void SetJavaCommandLineProp(char* classname, char* jarfile, int argc, char** argv);
      136 static void SetJavaLauncherProp(void);
      137 
      138 #ifdef JAVA_ARGS
      139 static void TranslateApplicationArgs(int *pargc, char ***pargv);
      140 static jboolean AddApplicationOptions(void);
      141 #endif
      142 
      143 static void PrintJavaVersion(JNIEnv *env);
      144 static void PrintUsage(JNIEnv* env, jboolean doXUsage);
      145 
      146 static void SetPaths(int argc, char **argv);
      147 
      148 
      149 /* Maximum supported entries from jvm.cfg. */
      150 #define INIT_MAX_KNOWN_VMS      10
      151 /* Values for vmdesc.flag */
      152 #define VM_UNKNOWN              -1
      153 #define VM_KNOWN                 0
      154 #define VM_ALIASED_TO            1
      155 #define VM_WARN                  2
      156 #define VM_ERROR                 3
      157 #define VM_IF_SERVER_CLASS       4
      158 #define VM_IGNORE                5
      159 struct vmdesc {
      160     char *name;
      161     int flag;
      162     char *alias;
      163     char *server_class;
      164 };
      165 static struct vmdesc *knownVMs = NULL;
      166 static int knownVMsCount = 0;
      167 static int knownVMsLimit = 0;
      168 
      169 static void GrowKnownVMs();
      170 static int  KnownVMIndex(const char* name);
      171 static void FreeKnownVMs();
      172 static void ShowSplashScreen();
      173 
      174 jboolean ServerClassMachine();
      175 
      176 /* flag which if set suppresses error messages from the launcher */
      177 static int noExitErrorMessage = 0;
      178 
      179 /*
      180  * Running Java code in primordial thread caused many problems. We will
      181  * create a new thread to invoke JVM. See 6316197 for more information.
      182  */
      183 static jlong threadStackSize = 0;  /* stack size of the new thread */
      184 
      185 int JNICALL JavaMain(void * args); /* entry point                  */
      186 
      187 struct JavaMainArgs {
      188   int     argc;
      189   char ** argv;
      190   char *  jarfile;
      191   char *  classname;
      192   InvocationFunctions ifn;
      193 };
      194 
      195 /*
      196  * Entry point.
      197  */
      198 int
      199 main(int argc, char ** argv)
      200 {
      201     char *jarfile = 0;
      202     char *classname = 0;
      203     char *s = 0;
      204     char *main_class = NULL;
      205     int ret;
      206     InvocationFunctions ifn;
      207     jlong start, end;
      208     char jrepath[MAXPATHLEN], jvmpath[MAXPATHLEN];
      209     char ** original_argv = argv;
      210 
      211     if (getenv("_JAVA_LAUNCHER_DEBUG") != 0) {
      212       int i;
      213       _launcher_debug = JNI_TRUE;
      214       printf("----_JAVA_LAUNCHER_DEBUG----\n");
      215       printf("Command line Args:\n");
      216       for(i = 0; i < argc+1; i++) {
      217         if (argv[i] != NULL){
      218           printf("\targv[%d] = '%s'\n",i,argv[i]);
      219         }
      220       }
      221     }
      222 
      223 
      224 
      225     /*
      226      * Make sure the specified version of the JRE is running.
      227      *
      228      * There are three things to note about the SelectVersion() routine:
      229      *  1) If the version running isn't correct, this routine doesn't
      230      *     return (either the correct version has been exec'd or an error
      231      *     was issued).
      232      *  2) Argc and Argv in this scope are *not* altered by this routine.
      233      *     It is the responsibility of subsequent code to ignore the
      234      *     arguments handled by this routine.
      235      *  3) As a side-effect, the variable "main_class" is guaranteed to
      236      *     be set (if it should ever be set).  This isn't exactly the
      237      *     poster child for structured programming, but it is a small
      238      *     price to pay for not processing a jar file operand twice.
      239      *     (Note: This side effect has been disabled.  See comment on
      240      *     bugid 5030265 below.)
      241      */
      242     SelectVersion(argc, argv, &main_class);
      243 
      244     /* copy original argv */
      245     {
      246       int i;
      247       original_argv = (char**)JLI_MemAlloc(sizeof(char*)*(argc+1));
      248       for(i = 0; i < argc+1; i++) {
      249         original_argv[i] = argv[i];
      250       }
      251     }
      252 
      253     CreateExecutionEnvironment(&argc, &argv,
      254                                jrepath, sizeof(jrepath),
      255                                jvmpath, sizeof(jvmpath),
      256                                original_argv);
      257 
      258     ifn.CreateJavaVM = 0;
      259     ifn.GetDefaultJavaVMInitArgs = 0;
      260 
      261     if (_launcher_debug)
      262       start = CounterGet();
      263     if (!LoadJavaVM(jvmpath, &ifn)) {
      264       exit(6);
      265     }
      266     if (_launcher_debug) {
      267       end   = CounterGet();
      268       printf("%ld micro seconds to LoadJavaVM\n",
      269              (long)(jint)Counter2Micros(end-start));
      270     }
      271 
      272 #ifdef JAVA_ARGS  /* javac, jar and friends. */
      273     progname = "java";
      274 #else             /* java, oldjava, javaw and friends */
      275 #ifdef PROGNAME
      276     progname = PROGNAME;
      277 #else
      278     progname = *argv;
      279     if ((s = strrchr(progname, FILE_SEPARATOR)) != 0) {
      280         progname = s + 1;
      281     }
      282 #endif /* PROGNAME */
      283 #endif /* JAVA_ARGS */
      284 
      285 #ifdef LAUNCHER_NAME
      286     launchername = LAUNCHER_NAME;
      287 #else
      288     launchername = progname;
      289 #endif /* LAUNCHER_NAME */
      290 
      291     ++argv;
      292     --argc;
      293 
      294 #ifdef JAVA_ARGS
      295     /* Preprocess wrapper arguments */
      296     TranslateApplicationArgs(&argc, &argv);
      297     if (!AddApplicationOptions()) {
      298         exit(1);
      299     }
      300 #endif
      301 
      302     /* Set default CLASSPATH */
      303     if ((s = getenv("CLASSPATH")) == 0) {
      304         s = ".";
      305     }
      306 #ifndef JAVA_ARGS
      307     SetClassPath(s);
      308 #endif
      309 
      310     /*
      311      *  Parse command line options; if the return value of
      312      *  ParseArguments is false, the program should exit.
      313      */
      314     if (!ParseArguments(&argc, &argv, &jarfile, &classname, &ret, jvmpath)) {
      315       exit(ret);
      316     }
      317 
      318     /* Override class path if -jar flag was specified */
      319     if (jarfile != 0) {
      320         SetClassPath(jarfile);
      321     }
      322 
      323     /* set the -Dsun.java.command pseudo property */
      324     SetJavaCommandLineProp(classname, jarfile, argc, argv);
      325 
      326     /* Set the -Dsun.java.launcher pseudo property */
      327     SetJavaLauncherProp();
      328 
      329     /* set the -Dsun.java.launcher.* platform properties */
      330     SetJavaLauncherPlatformProps();
      331 
      332     /* Show the splash screen if needed */
      333     ShowSplashScreen();
      334 
      335     /*
      336      * Done with all command line processing and potential re-execs so
      337      * clean up the environment.
      338      */
      339     (void)UnsetEnv(ENV_ENTRY);
      340     (void)UnsetEnv(SPLASH_FILE_ENV_ENTRY);
      341     (void)UnsetEnv(SPLASH_JAR_ENV_ENTRY);
      342 
      343     JLI_MemFree(splash_jar_entry);
      344     JLI_MemFree(splash_file_entry);
      345 
      346     /*
      347      * If user doesn't specify stack size, check if VM has a preference.
      348      * Note that HotSpot no longer supports JNI_VERSION_1_1 but it will
      349      * return its default stack size through the init args structure.
      350      */
      351     if (threadStackSize == 0) {
      352       struct JDK1_1InitArgs args1_1;
      353       memset((void*)&args1_1, 0, sizeof(args1_1));
      354       args1_1.version = JNI_VERSION_1_1;
      355       ifn.GetDefaultJavaVMInitArgs(&args1_1);  /* ignore return value */
      356       if (args1_1.javaStackSize > 0) {
      357          threadStackSize = args1_1.javaStackSize;
      358       }
      359     }
      360 
      361     { /* Create a new thread to create JVM and invoke main method */
      362       struct JavaMainArgs args;
      363 
      364       args.argc = argc;
      365       args.argv = argv;
      366       args.jarfile = jarfile;
      367       args.classname = classname;
      368       args.ifn = ifn;
      369 
      370       return ContinueInNewThread(JavaMain, threadStackSize, (void*)&args, ret);
      371     }
      372 }
      373 
      374 int JNICALL
      375 JavaMain(void * _args)
      376 {
      377     struct JavaMainArgs *args = (struct JavaMainArgs *)_args;
      378     int argc = args->argc;
      379     char **argv = args->argv;
      380     char *jarfile = args->jarfile;
      381     char *classname = args->classname;
      382     InvocationFunctions ifn = args->ifn;
      383 
      384     JavaVM *vm = 0;
      385     JNIEnv *env = 0;
      386     jstring mainClassName;
      387     jclass mainClass;
      388     jmethodID mainID;
      389     jobjectArray mainArgs;
      390     int ret = 0;
      391     jlong start, end;
      392 
      393     /*
      394      * Error message to print or display; by default the message will
      395      * only be displayed in a window.
      396      */
      397     char * message = "Fatal exception occurred.  Program will exit.";
      398     jboolean messageDest = JNI_FALSE;
      399 
      400     /* Initialize the virtual machine */
      401 
      402     if (_launcher_debug)
      403         start = CounterGet();
      404     if (!InitializeJVM(&vm, &env, &ifn)) {
      405         ReportErrorMessage("Could not create the Java virtual machine.",
      406                            JNI_TRUE);
      407         exit(1);
      408     }
      409 
      410     if (printVersion || showVersion) {
      411         PrintJavaVersion(env);
      412         if ((*env)->ExceptionOccurred(env)) {
      413             ReportExceptionDescription(env);
      414             goto leave;
      415         }
      416         if (printVersion) {
      417             ret = 0;
      418             message = NULL;
      419             goto leave;
      420         }
      421         if (showVersion) {
      422             fprintf(stderr, "\n");
      423         }
      424     }
      425 
      426     /* If the user specified neither a class name nor a JAR file */
      427     if (printXUsage || printUsage || (jarfile == 0 && classname == 0)) {
      428         PrintUsage(env, printXUsage);
      429         if ((*env)->ExceptionOccurred(env)) {
      430             ReportExceptionDescription(env);
      431             ret=1;
      432         }
      433         message = NULL;
      434         goto leave;
      435     }
      436 
      437 
      438 
      439     FreeKnownVMs();  /* after last possible PrintUsage() */
      440 
      441     if (_launcher_debug) {
      442         end   = CounterGet();
      443         printf("%ld micro seconds to InitializeJVM\n",
      444                (long)(jint)Counter2Micros(end-start));
      445     }
      446 
      447     /* At this stage, argc/argv have the applications' arguments */
      448     if (_launcher_debug) {
      449         int i = 0;
      450         printf("Main-Class is '%s'\n", classname ? classname : "");
      451         printf("Apps' argc is %d\n", argc);
      452         for (; i < argc; i++) {
      453             printf("    argv[%2d] = '%s'\n", i, argv[i]);
      454         }
      455     }
      456 
      457     ret = 1;
      458 
      459     /*
      460      * Get the application's main class.
      461      *
      462      * See bugid 5030265.  The Main-Class name has already been parsed
      463      * from the manifest, but not parsed properly for UTF-8 support.
      464      * Hence the code here ignores the value previously extracted and
      465      * uses the pre-existing code to reextract the value.  This is
      466      * possibly an end of release cycle expedient.  However, it has
      467      * also been discovered that passing some character sets through
      468      * the environment has "strange" behavior on some variants of
      469      * Windows.  Hence, maybe the manifest parsing code local to the
      470      * launcher should never be enhanced.
      471      *
      472      * Hence, future work should either:
      473      *     1)   Correct the local parsing code and verify that the
      474      *          Main-Class attribute gets properly passed through
      475      *          all environments,
      476      *     2)   Remove the vestages of maintaining main_class through
      477      *          the environment (and remove these comments).
      478      */
      479     if (jarfile != 0) {
      480         mainClassName = GetMainClassName(env, jarfile);
      481         if ((*env)->ExceptionOccurred(env)) {
      482             ReportExceptionDescription(env);
      483             goto leave;
      484         }
      485         if (mainClassName == NULL) {
      486           const char * format = "Failed to load Main-Class manifest "
      487                                 "attribute from\n%s";
      488           message = (char*)JLI_MemAlloc((strlen(format) + strlen(jarfile)) *
      489                                     sizeof(char));
      490           sprintf(message, format, jarfile);
      491           messageDest = JNI_TRUE;
      492           goto leave;
      493         }
      494         classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0);
      495         if (classname == NULL) {
      496             ReportExceptionDescription(env);
      497             goto leave;
      498         }
      499         mainClass = LoadClass(env, classname);
      500         if(mainClass == NULL) { /* exception occured */
      501             const char * format = "Could not find the main class: %s. Program will exit.";
      502             ReportExceptionDescription(env);
      503             message = (char *)JLI_MemAlloc((strlen(format) +
      504 					   strlen(classname)) * sizeof(char));
      505             messageDest = JNI_TRUE;
      506 	    sprintf(message, format, classname);
      507             goto leave;
      508         }
      509         (*env)->ReleaseStringUTFChars(env, mainClassName, classname);
      510     } else {
      511       mainClassName = NewPlatformString(env, classname);
      512       if (mainClassName == NULL) {
      513         const char * format = "Failed to load Main Class: %s";
      514         message = (char *)JLI_MemAlloc((strlen(format) + strlen(classname)) *
      515                                    sizeof(char) );
      516         sprintf(message, format, classname);
      517         messageDest = JNI_TRUE;
      518         goto leave;
      519       }
      520       classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0);
      521       if (classname == NULL) {
      522         ReportExceptionDescription(env);
      523         goto leave;
      524       }
      525       mainClass = LoadClass(env, classname);
      526       if(mainClass == NULL) { /* exception occured */
      527         const char * format = "Could not find the main class: %s. Program will exit.";
      528         ReportExceptionDescription(env);
      529         message = (char *)JLI_MemAlloc((strlen(format) +
      530                                           strlen(classname)) * sizeof(char));
      531         messageDest = JNI_TRUE;
      532         sprintf(message, format, classname);
      533         goto leave;
      534       }
      535       (*env)->ReleaseStringUTFChars(env, mainClassName, classname);
      536     }
      537 
      538     /* Get the application's main method */
      539     mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
      540                                        "([Ljava/lang/String;)V");
      541     if (mainID == NULL) {
      542         if ((*env)->ExceptionOccurred(env)) {
      543             ReportExceptionDescription(env);
      544         } else {
      545           message = "No main method found in specified class.";
      546           messageDest = JNI_TRUE;
      547         }
      548         goto leave;
      549     }
      550 
      551     {    /* Make sure the main method is public */
      552         jint mods;
      553         jmethodID mid;
      554         jobject obj = (*env)->ToReflectedMethod(env, mainClass,
      555                                                 mainID, JNI_TRUE);
      556 
      557         if( obj == NULL) { /* exception occurred */
      558             ReportExceptionDescription(env);
      559             goto leave;
      560         }
      561 
      562         mid =
      563           (*env)->GetMethodID(env,
      564                               (*env)->GetObjectClass(env, obj),
      565                               "getModifiers", "()I");
      566         if ((*env)->ExceptionOccurred(env)) {
      567             ReportExceptionDescription(env);
      568             goto leave;
      569         }
      570 
      571         mods = (*env)->CallIntMethod(env, obj, mid);
      572         if ((mods & 1) == 0) { /* if (!Modifier.isPublic(mods)) ... */
      573             message = "Main method not public.";
      574             messageDest = JNI_TRUE;
      575             goto leave;
      576         }
      577     }
      578 
      579     /* Build argument array */
      580     mainArgs = NewPlatformStringArray(env, argv, argc);
      581     if (mainArgs == NULL) {
      582         ReportExceptionDescription(env);
      583         goto leave;
      584     }
      585 
      586     /* Invoke main method. */
      587     (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
      588 
      589     /*
      590      * The launcher's exit code (in the absence of calls to
      591      * System.exit) will be non-zero if main threw an exception.
      592      */
      593     ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1;
      594 
      595     /*
      596      * Detach the main thread so that it appears to have ended when
      597      * the application's main method exits.  This will invoke the
      598      * uncaught exception handler machinery if main threw an
      599      * exception.  An uncaught exception handler cannot change the
      600      * launcher's return code except by calling System.exit.
      601      */
      602     if ((*vm)->DetachCurrentThread(vm) != 0) {
      603         message = "Could not detach main thread.";
      604         messageDest = JNI_TRUE;
      605         ret = 1;
      606         goto leave;
      607     }
      608 
      609     message = NULL;
      610 
      611  leave:
      612     /*
      613      * Wait for all non-daemon threads to end, then destroy the VM.
      614      * This will actually create a trivial new Java waiter thread
      615      * named "DestroyJavaVM", but this will be seen as a different
      616      * thread from the one that executed main, even though they are
      617      * the same C thread.  This allows mainThread.join() and
      618      * mainThread.isAlive() to work as expected.
      619      */
      620     (*vm)->DestroyJavaVM(vm);
      621 
      622     if(message != NULL && !noExitErrorMessage)
      623       ReportErrorMessage(message, messageDest);
      624     return ret;
      625 }
      626 
      627 
      628 /*
      629  * Checks the command line options to find which JVM type was
      630  * specified.  If no command line option was given for the JVM type,
      631  * the default type is used.  The environment variable
      632  * JDK_ALTERNATE_VM and the command line option -XXaltjvm= are also
      633  * checked as ways of specifying which JVM type to invoke.
      634  */
      635 char *
      636 CheckJvmType(int *pargc, char ***argv, jboolean speculative) {
      637     int i, argi;
      638     int argc;
      639     char **newArgv;
      640     int newArgvIdx = 0;
      641     int isVMType;
      642     int jvmidx = -1;
      643     char *jvmtype = getenv("JDK_ALTERNATE_VM");
      644 
      645     argc = *pargc;
      646 
      647     /* To make things simpler we always copy the argv array */
      648     newArgv = JLI_MemAlloc((argc + 1) * sizeof(char *));
      649 
      650     /* The program name is always present */
      651     newArgv[newArgvIdx++] = (*argv)[0];
      652 
      653     for (argi = 1; argi < argc; argi++) {
      654         char *arg = (*argv)[argi];
      655         isVMType = 0;
      656 
      657 #ifdef JAVA_ARGS
      658         if (arg[0] != '-') {
      659             newArgv[newArgvIdx++] = arg;
      660             continue;
      661         }
      662 #else
      663         if (strcmp(arg, "-classpath") == 0 ||
      664             strcmp(arg, "-cp") == 0) {
      665             newArgv[newArgvIdx++] = arg;
      666             argi++;
      667             if (argi < argc) {
      668                 newArgv[newArgvIdx++] = (*argv)[argi];
      669             }
      670             continue;
      671         }
      672         if (arg[0] != '-') break;
      673 #endif
      674 
      675         /* Did the user pass an explicit VM type? */
      676         i = KnownVMIndex(arg);
      677         if (i >= 0) {
      678             jvmtype = knownVMs[jvmidx = i].name + 1; /* skip the - */
      679             isVMType = 1;
      680             *pargc = *pargc - 1;
      681         }
      682 
      683         /* Did the user specify an "alternate" VM? */
      684         else if (strncmp(arg, "-XXaltjvm=", 10) == 0 || strncmp(arg, "-J-XXaltjvm=", 12) == 0) {
      685             isVMType = 1;
      686             jvmtype = arg+((arg[1]=='X')? 10 : 12);
      687             jvmidx = -1;
      688         }
      689 
      690         if (!isVMType) {
      691             newArgv[newArgvIdx++] = arg;
      692         }
      693     }
      694 
      695     /*
      696      * Finish copying the arguments if we aborted the above loop.
      697      * NOTE that if we aborted via "break" then we did NOT copy the
      698      * last argument above, and in addition argi will be less than
      699      * argc.
      700      */
      701     while (argi < argc) {
      702         newArgv[newArgvIdx++] = (*argv)[argi];
      703         argi++;
      704     }
      705 
      706     /* argv is null-terminated */
      707     newArgv[newArgvIdx] = 0;
      708 
      709     /* Copy back argv */
      710     *argv = newArgv;
      711     *pargc = newArgvIdx;
      712 
      713     /* use the default VM type if not specified (no alias processing) */
      714     if (jvmtype == NULL) {
      715       char* result = knownVMs[0].name+1;
      716       /* Use a different VM type if we are on a server class machine? */
      717       if ((knownVMs[0].flag == VM_IF_SERVER_CLASS) &&
      718           (ServerClassMachine() == JNI_TRUE)) {
      719         result = knownVMs[0].server_class+1;
      720       }
      721       if (_launcher_debug) {
      722         printf("Default VM: %s\n", result);
      723       }
      724       return result;
      725     }
      726 
      727     /* if using an alternate VM, no alias processing */
      728     if (jvmidx < 0)
      729       return jvmtype;
      730 
      731     /* Resolve aliases first */
      732     {
      733       int loopCount = 0;
      734       while (knownVMs[jvmidx].flag == VM_ALIASED_TO) {
      735         int nextIdx = KnownVMIndex(knownVMs[jvmidx].alias);
      736 
      737         if (loopCount > knownVMsCount) {
      738           if (!speculative) {
      739             ReportErrorMessage("Error: Corrupt jvm.cfg file; cycle in alias list.",
      740                                JNI_TRUE);
      741             exit(1);
      742           } else {
      743             return "ERROR";
      744             /* break; */
      745           }
      746         }
      747 
      748         if (nextIdx < 0) {
      749           if (!speculative) {
      750             ReportErrorMessage2("Error: Unable to resolve VM alias %s",
      751                                 knownVMs[jvmidx].alias, JNI_TRUE);
      752             exit(1);
      753           } else {
      754             return "ERROR";
      755           }
      756         }
      757         jvmidx = nextIdx;
      758         jvmtype = knownVMs[jvmidx].name+1;
      759         loopCount++;
      760       }
      761     }
      762 
      763     switch (knownVMs[jvmidx].flag) {
      764     case VM_WARN:
      765         if (!speculative) {
      766             fprintf(stderr, "Warning: %s VM not supported; %s VM will be used\n",
      767                     jvmtype, knownVMs[0].name + 1);
      768         }
      769         /* fall through */
      770     case VM_IGNORE:
      771         jvmtype = knownVMs[jvmidx=0].name + 1;
      772         /* fall through */
      773     case VM_KNOWN:
      774         break;
      775     case VM_ERROR:
      776         if (!speculative) {
      777             ReportErrorMessage2("Error: %s VM not supported", jvmtype, JNI_TRUE);
      778             exit(1);
      779         } else {
      780             return "ERROR";
      781         }
      782     }
      783 
      784     return jvmtype;
      785 }
      786 
      787 # define KB (1024UL)
      788 # define MB (1024UL * KB)
      789 # define GB (1024UL * MB)
      790 
      791 /* copied from HotSpot function "atomll()" */
      792 static int
      793 parse_stack_size(const char *s, jlong *result) {
      794   jlong n = 0;
      795   int args_read = sscanf(s, jlong_format_specifier(), &n);
      796   if (args_read != 1) {
      797     return 0;
      798   }
      799   while (*s != '\0' && *s >= '0' && *s <= '9') {
      800     s++;
      801   }
      802   // 4705540: illegal if more characters are found after the first non-digit
      803   if (strlen(s) > 1) {
      804     return 0;
      805   }
      806   switch (*s) {
      807     case 'T': case 't':
      808       *result = n * GB * KB;
      809       return 1;
      810     case 'G': case 'g':
      811       *result = n * GB;
      812       return 1;
      813     case 'M': case 'm':
      814       *result = n * MB;
      815       return 1;
      816     case 'K': case 'k':
      817       *result = n * KB;
      818       return 1;
      819     case '\0':
      820       *result = n;
      821       return 1;
      822     default:
      823       /* Create JVM with default stack and let VM handle malformed -Xss string*/
      824       return 0;
      825   }
      826 }
      827 
      828 /*
      829  * Adds a new VM option with the given given name and value.
      830  */
      831 void
      832 AddOption(char *str, void *info)
      833 {
      834     /*
      835      * Expand options array if needed to accommodate at least one more
      836      * VM option.
      837      */
      838     if (numOptions >= maxOptions) {
      839         if (options == 0) {
      840             maxOptions = 4;
      841             options = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption));
      842         } else {
      843             JavaVMOption *tmp;
      844             maxOptions *= 2;
      845             tmp = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption));
      846             memcpy(tmp, options, numOptions * sizeof(JavaVMOption));
      847             JLI_MemFree(options);
      848             options = tmp;
      849         }
      850     }
      851     options[numOptions].optionString = str;
      852     options[numOptions++].extraInfo = info;
      853 
      854     if (strncmp(str, "-Xss", 4) == 0) {
      855       jlong tmp;
      856       if (parse_stack_size(str + 4, &tmp)) {
      857         threadStackSize = tmp;
      858       }
      859     }
      860 }
      861 
      862 static void
      863 SetClassPath(const char *s)
      864 {
      865     char *def;
      866     s = JLI_WildcardExpandClasspath(s);
      867     def = JLI_MemAlloc(strlen(s) + 40);
      868     sprintf(def, "-Djava.class.path=%s", s);
      869     AddOption(def, NULL);
      870 }
      871 
      872 /*
      873  * The SelectVersion() routine ensures that an appropriate version of
      874  * the JRE is running.  The specification for the appropriate version
      875  * is obtained from either the manifest of a jar file (preferred) or
      876  * from command line options.
      877  * The routine also parses splash screen command line options and
      878  * passes on their values in private environment variables.
      879  */
      880 static void
      881 SelectVersion(int argc, char **argv, char **main_class)
      882 {
      883     char    *arg;
      884     char    **new_argv;
      885     char    **new_argp;
      886     char    *operand;
      887     char    *version = NULL;
      888     char    *jre = NULL;
      889     int     jarflag = 0;
      890     int     headlessflag = 0;
      891     int     restrict_search = -1;               /* -1 implies not known */
      892     manifest_info info;
      893     char    env_entry[MAXNAMELEN + 24] = ENV_ENTRY "=";
      894     char    *splash_file_name = NULL;
      895     char    *splash_jar_name = NULL;
      896     char    *env_in;
      897     int     res;
      898 
      899     /*
      900      * If the version has already been selected, set *main_class
      901      * with the value passed through the environment (if any) and
      902      * simply return.
      903      */
      904     if ((env_in = getenv(ENV_ENTRY)) != NULL) {
      905         if (*env_in != '\0')
      906             *main_class = JLI_StringDup(env_in);
      907         return;
      908     }
      909 
      910     /*
      911      * Scan through the arguments for options relevant to multiple JRE
      912      * support.  For reference, the command line syntax is defined as:
      913      *
      914      * SYNOPSIS
      915      *      java [options] class [argument...]
      916      *
      917      *      java [options] -jar file.jar [argument...]
      918      *
      919      * As the scan is performed, make a copy of the argument list with
      920      * the version specification options (new to 1.5) removed, so that
      921      * a version less than 1.5 can be exec'd.
      922      *
      923      * Note that due to the syntax of the native Windows interface
      924      * CreateProcess(), processing similar to the following exists in
      925      * the Windows platform specific routine ExecJRE (in java_md.c).
      926      * Changes here should be reproduced there.
      927      */
      928     new_argv = JLI_MemAlloc((argc + 1) * sizeof(char*));
      929     new_argv[0] = argv[0];
      930     new_argp = &new_argv[1];
      931     argc--;
      932     argv++;
      933     while ((arg = *argv) != 0 && *arg == '-') {
      934         if (strncmp(arg, "-version:", 9) == 0) {
      935             version = arg + 9;
      936         } else if (strcmp(arg, "-jre-restrict-search") == 0) {
      937             restrict_search = 1;
      938         } else if (strcmp(arg, "-no-jre-restrict-search") == 0) {
      939             restrict_search = 0;
      940         } else {
      941             if (strcmp(arg, "-jar") == 0)
      942                 jarflag = 1;
      943             /* deal with "unfortunate" classpath syntax */
      944             if ((strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) &&
      945               (argc >= 2)) {
      946                 *new_argp++ = arg;
      947                 argc--;
      948                 argv++;
      949                 arg = *argv;
      950             }
      951 
      952             /*
      953              * Checking for headless toolkit option in the some way as AWT does:
      954              * "true" means true and any other value means false
      955              */
      956             if (strcmp(arg, "-Djava.awt.headless=true") == 0) {
      957                 headlessflag = 1;
      958             } else if (strncmp(arg, "-Djava.awt.headless=", 20) == 0) {
      959                 headlessflag = 0;
      960             } else if (strncmp(arg, "-splash:", 8) == 0) {
      961                 splash_file_name = arg+8;
      962             }
      963             *new_argp++ = arg;
      964         }
      965         argc--;
      966         argv++;
      967     }
      968     if (argc <= 0) {    /* No operand? Possibly legit with -[full]version */
      969         operand = NULL;
      970     } else {
      971         argc--;
      972         *new_argp++ = operand = *argv++;
      973     }
      974     while (argc-- > 0)  /* Copy over [argument...] */
      975         *new_argp++ = *argv++;
      976     *new_argp = NULL;
      977 
      978     /*
      979      * If there is a jar file, read the manifest. If the jarfile can't be
      980      * read, the manifest can't be read from the jar file, or the manifest
      981      * is corrupt, issue the appropriate error messages and exit.
      982      *
      983      * Even if there isn't a jar file, construct a manifest_info structure
      984      * containing the command line information.  It's a convenient way to carry
      985      * this data around.
      986      */
      987     if (jarflag && operand) {
      988         if ((res = JLI_ParseManifest(operand, &info)) != 0) {
      989             if (res == -1)
      990                 ReportErrorMessage2("Unable to access jarfile %s",
      991                   operand, JNI_TRUE);
      992             else
      993                 ReportErrorMessage2("Invalid or corrupt jarfile %s",
      994                   operand, JNI_TRUE);
      995             exit(1);
      996         }
      997 
      998         /*
      999          * Command line splash screen option should have precedence
     1000          * over the manifest, so the manifest data is used only if
     1001          * splash_file_name has not been initialized above during command
     1002          * line parsing
     1003          */
     1004         if (!headlessflag && !splash_file_name && info.splashscreen_image_file_name) {
     1005             splash_file_name = info.splashscreen_image_file_name;
     1006             splash_jar_name = operand;
     1007         }
     1008     } else {
     1009         info.manifest_version = NULL;
     1010         info.main_class = NULL;
     1011         info.jre_version = NULL;
     1012         info.jre_restrict_search = 0;
     1013     }
     1014 
     1015     /*
     1016      * Passing on splash screen info in environment variables
     1017      */
     1018     if (splash_file_name && !headlessflag) {
     1019         char* splash_file_entry = JLI_MemAlloc(strlen(SPLASH_FILE_ENV_ENTRY "=")+strlen(splash_file_name)+1);
     1020         strcpy(splash_file_entry, SPLASH_FILE_ENV_ENTRY "=");
     1021         strcat(splash_file_entry, splash_file_name);
     1022         putenv(splash_file_entry);
     1023     }
     1024     if (splash_jar_name && !headlessflag) {
     1025         char* splash_jar_entry = JLI_MemAlloc(strlen(SPLASH_JAR_ENV_ENTRY "=")+strlen(splash_jar_name)+1);
     1026         strcpy(splash_jar_entry, SPLASH_JAR_ENV_ENTRY "=");
     1027         strcat(splash_jar_entry, splash_jar_name);
     1028         putenv(splash_jar_entry);
     1029     }
     1030 
     1031     /*
     1032      * The JRE-Version and JRE-Restrict-Search values (if any) from the
     1033      * manifest are overwritten by any specified on the command line.
     1034      */
     1035     if (version != NULL)
     1036         info.jre_version = version;
     1037     if (restrict_search != -1)
     1038         info.jre_restrict_search = restrict_search;
     1039 
     1040     /*
     1041      * "Valid" returns (other than unrecoverable errors) follow.  Set
     1042      * main_class as a side-effect of this routine.
     1043      */
     1044     if (info.main_class != NULL)
     1045         *main_class = JLI_StringDup(info.main_class);
     1046 
     1047     /*
     1048      * If no version selection information is found either on the command
     1049      * line or in the manifest, simply return.
     1050      */
     1051     if (info.jre_version == NULL) {
     1052         JLI_FreeManifest();
     1053         JLI_MemFree(new_argv);
     1054         return;
     1055     }
     1056 
     1057     /*
     1058      * Check for correct syntax of the version specification (JSR 56).
     1059      */
     1060     if (!JLI_ValidVersionString(info.jre_version)) {
     1061         ReportErrorMessage2("Syntax error in version specification \"%s\"",
     1062           info.jre_version, JNI_TRUE);
     1063         exit(1);
     1064     }
     1065 
     1066     /*
     1067      * Find the appropriate JVM on the system. Just to be as forgiving as
     1068      * possible, if the standard algorithms don't locate an appropriate
     1069      * jre, check to see if the one running will satisfy the requirements.
     1070      * This can happen on systems which haven't been set-up for multiple
     1071      * JRE support.
     1072      */
     1073     jre = LocateJRE(&info);
     1074     if (_launcher_debug)
     1075         printf("JRE-Version = %s, JRE-Restrict-Search = %s Selected = %s\n",
     1076           (info.jre_version?info.jre_version:"null"),
     1077           (info.jre_restrict_search?"true":"false"), (jre?jre:"null"));
     1078     if (jre == NULL) {
     1079         if (JLI_AcceptableRelease(FULL_VERSION, info.jre_version)) {
     1080             JLI_FreeManifest();
     1081             JLI_MemFree(new_argv);
     1082             return;
     1083         } else {
     1084             ReportErrorMessage2(
     1085               "Unable to locate JRE meeting specification \"%s\"",
     1086               info.jre_version, JNI_TRUE);
     1087             exit(1);
     1088         }
     1089     }
     1090 
     1091     /*
     1092      * If I'm not the chosen one, exec the chosen one.  Returning from
     1093      * ExecJRE indicates that I am indeed the chosen one.
     1094      *
     1095      * The private environment variable _JAVA_VERSION_SET is used to
     1096      * prevent the chosen one from re-reading the manifest file and
     1097      * using the values found within to override the (potential) command
     1098      * line flags stripped from argv (because the target may not
     1099      * understand them).  Passing the MainClass value is an optimization
     1100      * to avoid locating, expanding and parsing the manifest extra
     1101      * times.
     1102      */
     1103     if (info.main_class != NULL) {
     1104         if (strlen(info.main_class) <= MAXNAMELEN) {
     1105             (void)strcat(env_entry, info.main_class);
     1106         } else {
     1107             ReportErrorMessage("Error: main-class: attribute exceeds system limits\n", JNI_TRUE);
     1108 	    exit(1);
     1109         }
     1110     }
     1111     (void)putenv(env_entry);
     1112     ExecJRE(jre, new_argv);
     1113     JLI_FreeManifest();
     1114     JLI_MemFree(new_argv);
     1115     return;
     1116 }
     1117 
     1118 /*
     1119  * Parses command line arguments.  Returns JNI_FALSE if launcher
     1120  * should exit without starting vm, returns JNI_TRUE if vm needs
     1121  * to be started to process  given options. *pret (the launcher
     1122  * process return value) is set to 0 for a normal exit.
     1123  */
     1124 static jboolean
     1125 ParseArguments(int *pargc, char ***pargv, char **pjarfile,
     1126                        char **pclassname, int *pret, const char *jvmpath)
     1127 {
     1128     int argc = *pargc;
     1129     char **argv = *pargv;
     1130     jboolean jarflag = JNI_FALSE;
     1131     char *arg;
     1132 
     1133     *pret = 0;
     1134 
     1135     while ((arg = *argv) != 0 && *arg == '-') {
     1136         argv++; --argc;
     1137         if (strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) {
     1138             if (argc < 1) {
     1139                 ReportErrorMessage2("%s requires class path specification",
     1140                                     arg, JNI_TRUE);
     1141                 printUsage = JNI_TRUE;
     1142                 *pret = 1;
     1143                 return JNI_TRUE;
     1144             }
     1145             SetClassPath(*argv);
     1146             argv++; --argc;
     1147         } else if (strcmp(arg, "-jar") == 0) {
     1148             jarflag = JNI_TRUE;
     1149         } else if (strcmp(arg, "-help") == 0 ||
     1150                    strcmp(arg, "-h") == 0 ||
     1151                    strcmp(arg, "-?") == 0) {
     1152             printUsage = JNI_TRUE;
     1153             return JNI_TRUE;
     1154         } else if (strcmp(arg, "-version") == 0) {
     1155             printVersion = JNI_TRUE;
     1156             return JNI_TRUE;
     1157         } else if (strcmp(arg, "-showversion") == 0) {
     1158             showVersion = JNI_TRUE;
     1159         } else if (strcmp(arg, "-X") == 0) {
     1160             printXUsage = JNI_TRUE;
     1161             return JNI_TRUE;
     1162 /*
     1163  * The following case provide backward compatibility with old-style
     1164  * command line options.
     1165  */
     1166         } else if (strcmp(arg, "-fullversion") == 0) {
     1167             fprintf(stderr, "%s full version \"%s\"\n", launchername,
     1168                     FULL_VERSION);
     1169             return JNI_FALSE;
     1170         } else if (strcmp(arg, "-verbosegc") == 0) {
     1171             AddOption("-verbose:gc", NULL);
     1172         } else if (strcmp(arg, "-t") == 0) {
     1173             AddOption("-Xt", NULL);
     1174         } else if (strcmp(arg, "-tm") == 0) {
     1175             AddOption("-Xtm", NULL);
     1176         } else if (strcmp(arg, "-debug") == 0) {
     1177             AddOption("-Xdebug", NULL);
     1178         } else if (strcmp(arg, "-noclassgc") == 0) {
     1179             AddOption("-Xnoclassgc", NULL);
     1180         } else if (strcmp(arg, "-Xfuture") == 0) {
     1181             AddOption("-Xverify:all", NULL);
     1182         } else if (strcmp(arg, "-verify") == 0) {
     1183             AddOption("-Xverify:all", NULL);
     1184         } else if (strcmp(arg, "-verifyremote") == 0) {
     1185             AddOption("-Xverify:remote", NULL);
     1186         } else if (strcmp(arg, "-noverify") == 0) {
     1187             AddOption("-Xverify:none", NULL);
     1188         } else if (strcmp(arg, "-XXsuppressExitMessage") == 0) {
     1189             noExitErrorMessage = 1;
     1190         } else if (strncmp(arg, "-prof", 5) == 0) {
     1191             char *p = arg + 5;
     1192             char *tmp = JLI_MemAlloc(strlen(arg) + 50);
     1193             if (*p) {
     1194                 sprintf(tmp, "-Xrunhprof:cpu=old,file=%s", p + 1);
     1195             } else {
     1196                 sprintf(tmp, "-Xrunhprof:cpu=old,file=java.prof");
     1197             }
     1198             AddOption(tmp, NULL);
     1199         } else if (strncmp(arg, "-ss", 3) == 0 ||
     1200                    strncmp(arg, "-oss", 4) == 0 ||
     1201                    strncmp(arg, "-ms", 3) == 0 ||
     1202                    strncmp(arg, "-mx", 3) == 0) {
     1203             char *tmp = JLI_MemAlloc(strlen(arg) + 6);
     1204             sprintf(tmp, "-X%s", arg + 1); /* skip '-' */
     1205             AddOption(tmp, NULL);
     1206         } else if (strcmp(arg, "-checksource") == 0 ||
     1207                    strcmp(arg, "-cs") == 0 ||
     1208                    strcmp(arg, "-noasyncgc") == 0) {
     1209             /* No longer supported */
     1210             fprintf(stderr,
     1211                     "Warning: %s option is no longer supported.\n",
     1212                     arg);
     1213         } else if (strncmp(arg, "-version:", 9) == 0 ||
     1214                    strcmp(arg, "-no-jre-restrict-search") == 0 ||
     1215                    strcmp(arg, "-jre-restrict-search") == 0 ||
     1216                    strncmp(arg, "-splash:", 8) == 0) {
     1217             ; /* Ignore machine independent options already handled */
     1218         } else if (RemovableMachineDependentOption(arg) ) {
     1219             ; /* Do not pass option to vm. */
     1220         }
     1221         else {
     1222             AddOption(arg, NULL);
     1223         }
     1224     }
     1225 
     1226     if (--argc >= 0) {
     1227         if (jarflag) {
     1228             *pjarfile = *argv++;
     1229             *pclassname = 0;
     1230         } else {
     1231             *pjarfile = 0;
     1232             *pclassname = *argv++;
     1233         }
     1234         *pargc = argc;
     1235         *pargv = argv;
     1236     }
     1237 
     1238     return JNI_TRUE;
     1239 }
     1240 
     1241 /*
     1242  * Initializes the Java Virtual Machine. Also frees options array when
     1243  * finished.
     1244  */
     1245 static jboolean
     1246 InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn)
     1247 {
     1248     JavaVMInitArgs args;
     1249     jint r;
     1250 
     1251     memset(&args, 0, sizeof(args));
     1252     args.version  = JNI_VERSION_1_2;
     1253     args.nOptions = numOptions;
     1254     args.options  = options;
     1255     args.ignoreUnrecognized = JNI_FALSE;
     1256 
     1257     if (_launcher_debug) {
     1258         int i = 0;
     1259         printf("JavaVM args:\n    ");
     1260         printf("version 0x%08lx, ", (long)args.version);
     1261         printf("ignoreUnrecognized is %s, ",
     1262                args.ignoreUnrecognized ? "JNI_TRUE" : "JNI_FALSE");
     1263         printf("nOptions is %ld\n", (long)args.nOptions);
     1264         for (i = 0; i < numOptions; i++)
     1265             printf("    option[%2d] = '%s'\n",
     1266                    i, args.options[i].optionString);
     1267     }
     1268 
     1269     r = ifn->CreateJavaVM(pvm, (void **)penv, &args);
     1270     JLI_MemFree(options);
     1271     return r == JNI_OK;
     1272 }
     1273 
     1274 #define JNI_ERROR "Error: A JNI error has occurred, please check your installation and try again"
     1275 
     1276 #define NULL_CHECK0(e) if ((e) == 0) { \
     1277     ReportErrorMessage(JNI_ERROR, JNI_TRUE); \
     1278     return 0; \
     1279   }
     1280 
     1281 #define NULL_CHECK(e) if ((e) == 0) { \
     1282     ReportErrorMessage(JNI_ERROR, JNI_TRUE); \
     1283     return; \
     1284   }
     1285 
     1286 static jstring platformEncoding = NULL;
     1287 static jstring getPlatformEncoding(JNIEnv *env) {
     1288     if (platformEncoding == NULL) {
     1289         jstring propname = (*env)->NewStringUTF(env, "sun.jnu.encoding");
     1290         if (propname) {
     1291             jclass cls;
     1292             jmethodID mid;
     1293             NULL_CHECK0 (cls = (*env)->FindClass(env, "java/lang/System"));
     1294             NULL_CHECK0 (mid = (*env)->GetStaticMethodID(
     1295                                    env, cls,
     1296                                    "getProperty",
     1297                                    "(Ljava/lang/String;)Ljava/lang/String;"));
     1298             platformEncoding = (*env)->CallStaticObjectMethod (
     1299                                     env, cls, mid, propname);
     1300         }
     1301     }
     1302     return platformEncoding;
     1303 }
     1304 
     1305 static jboolean isEncodingSupported(JNIEnv *env, jstring enc) {
     1306     jclass cls;
     1307     jmethodID mid;
     1308     NULL_CHECK0 (cls = (*env)->FindClass(env, "java/nio/charset/Charset"));
     1309     NULL_CHECK0 (mid = (*env)->GetStaticMethodID(
     1310                            env, cls,
     1311                            "isSupported",
     1312                            "(Ljava/lang/String;)Z"));
     1313     return (*env)->CallStaticBooleanMethod(env, cls, mid, enc);
     1314 }
     1315 
     1316 /*
     1317  * Returns a new Java string object for the specified platform string.
     1318  */
     1319 static jstring
     1320 NewPlatformString(JNIEnv *env, char *s)
     1321 {
     1322     int len = (int)strlen(s);
     1323     jclass cls;
     1324     jmethodID mid;
     1325     jbyteArray ary;
     1326     jstring enc;
     1327 
     1328     if (s == NULL)
     1329         return 0;
     1330     enc = getPlatformEncoding(env);
     1331 
     1332     ary = (*env)->NewByteArray(env, len);
     1333     if (ary != 0) {
     1334         jstring str = 0;
     1335         (*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s);
     1336         if (!(*env)->ExceptionOccurred(env)) {
     1337             if (isEncodingSupported(env, enc) == JNI_TRUE) {
     1338                 NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String"));
     1339                 NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>",
     1340                                           "([BLjava/lang/String;)V"));
     1341                 str = (*env)->NewObject(env, cls, mid, ary, enc);
     1342             } else {
     1343                 /*If the encoding specified in sun.jnu.encoding is not
     1344                   endorsed by "Charset.isSupported" we have to fall back
     1345                   to use String(byte[]) explicitly here without specifying
     1346                   the encoding name, in which the StringCoding class will
     1347                   pickup the iso-8859-1 as the fallback converter for us.
     1348                 */
     1349                 NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String"));
     1350                 NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>",
     1351                                           "([B)V"));
     1352                 str = (*env)->NewObject(env, cls, mid, ary);
     1353             }
     1354             (*env)->DeleteLocalRef(env, ary);
     1355             return str;
     1356         }
     1357     }
     1358     return 0;
     1359 }
     1360 
     1361 /*
     1362  * Returns a new array of Java string objects for the specified
     1363  * array of platform strings.
     1364  */
     1365 static jobjectArray
     1366 NewPlatformStringArray(JNIEnv *env, char **strv, int strc)
     1367 {
     1368     jarray cls;
     1369     jarray ary;
     1370     int i;
     1371 
     1372     NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String"));
     1373     NULL_CHECK0(ary = (*env)->NewObjectArray(env, strc, cls, 0));
     1374     for (i = 0; i < strc; i++) {
     1375         jstring str = NewPlatformString(env, *strv++);
     1376         NULL_CHECK0(str);
     1377         (*env)->SetObjectArrayElement(env, ary, i, str);
     1378         (*env)->DeleteLocalRef(env, str);
     1379     }
     1380     return ary;
     1381 }
     1382 
     1383 /*
     1384  * Loads a class, convert the '.' to '/'.
     1385  */
     1386 static jclass
     1387 LoadClass(JNIEnv *env, char *name)
     1388 {
     1389     char *buf = JLI_MemAlloc(strlen(name) + 1);
     1390     char *s = buf, *t = name, c;
     1391     jclass cls;
     1392     jlong start, end;
     1393 
     1394     if (_launcher_debug)
     1395         start = CounterGet();
     1396 
     1397     do {
     1398         c = *t++;
     1399         *s++ = (c == '.') ? '/' : c;
     1400     } while (c != '\0');
     1401     cls = (*env)->FindClass(env, buf);
     1402     JLI_MemFree(buf);
     1403 
     1404     if (_launcher_debug) {
     1405         end   = CounterGet();
     1406         printf("%ld micro seconds to load main class\n",
     1407                (long)(jint)Counter2Micros(end-start));
     1408         printf("----_JAVA_LAUNCHER_DEBUG----\n");
     1409     }
     1410 
     1411     return cls;
     1412 }
     1413 
     1414 
     1415 /*
     1416  * Returns the main class name for the specified jar file.
     1417  */
     1418 static jstring
     1419 GetMainClassName(JNIEnv *env, char *jarname)
     1420 {
     1421 #define MAIN_CLASS "Main-Class"
     1422     jclass cls;
     1423     jmethodID mid;
     1424     jobject jar, man, attr;
     1425     jstring str, result = 0;
     1426 
     1427     NULL_CHECK0(cls = (*env)->FindClass(env, "java/util/jar/JarFile"));
     1428     NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>",
     1429                                           "(Ljava/lang/String;)V"));
     1430     NULL_CHECK0(str = NewPlatformString(env, jarname));
     1431     NULL_CHECK0(jar = (*env)->NewObject(env, cls, mid, str));
     1432     NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "getManifest",
     1433                                           "()Ljava/util/jar/Manifest;"));
     1434     man = (*env)->CallObjectMethod(env, jar, mid);
     1435     if (man != 0) {
     1436         NULL_CHECK0(mid = (*env)->GetMethodID(env,
     1437                                     (*env)->GetObjectClass(env, man),
     1438                                     "getMainAttributes",
     1439                                     "()Ljava/util/jar/Attributes;"));
     1440         attr = (*env)->CallObjectMethod(env, man, mid);
     1441         if (attr != 0) {
     1442             NULL_CHECK0(mid = (*env)->GetMethodID(env,
     1443                                     (*env)->GetObjectClass(env, attr),
     1444                                     "getValue",
     1445                                     "(Ljava/lang/String;)Ljava/lang/String;"));
     1446             NULL_CHECK0(str = NewPlatformString(env, MAIN_CLASS));
     1447             result = (*env)->CallObjectMethod(env, attr, mid, str);
     1448         }
     1449     }
     1450     return result;
     1451 }
     1452 
     1453 #ifdef JAVA_ARGS
     1454 static char *java_args[] = JAVA_ARGS;
     1455 static char *app_classpath[] = APP_CLASSPATH;
     1456 
     1457 /*
     1458  * For tools, convert command line args thus:
     1459  *   javac -cp foo:foo/"*" -J-ms32m ...
     1460  *   java -ms32m -cp JLI_WildcardExpandClasspath(foo:foo/"*") ...
     1461  */
     1462 static void
     1463 TranslateApplicationArgs(int *pargc, char ***pargv)
     1464 {
     1465     const int NUM_ARGS = (sizeof(java_args) / sizeof(char *));
     1466     int argc = *pargc;
     1467     char **argv = *pargv;
     1468     int nargc = argc + NUM_ARGS;
     1469     char **nargv = JLI_MemAlloc((nargc + 1) * sizeof(char *));
     1470     int i;
     1471 
     1472     *pargc = nargc;
     1473     *pargv = nargv;
     1474 
     1475     /* Copy the VM arguments (i.e. prefixed with -J) */
     1476     for (i = 0; i < NUM_ARGS; i++) {
     1477         char *arg = java_args[i];
     1478         if (arg[0] == '-' && arg[1] == 'J') {
     1479             *nargv++ = arg + 2;
     1480         }
     1481     }
     1482 
     1483     for (i = 0; i < argc; i++) {
     1484         char *arg = argv[i];
     1485         if (arg[0] == '-' && arg[1] == 'J') {
     1486             if (arg[2] == '\0') {
     1487                 ReportErrorMessage("Error: the -J option should not be "
     1488                                    "followed by a space.", JNI_TRUE);
     1489                 exit(1);
     1490             }
     1491             *nargv++ = arg + 2;
     1492         }
     1493     }
     1494 
     1495     /* Copy the rest of the arguments */
     1496     for (i = 0; i < NUM_ARGS; i++) {
     1497         char *arg = java_args[i];
     1498         if (arg[0] != '-' || arg[1] != 'J') {
     1499             *nargv++ = arg;
     1500         }
     1501     }
     1502     for (i = 0; i < argc; i++) {
     1503         char *arg = argv[i];
     1504         if (arg[0] == '-') {
     1505             if (arg[1] == 'J')
     1506                 continue;
     1507 #ifdef EXPAND_CLASSPATH_WILDCARDS
     1508             if (arg[1] == 'c'
     1509                 && (strcmp(arg, "-cp") == 0 ||
     1510                     strcmp(arg, "-classpath") == 0)
     1511                 && i < argc - 1) {
     1512                 *nargv++ = arg;
     1513                 *nargv++ = (char *) JLI_WildcardExpandClasspath(argv[i+1]);
     1514                 i++;
     1515                 continue;
     1516             }
     1517 #endif
     1518         }
     1519         *nargv++ = arg;
     1520     }
     1521     *nargv = 0;
     1522 }
     1523 
     1524 /*
     1525  * For our tools, we try to add 3 VM options:
     1526  *      -Denv.class.path=<envcp>
     1527  *      -Dapplication.home=<apphome>
     1528  *      -Djava.class.path=<appcp>
     1529  * <envcp>   is the user's setting of CLASSPATH -- for instance the user
     1530  *           tells javac where to find binary classes through this environment
     1531  *           variable.  Notice that users will be able to compile against our
     1532  *           tools classes (sun.tools.javac.Main) only if they explicitly add
     1533  *           tools.jar to CLASSPATH.
     1534  * <apphome> is the directory where the application is installed.
     1535  * <appcp>   is the classpath to where our apps' classfiles are.
     1536  */
     1537 static jboolean
     1538 AddApplicationOptions()
     1539 {
     1540     const int NUM_APP_CLASSPATH = (sizeof(app_classpath) / sizeof(char *));
     1541     char *envcp, *appcp, *apphome;
     1542     char home[MAXPATHLEN]; /* application home */
     1543     char separator[] = { PATH_SEPARATOR, '\0' };
     1544     int size, i;
     1545     int strlenHome;
     1546 
     1547     {
     1548         const char *s = getenv("CLASSPATH");
     1549         if (s) {
     1550             s = (char *) JLI_WildcardExpandClasspath(s);
     1551             /* 40 for -Denv.class.path= */
     1552             envcp = (char *)JLI_MemAlloc(strlen(s) + 40);
     1553             sprintf(envcp, "-Denv.class.path=%s", s);
     1554             AddOption(envcp, NULL);
     1555         }
     1556     }
     1557 
     1558     if (!GetApplicationHome(home, sizeof(home))) {
     1559         ReportErrorMessage("Can't determine application home", JNI_TRUE);
     1560         return JNI_FALSE;
     1561     }
     1562 
     1563     /* 40 for '-Dapplication.home=' */
     1564     apphome = (char *)JLI_MemAlloc(strlen(home) + 40);
     1565     sprintf(apphome, "-Dapplication.home=%s", home);
     1566     AddOption(apphome, NULL);
     1567 
     1568     /* How big is the application's classpath? */
     1569     size = 40;                                 /* 40: "-Djava.class.path=" */
     1570     strlenHome = (int)strlen(home);
     1571     for (i = 0; i < NUM_APP_CLASSPATH; i++) {
     1572         size += strlenHome + (int)strlen(app_classpath[i]) + 1; /* 1: separator */
     1573     }
     1574     appcp = (char *)JLI_MemAlloc(size + 1);
     1575     strcpy(appcp, "-Djava.class.path=");
     1576     for (i = 0; i < NUM_APP_CLASSPATH; i++) {
     1577         strcat(appcp, home);                    /* c:\program files\myapp */
     1578         strcat(appcp, app_classpath[i]);        /* \lib\myapp.jar         */
     1579         strcat(appcp, separator);               /* ;                      */
     1580     }
     1581     appcp[strlen(appcp)-1] = '\0';  /* remove trailing path separator */
     1582     AddOption(appcp, NULL);
     1583     return JNI_TRUE;
     1584 }
     1585 #endif /* JAVA_ARGS */
     1586 
     1587 /*
     1588  * inject the -Dsun.java.command pseudo property into the args structure
     1589  * this pseudo property is used in the HotSpot VM to expose the
     1590  * Java class name and arguments to the main method to the VM. The
     1591  * HotSpot VM uses this pseudo property to store the Java class name
     1592  * (or jar file name) and the arguments to the class's main method
     1593  * to the instrumentation memory region. The sun.java.command pseudo
     1594  * property is not exported by HotSpot to the Java layer.
     1595  */
     1596 void
     1597 SetJavaCommandLineProp(char *classname, char *jarfile,
     1598                        int argc, char **argv)
     1599 {
     1600 
     1601     int i = 0;
     1602     size_t len = 0;
     1603     char* javaCommand = NULL;
     1604     char* dashDstr = "-Dsun.java.command=";
     1605 
     1606     if (classname == NULL && jarfile == NULL) {
     1607         /* unexpected, one of these should be set. just return without
     1608          * setting the property
     1609          */
     1610         return;
     1611     }
     1612 
     1613     /* if the class name is not set, then use the jarfile name */
     1614     if (classname == NULL) {
     1615         classname = jarfile;
     1616     }
     1617 
     1618     /* determine the amount of memory to allocate assuming
     1619      * the individual components will be space separated
     1620      */
     1621     len = strlen(classname);
     1622     for (i = 0; i < argc; i++) {
     1623         len += strlen(argv[i]) + 1;
     1624     }
     1625 
     1626     /* allocate the memory */
     1627     javaCommand = (char*) JLI_MemAlloc(len + strlen(dashDstr) + 1);
     1628 
     1629     /* build the -D string */
     1630     *javaCommand = '\0';
     1631     strcat(javaCommand, dashDstr);
     1632     strcat(javaCommand, classname);
     1633 
     1634     for (i = 0; i < argc; i++) {
     1635         /* the components of the string are space separated. In
     1636          * the case of embedded white space, the relationship of
     1637          * the white space separated components to their true
     1638          * positional arguments will be ambiguous. This issue may
     1639          * be addressed in a future release.
     1640          */
     1641         strcat(javaCommand, " ");
     1642         strcat(javaCommand, argv[i]);
     1643     }
     1644 
     1645     AddOption(javaCommand, NULL);
     1646 }
     1647 
     1648 /*
     1649  * JVM would like to know if it's created by a standard Sun launcher, or by
     1650  * user native application, the following property indicates the former.
     1651  */
     1652 void SetJavaLauncherProp() {
     1653   AddOption("-Dsun.java.launcher=SUN_STANDARD", NULL);
     1654 }
     1655 
     1656 /*
     1657  * Prints the version information from the java.version and other properties.
     1658  */
     1659 static void
     1660 PrintJavaVersion(JNIEnv *env)
     1661 {
     1662     jclass ver;
     1663     jmethodID print;
     1664 
     1665     NULL_CHECK(ver = (*env)->FindClass(env, "sun/misc/Version"));
     1666     NULL_CHECK(print = (*env)->GetStaticMethodID(env, ver, "print", "()V"));
     1667 
     1668     (*env)->CallStaticVoidMethod(env, ver, print);
     1669 }
     1670 
     1671 /*
     1672  * Prints default usage or the Xusage message, see sun.launcher.LauncherHelp.java
     1673  */
     1674 static void
     1675 PrintUsage(JNIEnv* env, jboolean doXUsage)
     1676 {
     1677   jclass cls;
     1678   jmethodID initHelp, vmSelect, vmSynonym, vmErgo, printHelp, printXUsageMessage;
     1679   jstring jprogname, vm1, vm2;
     1680   int i;
     1681 
     1682   NULL_CHECK(cls = (*env)->FindClass(env, "sun/launcher/LauncherHelp"));
     1683 
     1684 
     1685   if (doXUsage) {
     1686     NULL_CHECK(printXUsageMessage = (*env)->GetStaticMethodID(env, cls,
     1687                                         "printXUsageMessage", "(Z)V"));
     1688     (*env)->CallStaticVoidMethod(env, cls, printXUsageMessage, JNI_TRUE);
     1689   } else {
     1690     NULL_CHECK(initHelp = (*env)->GetStaticMethodID(env, cls,
     1691                                         "initHelpMessage", "(Ljava/lang/String;)V"));
     1692 
     1693     NULL_CHECK(vmSelect = (*env)->GetStaticMethodID(env, cls, "appendVmSelectMessage",
     1694                                         "(Ljava/lang/String;Ljava/lang/String;)V"));
     1695 
     1696     NULL_CHECK(vmSynonym = (*env)->GetStaticMethodID(env, cls,
     1697                                         "appendVmSynonymMessage",
     1698                                         "(Ljava/lang/String;Ljava/lang/String;)V"));
     1699     NULL_CHECK(vmErgo = (*env)->GetStaticMethodID(env, cls,
     1700                                         "appendVmErgoMessage", "(ZLjava/lang/String;)V"));
     1701 
     1702     NULL_CHECK(printHelp = (*env)->GetStaticMethodID(env, cls,
     1703                                         "printHelpMessage", "(Z)V"));
     1704 
     1705     jprogname = (*env)->NewStringUTF(env, progname);
     1706 
     1707     /* Initialize the usage message with the usual preamble */
     1708     (*env)->CallStaticVoidMethod(env, cls, initHelp, jprogname);
     1709 
     1710 
     1711     /* Assemble the other variant part of the usage */
     1712     if ((knownVMs[0].flag == VM_KNOWN) ||
     1713         (knownVMs[0].flag == VM_IF_SERVER_CLASS)) {
     1714       vm1 = (*env)->NewStringUTF(env, knownVMs[0].name);
     1715       vm2 =  (*env)->NewStringUTF(env, knownVMs[0].name+1);
     1716       (*env)->CallStaticVoidMethod(env, cls, vmSelect, vm1, vm2);
     1717     }
     1718     for (i=1; i<knownVMsCount; i++) {
     1719       if (knownVMs[i].flag == VM_KNOWN) {
     1720         vm1 =  (*env)->NewStringUTF(env, knownVMs[i].name);
     1721         vm2 =  (*env)->NewStringUTF(env, knownVMs[i].name+1);
     1722         (*env)->CallStaticVoidMethod(env, cls, vmSelect, vm1, vm2);
     1723       }
     1724     }
     1725     for (i=1; i<knownVMsCount; i++) {
     1726       if (knownVMs[i].flag == VM_ALIASED_TO) {
     1727         vm1 =  (*env)->NewStringUTF(env, knownVMs[i].name);
     1728         vm2 =  (*env)->NewStringUTF(env, knownVMs[i].alias+1);
     1729         (*env)->CallStaticVoidMethod(env, cls, vmSynonym, vm1, vm2);
     1730       }
     1731     }
     1732 
     1733     /* The first known VM is the default */
     1734     {
     1735       jboolean isServerClassMachine = ServerClassMachine();
     1736 
     1737       const char* defaultVM  =  knownVMs[0].name+1;
     1738       if ((knownVMs[0].flag == VM_IF_SERVER_CLASS) && isServerClassMachine) {
     1739         defaultVM = knownVMs[0].server_class+1;
     1740       }
     1741 
     1742       vm1 =  (*env)->NewStringUTF(env, defaultVM);
     1743       (*env)->CallStaticVoidMethod(env, cls, vmErgo, isServerClassMachine,  vm1);
     1744     }
     1745 
     1746     /* Complete the usage message and print to stderr*/
     1747     (*env)->CallStaticVoidMethod(env, cls, printHelp, JNI_TRUE);
     1748   }
     1749   return;
     1750 }
     1751 
     1752 /*
     1753  * Read the jvm.cfg file and fill the knownJVMs[] array.
     1754  *
     1755  * The functionality of the jvm.cfg file is subject to change without
     1756  * notice and the mechanism will be removed in the future.
     1757  *
     1758  * The lexical structure of the jvm.cfg file is as follows:
     1759  *
     1760  *     jvmcfg         :=  { vmLine }
     1761  *     vmLine         :=  knownLine
     1762  *                    |   aliasLine
     1763  *                    |   warnLine
     1764  *                    |   ignoreLine
     1765  *                    |   errorLine
     1766  *                    |   predicateLine
     1767  *                    |   commentLine
     1768  *     knownLine      :=  flag  "KNOWN"                  EOL
     1769  *     warnLine       :=  flag  "WARN"                   EOL
     1770  *     ignoreLine     :=  flag  "IGNORE"                 EOL
     1771  *     errorLine      :=  flag  "ERROR"                  EOL
     1772  *     aliasLine      :=  flag  "ALIASED_TO"       flag  EOL
     1773  *     predicateLine  :=  flag  "IF_SERVER_CLASS"  flag  EOL
     1774  *     commentLine    :=  "#" text                       EOL
     1775  *     flag           :=  "-" identifier
     1776  *
     1777  * The semantics are that when someone specifies a flag on the command line:
     1778  * - if the flag appears on a knownLine, then the identifier is used as
     1779  *   the name of the directory holding the JVM library (the name of the JVM).
     1780  * - if the flag appears as the first flag on an aliasLine, the identifier
     1781  *   of the second flag is used as the name of the JVM.
     1782  * - if the flag appears on a warnLine, the identifier is used as the
     1783  *   name of the JVM, but a warning is generated.
     1784  * - if the flag appears on an ignoreLine, the identifier is recognized as the
     1785  *   name of a JVM, but the identifier is ignored and the default vm used
     1786  * - if the flag appears on an errorLine, an error is generated.
     1787  * - if the flag appears as the first flag on a predicateLine, and
     1788  *   the machine on which you are running passes the predicate indicated,
     1789  *   then the identifier of the second flag is used as the name of the JVM,
     1790  *   otherwise the identifier of the first flag is used as the name of the JVM.
     1791  * If no flag is given on the command line, the first vmLine of the jvm.cfg
     1792  * file determines the name of the JVM.
     1793  * PredicateLines are only interpreted on first vmLine of a jvm.cfg file,
     1794  * since they only make sense if someone hasn't specified the name of the
     1795  * JVM on the command line.
     1796  *
     1797  * The intent of the jvm.cfg file is to allow several JVM libraries to
     1798  * be installed in different subdirectories of a single JRE installation,
     1799  * for space-savings and convenience in testing.
     1800  * The intent is explicitly not to provide a full aliasing or predicate
     1801  * mechanism.
     1802  */
     1803 jint
     1804 ReadKnownVMs(const char *jrepath, char * arch, jboolean speculative)
     1805 {
     1806     FILE *jvmCfg;
     1807     char jvmCfgName[MAXPATHLEN+20];
     1808     char line[MAXPATHLEN+20];
     1809     int cnt = 0;
     1810     int lineno = 0;
     1811     jlong start, end;
     1812     int vmType;
     1813     char *tmpPtr;
     1814     char *altVMName = NULL;
     1815     char *serverClassVMName = NULL;
     1816     static char *whiteSpace = " \t";
     1817     if (_launcher_debug) {
     1818         start = CounterGet();
     1819     }
     1820 
     1821     strcpy(jvmCfgName, jrepath);
     1822     strcat(jvmCfgName, FILESEP "lib" FILESEP);
     1823     strcat(jvmCfgName, arch);
     1824     strcat(jvmCfgName, FILESEP "jvm.cfg");
     1825 
     1826     jvmCfg = fopen(jvmCfgName, "r");
     1827     if (jvmCfg == NULL) {
     1828       if (!speculative) {
     1829         ReportErrorMessage2("Error: could not open `%s'", jvmCfgName,
     1830                             JNI_TRUE);
     1831         exit(1);
     1832       } else {
     1833         return -1;
     1834       }
     1835     }
     1836     while (fgets(line, sizeof(line), jvmCfg) != NULL) {
     1837         vmType = VM_UNKNOWN;
     1838         lineno++;
     1839         if (line[0] == '#')
     1840             continue;
     1841         if (line[0] != '-') {
     1842             fprintf(stderr, "Warning: no leading - on line %d of `%s'\n",
     1843                     lineno, jvmCfgName);
     1844         }
     1845         if (cnt >= knownVMsLimit) {
     1846             GrowKnownVMs(cnt);
     1847         }
     1848         line[strlen(line)-1] = '\0'; /* remove trailing newline */
     1849         tmpPtr = line + strcspn(line, whiteSpace);
     1850         if (*tmpPtr == 0) {
     1851             fprintf(stderr, "Warning: missing VM type on line %d of `%s'\n",
     1852                     lineno, jvmCfgName);
     1853         } else {
     1854             /* Null-terminate this string for JLI_StringDup below */
     1855             *tmpPtr++ = 0;
     1856             tmpPtr += strspn(tmpPtr, whiteSpace);
     1857             if (*tmpPtr == 0) {
     1858                 fprintf(stderr, "Warning: missing VM type on line %d of `%s'\n",
     1859                         lineno, jvmCfgName);
     1860             } else {
     1861                 if (!strncmp(tmpPtr, "KNOWN", strlen("KNOWN"))) {
     1862                     vmType = VM_KNOWN;
     1863                 } else if (!strncmp(tmpPtr, "ALIASED_TO", strlen("ALIASED_TO"))) {
     1864                     tmpPtr += strcspn(tmpPtr, whiteSpace);
     1865                     if (*tmpPtr != 0) {
     1866                         tmpPtr += strspn(tmpPtr, whiteSpace);
     1867                     }
     1868                     if (*tmpPtr == 0) {
     1869                         fprintf(stderr, "Warning: missing VM alias on line %d of `%s'\n",
     1870                                 lineno, jvmCfgName);
     1871                     } else {
     1872                         /* Null terminate altVMName */
     1873                         altVMName = tmpPtr;
     1874                         tmpPtr += strcspn(tmpPtr, whiteSpace);
     1875                         *tmpPtr = 0;
     1876                         vmType = VM_ALIASED_TO;
     1877                     }
     1878                 } else if (!strncmp(tmpPtr, "WARN", strlen("WARN"))) {
     1879                     vmType = VM_WARN;
     1880                 } else if (!strncmp(tmpPtr, "IGNORE", strlen("IGNORE"))) {
     1881                     vmType = VM_IGNORE;
     1882                 } else if (!strncmp(tmpPtr, "ERROR", strlen("ERROR"))) {
     1883                     vmType = VM_ERROR;
     1884                 } else if (!strncmp(tmpPtr,
     1885                                     "IF_SERVER_CLASS",
     1886                                     strlen("IF_SERVER_CLASS"))) {
     1887                     tmpPtr += strcspn(tmpPtr, whiteSpace);
     1888                     if (*tmpPtr != 0) {
     1889                         tmpPtr += strspn(tmpPtr, whiteSpace);
     1890                     }
     1891                     if (*tmpPtr == 0) {
     1892                         fprintf(stderr, "Warning: missing server class VM on line %d of `%s'\n",
     1893                                 lineno, jvmCfgName);
     1894                     } else {
     1895                         /* Null terminate server class VM name */
     1896                         serverClassVMName = tmpPtr;
     1897                         tmpPtr += strcspn(tmpPtr, whiteSpace);
     1898                         *tmpPtr = 0;
     1899                         vmType = VM_IF_SERVER_CLASS;
     1900                     }
     1901                 } else {
     1902                     fprintf(stderr, "Warning: unknown VM type on line %d of `%s'\n",
     1903                             lineno, &jvmCfgName[0]);
     1904                     vmType = VM_KNOWN;
     1905                 }
     1906             }
     1907         }
     1908 
     1909         if (_launcher_debug)
     1910             printf("jvm.cfg[%d] = ->%s<-\n", cnt, line);
     1911         if (vmType != VM_UNKNOWN) {
     1912             knownVMs[cnt].name = JLI_StringDup(line);
     1913             knownVMs[cnt].flag = vmType;
     1914             switch (vmType) {
     1915             default:
     1916                 break;
     1917             case VM_ALIASED_TO:
     1918                 knownVMs[cnt].alias = JLI_StringDup(altVMName);
     1919                 if (_launcher_debug) {
     1920                     printf("    name: %s  vmType: %s  alias: %s\n",
     1921                            knownVMs[cnt].name, "VM_ALIASED_TO", knownVMs[cnt].alias);
     1922                 }
     1923                 break;
     1924             case VM_IF_SERVER_CLASS:
     1925                 knownVMs[cnt].server_class = JLI_StringDup(serverClassVMName);
     1926                 if (_launcher_debug) {
     1927                     printf("    name: %s  vmType: %s  server_class: %s\n",
     1928                            knownVMs[cnt].name, "VM_IF_SERVER_CLASS", knownVMs[cnt].server_class);
     1929                 }
     1930                 break;
     1931             }
     1932             cnt++;
     1933         }
     1934     }
     1935     fclose(jvmCfg);
     1936     knownVMsCount = cnt;
     1937 
     1938     if (_launcher_debug) {
     1939         end   = CounterGet();
     1940         printf("%ld micro seconds to parse jvm.cfg\n",
     1941                (long)(jint)Counter2Micros(end-start));
     1942     }
     1943 
     1944     return cnt;
     1945 }
     1946 
     1947 
     1948 static void
     1949 GrowKnownVMs(int minimum)
     1950 {
     1951     struct vmdesc* newKnownVMs;
     1952     int newMax;
     1953 
     1954     newMax = (knownVMsLimit == 0 ? INIT_MAX_KNOWN_VMS : (2 * knownVMsLimit));
     1955     if (newMax <= minimum) {
     1956         newMax = minimum;
     1957     }
     1958     newKnownVMs = (struct vmdesc*) JLI_MemAlloc(newMax * sizeof(struct vmdesc));
     1959     if (knownVMs != NULL) {
     1960         memcpy(newKnownVMs, knownVMs, knownVMsLimit * sizeof(struct vmdesc));
     1961     }
     1962     JLI_MemFree(knownVMs);
     1963     knownVMs = newKnownVMs;
     1964     knownVMsLimit = newMax;
     1965 }
     1966 
     1967 
     1968 /* Returns index of VM or -1 if not found */
     1969 static int
     1970 KnownVMIndex(const char* name)
     1971 {
     1972     int i;
     1973     if (strncmp(name, "-J", 2) == 0) name += 2;
     1974     for (i = 0; i < knownVMsCount; i++) {
     1975         if (!strcmp(name, knownVMs[i].name)) {
     1976             return i;
     1977         }
     1978     }
     1979     return -1;
     1980 }
     1981 
     1982 static void
     1983 FreeKnownVMs()
     1984 {
     1985     int i;
     1986     for (i = 0; i < knownVMsCount; i++) {
     1987         JLI_MemFree(knownVMs[i].name);
     1988         knownVMs[i].name = NULL;
     1989     }
     1990     JLI_MemFree(knownVMs);
     1991 }
     1992 
     1993 
     1994 /*
     1995  * Displays the splash screen according to the jar file name
     1996  * and image file names stored in environment variables
     1997  */
     1998 static void
     1999 ShowSplashScreen()
     2000 {
     2001     const char *jar_name = getenv(SPLASH_JAR_ENV_ENTRY);
     2002     const char *file_name = getenv(SPLASH_FILE_ENV_ENTRY);
     2003     int data_size;
     2004     void *image_data;
     2005     if (jar_name) {
     2006         image_data = JLI_JarUnpackFile(jar_name, file_name, &data_size);
     2007         if (image_data) {
     2008             DoSplashInit();
     2009             DoSplashLoadMemory(image_data, data_size);
     2010             JLI_MemFree(image_data);
     2011         }
     2012     } else if (file_name) {
     2013         DoSplashInit();
     2014         DoSplashLoadFile(file_name);
     2015     } else {
     2016         return;
     2017     }
     2018     DoSplashSetFileJarName(file_name, jar_name);
     2019 }