/* * Load a jvm from "jvmpath" and initialize the invocation functions. */ jboolean LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) { HINSTANCE handle; if (_launcher_debug) { printf("JVM path is %s\n", jvmpath); } /* Load the Java VM DLL */ if ((handle = LoadLibrary(jvmpath)) == 0) { ReportErrorMessage2("Error loading: %s", (char *)jvmpath, JNI_TRUE); return JNI_FALSE; } /* Now get the function addresses */ ifn->CreateJavaVM = (void *)GetProcAddress(handle, "JNI_CreateJavaVM"); ifn->GetDefaultJavaVMInitArgs = (void *)GetProcAddress(handle, "JNI_GetDefaultJavaVMInitArgs"); if (ifn->CreateJavaVM == 0 || ifn->GetDefaultJavaVMInitArgs == 0) { ReportErrorMessage2("Error: can't find JNI interfaces in: %s", (char *)jvmpath, JNI_TRUE); return JNI_FALSE; } return JNI_TRUE; }
/* * Load a jvm from "jvmpath" and initialize the invocation functions. */ jboolean LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) { HINSTANCE handle; char crtpath[MAXPATHLEN]; if (_launcher_debug) { printf("JVM path is %s\n", jvmpath); } /* * The Microsoft C Runtime Library needs to be loaded first. A copy is * assumed to be present in the "JRE path" directory. If it is not found * there (or "JRE path" fails to resolve), skip the explicit load and let * nature take its course, which is likely to be a failure to execute. */ if (GetJREPath(crtpath, MAXPATHLEN)) { (void)strcat(crtpath, "\\bin\\" CRT_DLL); /* Add crt dll */ if (_launcher_debug) { printf("CRT path is %s\n", crtpath); } if (_access(crtpath, 0) == 0) { if (LoadLibrary(crtpath) == 0) { ReportErrorMessage2("Error loading: %s", crtpath, JNI_TRUE); return JNI_FALSE; } } } /* Load the Java VM DLL */ if ((handle = LoadLibrary(jvmpath)) == 0) { ReportErrorMessage2("Error loading: %s", (char *)jvmpath, JNI_TRUE); return JNI_FALSE; } /* Now get the function addresses */ ifn->CreateJavaVM = (void *)GetProcAddress(handle, "JNI_CreateJavaVM"); ifn->GetDefaultJavaVMInitArgs = (void *)GetProcAddress(handle, "JNI_GetDefaultJavaVMInitArgs"); if (ifn->CreateJavaVM == 0 || ifn->GetDefaultJavaVMInitArgs == 0) { ReportErrorMessage2("Error: can't find JNI interfaces in: %s", (char *)jvmpath, JNI_TRUE); return JNI_FALSE; } return JNI_TRUE; }
static jboolean LoadMSVCRT() { // Only do this once static int loaded = 0; char crtpath[MAXPATHLEN]; if (!loaded) { /* * The Microsoft C Runtime Library needs to be loaded first. A copy is * assumed to be present in the "JRE path" directory. If it is not found * there (or "JRE path" fails to resolve), skip the explicit load and let * nature take its course, which is likely to be a failure to execute. */ if (GetJREPath(crtpath, MAXPATHLEN)) { (void)strcat(crtpath, "\\bin\\" CRT_DLL); /* Add crt dll */ if (_launcher_debug) { printf("CRT path is %s\n", crtpath); } if (_access(crtpath, 0) == 0) { if (LoadLibrary(crtpath) == 0) { ReportErrorMessage2("Error loading: %s", crtpath, JNI_TRUE); return JNI_FALSE; } } } loaded = 1; } return JNI_TRUE; }
/* * Load a jvm from "jvmpath" and initialize the invocation functions. */ jboolean LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) { #ifdef GAMMA /* JVM is directly linked with gamma launcher; no Loadlibrary() */ ifn->CreateJavaVM = JNI_CreateJavaVM; ifn->GetDefaultJavaVMInitArgs = JNI_GetDefaultJavaVMInitArgs; return JNI_TRUE; #else HINSTANCE handle; if (_launcher_debug) { printf("JVM path is %s\n", jvmpath); } /* The Microsoft C Runtime Library needs to be loaded first. */ LoadMSVCRT(); /* Load the Java VM DLL */ if ((handle = LoadLibrary(jvmpath)) == 0) { ReportErrorMessage2("Error loading: %s", (char *)jvmpath, JNI_TRUE); return JNI_FALSE; } /* Now get the function addresses */ ifn->CreateJavaVM = (void *)GetProcAddress(handle, "JNI_CreateJavaVM"); ifn->GetDefaultJavaVMInitArgs = (void *)GetProcAddress(handle, "JNI_GetDefaultJavaVMInitArgs"); if (ifn->CreateJavaVM == 0 || ifn->GetDefaultJavaVMInitArgs == 0) { ReportErrorMessage2("Error: can't find JNI interfaces in: %s", (char *)jvmpath, JNI_TRUE); return JNI_FALSE; } return JNI_TRUE; #endif /* ifndef GAMMA */ }
/* * Parses command line arguments. Returns JNI_FALSE if launcher * should exit without starting vm (e.g. certain version and usage * options); returns JNI_TRUE if vm needs to be started to process * given options. *pret (the launcher process return value) is set to * 0 for a normal exit. */ static jboolean ParseArguments(int *pargc, char ***pargv, char **pjarfile, char **pclassname, int *pret) { int argc = *pargc; char **argv = *pargv; jboolean jarflag = JNI_FALSE; char *arg; *pret = 1; while ((arg = *argv) != 0 && *arg == '-') { argv++; --argc; if (strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) { if (argc < 1) { ReportErrorMessage2("%s requires class path specification", arg, JNI_TRUE); PrintUsage(); return JNI_FALSE; } SetClassPath(*argv); argv++; --argc; } else if (strcmp(arg, "-jar") == 0) { jarflag = JNI_TRUE; } else if (strcmp(arg, "-help") == 0 || strcmp(arg, "-h") == 0 || strcmp(arg, "-?") == 0) { PrintUsage(); *pret = 0; return JNI_FALSE; } else if (strcmp(arg, "-version") == 0) { printVersion = JNI_TRUE; return JNI_TRUE; } else if (strcmp(arg, "-showversion") == 0) { showVersion = JNI_TRUE; } else if (strcmp(arg, "-X") == 0) { *pret = PrintXUsage(); return JNI_FALSE; /* * The following case provide backward compatibility with old-style * command line options. */ } else if (strcmp(arg, "-fullversion") == 0) { fprintf(stderr, "%s full version \"%s\"\n", progname, FULL_VERSION); *pret = 0; return JNI_FALSE; } else if (strcmp(arg, "-verbosegc") == 0) { AddOption("-verbose:gc", NULL); } else if (strcmp(arg, "-t") == 0) { AddOption("-Xt", NULL); } else if (strcmp(arg, "-tm") == 0) { AddOption("-Xtm", NULL); } else if (strcmp(arg, "-debug") == 0) { AddOption("-Xdebug", NULL); } else if (strcmp(arg, "-noclassgc") == 0) { AddOption("-Xnoclassgc", NULL); } else if (strcmp(arg, "-Xfuture") == 0) { AddOption("-Xverify:all", NULL); } else if (strcmp(arg, "-verify") == 0) { AddOption("-Xverify:all", NULL); } else if (strcmp(arg, "-verifyremote") == 0) { AddOption("-Xverify:remote", NULL); } else if (strcmp(arg, "-noverify") == 0) { AddOption("-Xverify:none", NULL); } else if (strcmp(arg, "-XXsuppressExitMessage") == 0) { noExitErrorMessage = 1; } else if (strncmp(arg, "-prof", 5) == 0) { char *p = arg + 5; char *tmp = MemAlloc(strlen(arg) + 50); if (*p) { sprintf(tmp, "-Xrunhprof:cpu=old,file=%s", p + 1); } else { sprintf(tmp, "-Xrunhprof:cpu=old,file=java.prof"); } AddOption(tmp, NULL); } else if (strncmp(arg, "-ss", 3) == 0 || strncmp(arg, "-oss", 4) == 0 || strncmp(arg, "-ms", 3) == 0 || strncmp(arg, "-mx", 3) == 0) { char *tmp = MemAlloc(strlen(arg) + 6); sprintf(tmp, "-X%s", arg + 1); /* skip '-' */ AddOption(tmp, NULL); } else if (strcmp(arg, "-checksource") == 0 || strcmp(arg, "-cs") == 0 || strcmp(arg, "-noasyncgc") == 0) { /* No longer supported */ fprintf(stderr, "Warning: %s option is no longer supported.\n", arg); } else if (strncmp(arg, "-version:", 9) == 0 || strcmp(arg, "-no-jre-restrict-search") == 0 || strcmp(arg, "-jre-restrict-search") == 0) { ; /* Ignore machine independent options already handled */ } else if (RemovableMachineDependentOption(arg) ) { ; /* Do not pass option to vm. */ } else { AddOption(arg, NULL); } } if (--argc >= 0) { if (jarflag) { *pjarfile = *argv++; *pclassname = 0; } else { *pjarfile = 0; *pclassname = *argv++; } *pargc = argc; *pargv = argv; } return JNI_TRUE; }
/* * The SelectVersion() routine ensures that an appropriate version of * the JRE is running. The specification for the appropriate version * is obtained from either the manifest of a jar file (preferred) or * from command line options. */ static void SelectVersion(int argc, char **argv, char **main_class) { char *arg; char **new_argv; char **new_argp; char *operand; char *version = NULL; char *jre = NULL; int jarflag = 0; int restrict_search = -1; /* -1 implies not known */ manifest_info info; char env_entry[MAXNAMELEN + 24] = ENV_ENTRY "="; char *env_in; int res; /* * If the version has already been selected, set *main_class * with the value passed through the environment (if any) and * simply return. */ if ((env_in = getenv(ENV_ENTRY)) != NULL) { if (*env_in != '\0') *main_class = strdup(env_in); return; } /* * Scan through the arguments for options relevant to multiple JRE * support. For reference, the command line syntax is defined as: * * SYNOPSIS * java [options] class [argument...] * * java [options] -jar file.jar [argument...] * * As the scan is performed, make a copy of the argument list with * the version specification options (new to 1.5) removed, so that * a version less than 1.5 can be exec'd. */ new_argv = MemAlloc((argc + 1) * sizeof(char*)); new_argv[0] = argv[0]; new_argp = &new_argv[1]; argc--; argv++; while ((arg = *argv) != 0 && *arg == '-') { if (strncmp(arg, "-version:", 9) == 0) { version = arg + 9; } else if (strcmp(arg, "-jre-restrict-search") == 0) { restrict_search = 1; } else if (strcmp(arg, "-no-jre-restrict-search") == 0) { restrict_search = 0; } else { if (strcmp(arg, "-jar") == 0) jarflag = 1; /* deal with "unfortunate" classpath syntax */ if (strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) { if (argc >= 1) { *new_argp++ = arg; argc--; argv++; arg = *argv; } } *new_argp++ = arg; } argc--; argv++; } if (argc <= 0) { /* No operand? Possibly legit with -[full]version */ operand = NULL; } else { argc--; *new_argp++ = operand = *argv++; } while (argc-- > 0) /* Copy over [argument...] */ *new_argp++ = *argv++; *new_argp = NULL; /* * If there is a jar file, read the manifest. If the jarfile can't be * read, the manifest can't be read from the jar file, or the manifest * is corrupt, issue the appropriate error messages and exit. * * Even if there isn't a jar file, construct a manifest_info structure * containing the command line information. Its a convenient way to carry * this data around. */ if (jarflag && operand) { if ((res = parse_manifest(operand, &info)) != 0) { if (res == -1) ReportErrorMessage2("Unable to access jarfile %s", operand, JNI_TRUE); else ReportErrorMessage2("Invalid or corrupt jarfile %s", operand, JNI_TRUE); exit(1); } } else { info.manifest_version = NULL; info.main_class = NULL; info.jre_version = NULL; info.jre_restrict_search = 0; } /* * The JRE-Version and JRE-Restrict-Search values (if any) from the * manifest are overwritten by any specified on the command line. */ if (version != NULL) info.jre_version = version; if (restrict_search != -1) info.jre_restrict_search = restrict_search; /* * "Valid" returns (other than unrecoverable errors) follow. Set * main_class as a side-effect of this routine. */ if (info.main_class != NULL) *main_class = strdup(info.main_class); /* * If no version selection information is found either on the command * line or in the manifest, simply return. */ if (info.jre_version == NULL) { free_manifest(); free(new_argv); return; } /* * Check for correct syntax of the version specification (JSR 56). */ if (!valid_version_string(info.jre_version)) { ReportErrorMessage2("Syntax error in version specification \"%s\"", info.jre_version, JNI_TRUE); exit(1); } /* * Find the appropriate JVM on the system. Just to be as forgiving as * possible, if the standard algorithms don't locate an appropriate * jre, check to see if the one running will satisfy the requirements. * This can happen on systems which haven't been set-up for multiple * JRE support. */ jre = LocateJRE(&info); if (_launcher_debug) printf("JRE-Version = %s, JRE-Restrict-Search = %s Selected = %s\n", (info.jre_version?info.jre_version:"null"), (info.jre_restrict_search?"true":"false"), (jre?jre:"null")); if (jre == NULL) { if (acceptable_release(FULL_VERSION, info.jre_version)) { free_manifest(); free(new_argv); return; } else { ReportErrorMessage2( "Unable to locate JRE meeting specification \"%s\"", info.jre_version, JNI_TRUE); exit(1); } } /* * If I'm not the chosen one, exec the chosen one. Returning from * ExecJRE indicates that I am indeed the chosen one. * * The private environment variable _JAVA_VERSION_SET is used to * prevent the chosen one from re-reading the manifest file and * using the values found within to override the (potential) command * line flags stripped from argv (because the target may not * understand them). Passing the MainClass value is an optimization * to avoid locating, expanding and parsing the manifest extra * times. */ if (info.main_class != NULL) { if (strlen(info.main_class) <= MAXNAMELEN) { (void)strcat(env_entry, info.main_class); } else { ReportErrorMessage("Error: main-class: attribute exceeds system limits\n", JNI_TRUE); exit(1); } } (void)putenv(env_entry); ExecJRE(jre, new_argv); free_manifest(); free(new_argv); return; }
/* * Checks the command line options to find which JVM type was * specified. If no command line option was given for the JVM type, * the default type is used. The environment variable * JDK_ALTERNATE_VM and the command line option -XXaltjvm= are also * checked as ways of specifying which JVM type to invoke. */ char * CheckJvmType(int *pargc, char ***argv, jboolean speculative) { int i, argi; int argc; char **newArgv; int newArgvIdx = 0; int isVMType; int jvmidx = -1; char *jvmtype = getenv("JDK_ALTERNATE_VM"); argc = *pargc; /* To make things simpler we always copy the argv array */ newArgv = MemAlloc((argc + 1) * sizeof(char *)); /* The program name is always present */ newArgv[newArgvIdx++] = (*argv)[0]; for (argi = 1; argi < argc; argi++) { char *arg = (*argv)[argi]; isVMType = 0; #ifdef JAVA_ARGS if (arg[0] != '-') { newArgv[newArgvIdx++] = arg; continue; } #else if (strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) { newArgv[newArgvIdx++] = arg; argi++; if (argi < argc) { newArgv[newArgvIdx++] = (*argv)[argi]; } continue; } if (arg[0] != '-') break; #endif /* Did the user pass an explicit VM type? */ i = KnownVMIndex(arg); if (i >= 0) { jvmtype = knownVMs[jvmidx = i].name + 1; /* skip the - */ isVMType = 1; *pargc = *pargc - 1; } /* Did the user specify an "alternate" VM? */ else if (strncmp(arg, "-XXaltjvm=", 10) == 0 || strncmp(arg, "-J-XXaltjvm=", 12) == 0) { isVMType = 1; jvmtype = arg+((arg[1]=='X')? 10 : 12); jvmidx = -1; } if (!isVMType) { newArgv[newArgvIdx++] = arg; } } /* * Finish copying the arguments if we aborted the above loop. * NOTE that if we aborted via "break" then we did NOT copy the * last argument above, and in addition argi will be less than * argc. */ while (argi < argc) { newArgv[newArgvIdx++] = (*argv)[argi]; argi++; } /* argv is null-terminated */ newArgv[newArgvIdx] = 0; /* Copy back argv */ *argv = newArgv; *pargc = newArgvIdx; /* use the default VM type if not specified (no alias processing) */ if (jvmtype == NULL) return knownVMs[0].name+1; /* if using an alternate VM, no alias processing */ if (jvmidx < 0) return jvmtype; /* Resolve aliases first */ { int loopCount = 0; while (knownVMs[jvmidx].flag == VM_ALIASED_TO) { int nextIdx = KnownVMIndex(knownVMs[jvmidx].alias); if (loopCount > knownVMsCount) { if (!speculative) { ReportErrorMessage("Error: Corrupt jvm.cfg file; cycle in alias list.", JNI_TRUE); exit(1); } else { return "ERROR"; /* break; */ } } if (nextIdx < 0) { if (!speculative) { ReportErrorMessage2("Error: Unable to resolve VM alias %s", knownVMs[jvmidx].alias, JNI_TRUE); exit(1); } else { return "ERROR"; } } jvmidx = nextIdx; jvmtype = knownVMs[jvmidx].name+1; loopCount++; } } switch (knownVMs[jvmidx].flag) { case VM_WARN: if (!speculative) { fprintf(stderr, "Warning: %s VM not supported; %s VM will be used\n", jvmtype, knownVMs[0].name + 1); } jvmtype = knownVMs[jvmidx=0].name + 1; /* fall through */ case VM_KNOWN: break; case VM_ERROR: if (!speculative) { ReportErrorMessage2("Error: %s VM not supported", jvmtype, JNI_TRUE); exit(1); } else { return "ERROR"; } } return jvmtype; }
/* * Read the jvm.cfg file and fill the knownJVMs[] array. * * The functionality of the jvm.cfg file is subject to change without * notice and the mechanism will be removed in the future. * * The lexical structure of the jvm.cfg file is as follows: * * jvmcfg := { vmLine } * vmLine := knownLine * | aliasLine * | warnLine * | errorLine * | commentLine * knownLine := flag "KNOWN" EOL * warnLine := flag "WARN" EOL * errorLine := flag "ERROR" EOL * aliasLine := flag "ALIASED_TO" flag EOL * commentLine := "#" text EOL * flag := "-" identifier * * The semantics are that when someone specifies a flag on the command line: * - if the flag appears on a knownLine, then the identifier is used as * the name of the directory holding the JVM library (the name of the JVM). * - if the flag appears as the first flag on an aliasLine, the identifier * of the second flag is used as the name of the JVM. * - if the flag appears on a warnLine, the identifier is used as the * name of the JVM, but a warning is generated. * - if the flag appears on an errorLine, an error is generated. * If no flag is given on the command line, the first vmLine of the jvm.cfg * file determines the name of the JVM. * * The intent of the jvm.cfg file is to allow several JVM libraries to * be installed in different subdirectories of a single JRE installation, * for space-savings and convenience in testing. * The intent is explicitly not to provide a full aliasing or predicate * mechanism. */ jint ReadKnownVMs(const char *jrepath, char * arch, jboolean speculative) { FILE *jvmCfg; char jvmCfgName[MAXPATHLEN+20]; char line[MAXPATHLEN+20]; int cnt = 0; int lineno = 0; jlong start, end; int vmType; char *tmpPtr; char *altVMName; static char *whiteSpace = " \t"; if (_launcher_debug) { start = CounterGet(); } strcpy(jvmCfgName, jrepath); strcat(jvmCfgName, FILESEP "lib" FILESEP); strcat(jvmCfgName, arch); strcat(jvmCfgName, FILESEP "jvm.cfg"); jvmCfg = fopen(jvmCfgName, "r"); if (jvmCfg == NULL) { if (!speculative) { ReportErrorMessage2("Error: could not open `%s'", jvmCfgName, JNI_TRUE); exit(1); } else { return -1; } } while (fgets(line, sizeof(line), jvmCfg) != NULL) { vmType = VM_UNKNOWN; lineno++; if (line[0] == '#') continue; if (line[0] != '-') { fprintf(stderr, "Warning: no leading - on line %d of `%s'\n", lineno, jvmCfgName); } if (cnt >= knownVMsLimit) { GrowKnownVMs(cnt); } line[strlen(line)-1] = '\0'; /* remove trailing newline */ tmpPtr = line + strcspn(line, whiteSpace); if (*tmpPtr == 0) { fprintf(stderr, "Warning: missing VM type on line %d of `%s'\n", lineno, jvmCfgName); } else { /* Null-terminate this string for strdup below */ *tmpPtr++ = 0; tmpPtr += strspn(tmpPtr, whiteSpace); if (*tmpPtr == 0) { fprintf(stderr, "Warning: missing VM type on line %d of `%s'\n", lineno, jvmCfgName); } else { if (!strncmp(tmpPtr, "KNOWN", strlen("KNOWN"))) { vmType = VM_KNOWN; } else if (!strncmp(tmpPtr, "ALIASED_TO", strlen("ALIASED_TO"))) { tmpPtr += strcspn(tmpPtr, whiteSpace); if (*tmpPtr != 0) { tmpPtr += strspn(tmpPtr, whiteSpace); } if (*tmpPtr == 0) { fprintf(stderr, "Warning: missing VM alias on line %d of `%s'\n", lineno, jvmCfgName); } else { /* Null terminate altVMName */ altVMName = tmpPtr; tmpPtr += strcspn(tmpPtr, whiteSpace); *tmpPtr = 0; vmType = VM_ALIASED_TO; } } else if (!strncmp(tmpPtr, "WARN", strlen("WARN"))) { vmType = VM_WARN; } else if (!strncmp(tmpPtr, "ERROR", strlen("ERROR"))) { vmType = VM_ERROR; } else { fprintf(stderr, "Warning: unknown VM type on line %d of `%s'\n", lineno, &jvmCfgName[0]); vmType = VM_KNOWN; } } } if (_launcher_debug) printf("jvm.cfg[%d] = ->%s<-\n", cnt, line); if (vmType != VM_UNKNOWN) { knownVMs[cnt].name = strdup(line); knownVMs[cnt].flag = vmType; switch (vmType) { default: break; case VM_ALIASED_TO: knownVMs[cnt].alias = strdup(altVMName); if (_launcher_debug) { printf(" name: %s vmType: %s alias: %s\n", knownVMs[cnt].name, "VM_ALIASED_TO", knownVMs[cnt].alias); } break; } cnt++; } } fclose(jvmCfg); knownVMsCount = cnt; if (_launcher_debug) { end = CounterGet(); printf("%ld micro seconds to parse jvm.cfg\n", (long)(jint)Counter2Micros(end-start)); } return cnt; }