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