/* * Determine if there is an acceptable JRE in the registry directory top_key. * Upon locating the "best" one, return a fully qualified path to it. * "Best" is defined as the most advanced JRE meeting the constraints * contained in the manifest_info. If no JRE in this directory meets the * constraints, return NULL. * * It doesn't matter if we get an error reading the registry, or we just * don't find anything interesting in the directory. We just return NULL * in either case. */ static char * ProcessDir(manifest_info* info, HKEY top_key) { DWORD index = 0; HKEY ver_key; char name[MAXNAMELEN]; int len; char *best = NULL; /* * Enumerate "<top_key>/SOFTWARE/JavaSoft/Java Runtime Environment" * searching for the best available version. */ while (RegEnumKey(top_key, index, name, MAXNAMELEN) == ERROR_SUCCESS) { index++; if (acceptable_release(name, info->jre_version)) if ((best == NULL) || (exact_version_id(name, best) > 0)) { if (best != NULL) free(best); best = strdup(name); } } /* * Extract "JavaHome" from the "best" registry directory and return * that path. If no appropriate version was located, or there is an * error in extracting the "JavaHome" string, return null. */ if (best == NULL) return (NULL); else { if (RegOpenKeyEx(top_key, best, 0, KEY_READ, &ver_key) != ERROR_SUCCESS) { free(best); if (ver_key != NULL) RegCloseKey(ver_key); return (NULL); } free(best); len = MAXNAMELEN; if (RegQueryValueEx(ver_key, "JavaHome", NULL, NULL, (LPBYTE)name, &len) != ERROR_SUCCESS) { if (ver_key != NULL) RegCloseKey(ver_key); return (NULL); } if (ver_key != NULL) RegCloseKey(ver_key); return (strdup(name)); } }
/* * 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; }