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