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