/* * Entry point. */ int main(int argc, char ** argv) { JavaVM *vm = 0; JNIEnv *env = 0; char *jarfile = 0; char *classname = 0; char *s = 0; char *main_class = NULL; jstring mainClassName; jclass mainClass; jmethodID mainID; jobjectArray mainArgs; int ret; InvocationFunctions ifn; jlong start, end; char jrepath[MAXPATHLEN], jvmpath[MAXPATHLEN]; char ** original_argv = argv; /* * Error message to print or display; by default the message will * only be displayed in a window. */ char * message = "Fatal exception occurred. Program will exit."; jboolean messageDest = JNI_FALSE; if (getenv("_JAVA_LAUNCHER_DEBUG") != 0) { _launcher_debug = JNI_TRUE; printf("----_JAVA_LAUNCHER_DEBUG----\n"); } /* * Make sure the specified version of the JRE is running. * * There are three things to note about the SelectVersion() routine: * 1) If the version running isn't correct, this routine doesn't * return (either the correct version has been exec'd or an error * was issued). * 2) Argc and Argv in this scope are *not* altered by this routine. * It is the responsibility of subsequent code to ignore the * arguments handled by this routine. * 3) As a side-effect, the variable "main_class" is guaranteed to * be set (if it should ever be set). This isn't exactly the * poster child for structured programming, but it is a small * price to pay for not processing a jar file operand twice. */ SelectVersion(argc, argv, &main_class); /* copy original argv */ { int i; original_argv = (char**)MemAlloc(sizeof(char*)*(argc+1)); for(i = 0; i < argc+1; i++) original_argv[i] = argv[i]; } CreateExecutionEnvironment(&argc, &argv, jrepath, sizeof(jrepath), jvmpath, sizeof(jvmpath), original_argv); ifn.CreateJavaVM = 0; ifn.GetDefaultJavaVMInitArgs = 0; if (_launcher_debug) start = CounterGet(); if (!LoadJavaVM(jvmpath, &ifn)) { exit(6); } if (_launcher_debug) { end = CounterGet(); printf("%ld micro seconds to LoadJavaVM\n", (long)(jint)Counter2Micros(end-start)); } #ifdef JAVA_ARGS /* javac, jar and friends. */ progname = "java"; #else /* java, oldjava, javaw and friends */ #ifdef PROGNAME progname = PROGNAME; #else progname = *argv; if ((s = strrchr(progname, FILE_SEPARATOR)) != 0) { progname = s + 1; } #endif /* PROGNAME */ #endif /* JAVA_ARGS */ ++argv; --argc; #ifdef JAVA_ARGS /* Preprocess wrapper arguments */ TranslateDashJArgs(&argc, &argv); if (!AddApplicationOptions()) { exit(1); } #endif /* Set default CLASSPATH */ if ((s = getenv("CLASSPATH")) == 0) { s = "."; } #ifndef JAVA_ARGS SetClassPath(s); #endif /* * Parse command line options; if the return value of * ParseArguments is false, the program should exit. */ if (!ParseArguments(&argc, &argv, &jarfile, &classname, &ret)) { exit(ret); } /* Override class path if -jar flag was specified */ if (jarfile != 0) { SetClassPath(jarfile); } /* set the -Dsun.java.command pseudo property */ SetJavaCommandLineProp(classname, jarfile, argc, argv); /* Set the -Dsun.java.launcher pseudo property */ SetJavaLauncherProp(); /* * Done with all command line processing and potential re-execs so * clean up the environment. */ (void)UnsetEnv(ENV_ENTRY); /* Initialize the virtual machine */ if (_launcher_debug) start = CounterGet(); if (!InitializeJVM(&vm, &env, &ifn)) { ReportErrorMessage("Could not create the Java virtual machine.", JNI_TRUE); exit(1); } if (printVersion || showVersion) { PrintJavaVersion(env); if ((*env)->ExceptionOccurred(env)) { ReportExceptionDescription(env); goto leave; } if (printVersion) { ret = 0; message = NULL; goto leave; } if (showVersion) { fprintf(stderr, "\n"); } } /* If the user specified neither a class name nor a JAR file */ if (jarfile == 0 && classname == 0) { PrintUsage(); message = NULL; goto leave; } FreeKnownVMs(); /* after last possible PrintUsage() */ if (_launcher_debug) { end = CounterGet(); printf("%ld micro seconds to InitializeJVM\n", (long)(jint)Counter2Micros(end-start)); } /* At this stage, argc/argv have the applications' arguments */ if (_launcher_debug) { int i = 0; printf("Main-Class is '%s'\n", classname ? classname : ""); printf("Apps' argc is %d\n", argc); for (; i < argc; i++) { printf(" argv[%2d] = '%s'\n", i, argv[i]); } } ret = 1; /* Get the application's main class */ if (jarfile != 0) { mainClassName = GetMainClassName(env, jarfile); if ((*env)->ExceptionOccurred(env)) { ReportExceptionDescription(env); goto leave; } if (mainClassName == NULL) { const char * format = "Failed to load Main-Class manifest " "attribute from\n%s"; message = (char*)MemAlloc((strlen(format) + strlen(jarfile)) * sizeof(char)); sprintf(message, format, jarfile); messageDest = JNI_TRUE; goto leave; } classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); if (classname == NULL) { ReportExceptionDescription(env); goto leave; } mainClass = LoadClass(env, classname); if(mainClass == NULL) { /* exception occured */ ReportExceptionDescription(env); message = "Could not find the main class. Program will exit."; goto leave; } (*env)->ReleaseStringUTFChars(env, mainClassName, classname); } else { mainClassName = NewPlatformString(env, classname); if (mainClassName == NULL) { const char * format = "Failed to load Main Class: %s"; message = (char *)MemAlloc((strlen(format) + strlen(classname)) * sizeof(char) ); sprintf(message, format, classname); messageDest = JNI_TRUE; goto leave; } classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); if (classname == NULL) { ReportExceptionDescription(env); goto leave; } mainClass = LoadClass(env, classname); if(mainClass == NULL) { /* exception occured */ ReportExceptionDescription(env); message = "Could not find the main class. Program will exit."; goto leave; } (*env)->ReleaseStringUTFChars(env, mainClassName, classname); } /* Get the application's main method */ mainID = (*env)->GetStaticMethodID(env, mainClass, "main", "([Ljava/lang/String;)V"); if (mainID == NULL) { if ((*env)->ExceptionOccurred(env)) { ReportExceptionDescription(env); } else { message = "No main method found in specified class."; messageDest = JNI_TRUE; } goto leave; } { /* Make sure the main method is public */ jint mods; jmethodID mid; jobject obj = (*env)->ToReflectedMethod(env, mainClass, mainID, JNI_TRUE); if( obj == NULL) { /* exception occurred */ ReportExceptionDescription(env); goto leave; } mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, obj), "getModifiers", "()I"); if ((*env)->ExceptionOccurred(env)) { ReportExceptionDescription(env); goto leave; } mods = (*env)->CallIntMethod(env, obj, mid); if ((mods & 1) == 0) { /* if (!Modifier.isPublic(mods)) ... */ message = "Main method not public."; messageDest = JNI_TRUE; goto leave; } } /* Build argument array */ mainArgs = NewPlatformStringArray(env, argv, argc); if (mainArgs == NULL) { ReportExceptionDescription(env); goto leave; } /* Invoke main method. */ (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); if ((*env)->ExceptionOccurred(env)) { /* * Formerly, we used to call the "uncaughtException" method of * the main thread group, but this was later shown to be * unnecessary since the default definition merely printed out * the same exception stack trace as ExceptionDescribe and * could never actually be overridden by application programs. */ ReportExceptionDescription(env); goto leave; } /* * Detach the current thread so that it appears to have exited when * the application's main method exits. */ if ((*vm)->DetachCurrentThread(vm) != 0) { message = "Could not detach main thread."; messageDest = JNI_TRUE; goto leave; } ret = 0; message = NULL; leave: (*vm)->DestroyJavaVM(vm); if(message != NULL && !noExitErrorMessage) ReportErrorMessage(message, messageDest); return ret; }
/* * At this point we have the arguments to the application, and we need to * check with original stdargs in order to compare which of these truly * needs expansion. cmdtoargs will specify this if it finds a bare * (unquoted) argument containing a glob character(s) ie. * or ? */ jobjectArray CreateApplicationArgs(JNIEnv *env, char **strv, int argc) { int i, j, idx; size_t tlen; jobjectArray outArray, inArray; char *arg, **nargv; jboolean needs_expansion = JNI_FALSE; jmethodID mid; int stdargc; StdArg *stdargs; int *appArgIdx; int isTool; jclass cls = GetLauncherHelperClass(env); NULL_CHECK0(cls); if (argc == 0) { return NewPlatformStringArray(env, strv, argc); } // the holy grail we need to compare with. stdargs = JLI_GetStdArgs(); stdargc = JLI_GetStdArgc(); // sanity check, this should never happen if (argc > stdargc) { JLI_TraceLauncher("Warning: app args is larger than the original, %d %d\n", argc, stdargc); JLI_TraceLauncher("passing arguments as-is.\n"); return NewPlatformStringArray(env, strv, argc); } // sanity check, match the args we have, to the holy grail idx = JLI_GetAppArgIndex(); isTool = (idx == 0); if (isTool) { idx++; } // skip tool name JLI_TraceLauncher("AppArgIndex: %d points to %s\n", idx, stdargs[idx].arg); appArgIdx = calloc(argc, sizeof(int)); for (i = idx, j = 0; i < stdargc; i++) { if (isTool) { // filter -J used by tools to pass JVM options arg = stdargs[i].arg; if (arg[0] == '-' && arg[1] == 'J') { continue; } } appArgIdx[j++] = i; } // sanity check, ensure same number of arguments for application if (j != argc) { JLI_TraceLauncher("Warning: app args count doesn't match, %d %d\n", j, argc); JLI_TraceLauncher("passing arguments as-is.\n"); JLI_MemFree(appArgIdx); return NewPlatformStringArray(env, strv, argc); } // make a copy of the args which will be expanded in java if required. nargv = (char **)JLI_MemAlloc(argc * sizeof(char*)); for (i = 0; i < argc; i++) { jboolean arg_expand; j = appArgIdx[i]; arg_expand = (JLI_StrCmp(stdargs[j].arg, strv[i]) == 0) ? stdargs[j].has_wildcard : JNI_FALSE; if (needs_expansion == JNI_FALSE) needs_expansion = arg_expand; // indicator char + String + NULL terminator, the java method will strip // out the first character, the indicator character, so no matter what // we add the indicator tlen = 1 + JLI_StrLen(strv[i]) + 1; nargv[i] = (char *) JLI_MemAlloc(tlen); if (JLI_Snprintf(nargv[i], tlen, "%c%s", arg_expand ? 'T' : 'F', strv[i]) < 0) { return NULL; } JLI_TraceLauncher("%s\n", nargv[i]); } if (!needs_expansion) { // clean up any allocated memory and return back the old arguments for (i = 0 ; i < argc ; i++) { JLI_MemFree(nargv[i]); } JLI_MemFree(nargv); JLI_MemFree(appArgIdx); return NewPlatformStringArray(env, strv, argc); } NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls, "expandArgs", "([Ljava/lang/String;)[Ljava/lang/String;")); // expand the arguments that require expansion, the java method will strip // out the indicator character. NULL_CHECK0(inArray = NewPlatformStringArray(env, nargv, argc)); outArray = (*env)->CallStaticObjectMethod(env, cls, mid, inArray); for (i = 0; i < argc; i++) { JLI_MemFree(nargv[i]); } JLI_MemFree(nargv); JLI_MemFree(appArgIdx); return outArray; }
jobjectArray CreateApplicationArgs(JNIEnv *env, char **strv, int argc) { return NewPlatformStringArray(env, strv, argc); }
/* * At this point we have the arguments to the application, and we need to * check with original stdargs in order to compare which of these truly * needs expansion. cmdtoargs will specify this if it finds a bare * (unquoted) argument containing a glob character(s) ie. * or ? */ jobjectArray CreateApplicationArgs(JNIEnv *env, char **strv, int argc) { int i, j, idx, tlen; jobjectArray outArray, inArray; char *ostart, *astart, **nargv; jboolean needs_expansion = JNI_FALSE; jmethodID mid; int stdargc; StdArg *stdargs; jclass cls = GetLauncherHelperClass(env); NULL_CHECK0(cls); if (argc == 0) { return NewPlatformStringArray(env, strv, argc); } // the holy grail we need to compare with. stdargs = JLI_GetStdArgs(); stdargc = JLI_GetStdArgc(); // sanity check, this should never happen if (argc > stdargc) { JLI_TraceLauncher("Warning: app args is larger than the original, %d %d\n", argc, stdargc); JLI_TraceLauncher("passing arguments as-is.\n"); return NewPlatformStringArray(env, strv, argc); } // sanity check, match the args we have, to the holy grail idx = stdargc - argc; ostart = stdargs[idx].arg; astart = strv[0]; // sanity check, ensure that the first argument of the arrays are the same if (JLI_StrCmp(ostart, astart) != 0) { // some thing is amiss the args don't match JLI_TraceLauncher("Warning: app args parsing error\n"); JLI_TraceLauncher("passing arguments as-is\n"); return NewPlatformStringArray(env, strv, argc); } // make a copy of the args which will be expanded in java if required. nargv = (char **)JLI_MemAlloc(argc * sizeof(char*)); for (i = 0, j = idx; i < argc; i++, j++) { jboolean arg_expand = (JLI_StrCmp(stdargs[j].arg, strv[i]) == 0) ? stdargs[j].has_wildcard : JNI_FALSE; if (needs_expansion == JNI_FALSE) needs_expansion = arg_expand; // indicator char + String + NULL terminator, the java method will strip // out the first character, the indicator character, so no matter what // we add the indicator tlen = 1 + JLI_StrLen(strv[i]) + 1; nargv[i] = (char *) JLI_MemAlloc(tlen); if (JLI_Snprintf(nargv[i], tlen, "%c%s", arg_expand ? 'T' : 'F', strv[i]) < 0) { return NULL; } JLI_TraceLauncher("%s\n", nargv[i]); } if (!needs_expansion) { // clean up any allocated memory and return back the old arguments for (i = 0 ; i < argc ; i++) { JLI_MemFree(nargv[i]); } JLI_MemFree(nargv); return NewPlatformStringArray(env, strv, argc); } NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls, "expandArgs", "([Ljava/lang/String;)[Ljava/lang/String;")); // expand the arguments that require expansion, the java method will strip // out the indicator character. inArray = NewPlatformStringArray(env, nargv, argc); outArray = (*env)->CallStaticObjectMethod(env, cls, mid, inArray); for (i = 0; i < argc; i++) { JLI_MemFree(nargv[i]); } JLI_MemFree(nargv); return outArray; }