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