/* * Compute the name of the executable * * In order to re-exec securely we need the absolute path of the * executable. On Solaris getexecname(3c) may not return an absolute * path so we use dladdr to get the filename of the executable and * then use realpath to derive an absolute path. From Solaris 9 * onwards the filename returned in DL_info structure from dladdr is * an absolute pathname so technically realpath isn't required. * On Linux we read the executable name from /proc/self/exe. * As a fallback, and for platforms other than Solaris and Linux, * we use FindExecName to compute the executable name. */ const char* SetExecname(char **argv) { char* exec_path = NULL; { Dl_info dlinfo; int (*fptr)(); fptr = (int (*)())dlsym(RTLD_DEFAULT, "main"); if (fptr == NULL) { JLI_ReportErrorMessage(DLL_ERROR3, dlerror()); return JNI_FALSE; } if (dladdr((void*)fptr, &dlinfo)) { char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1); if (resolved != NULL) { exec_path = realpath(dlinfo.dli_fname, resolved); if (exec_path == NULL) { JLI_MemFree(resolved); } } } } if (exec_path == NULL) { exec_path = FindExecName(argv[0]); } execname = exec_path; return exec_path; }
/* * 从给定目录中搜索与指定版本最匹配的jre安装路径 */ static char *ProcessDir(manifest_info *info, char *dirname) { DIR *dirp; struct dirent *dp; char *best = NULL; int offset; int best_offset = 0; char *ret_str = NULL; char buffer[PATH_MAX]; printf("%s[%d] [tid: %lu]: 开始从目录[%]中搜索安装的最佳jre版本...\n", __FILE__, __LINE__, pthread_self(), dirname); if ((dirp = opendir(dirname)) == NULL) return (NULL); do { if ((dp = readdir(dirp)) != NULL) { offset = 0; if ((JLI_StrNCmp(dp->d_name, "jre", 3) == 0) || (JLI_StrNCmp(dp->d_name, "jdk", 3) == 0)) offset = 3; else if (JLI_StrNCmp(dp->d_name, "j2re", 4) == 0) offset = 4; else if (JLI_StrNCmp(dp->d_name, "j2sdk", 5) == 0) offset = 5; if (offset > 0) { if ((JLI_AcceptableRelease(dp->d_name + offset, info->jre_version)) && CheckSanity(dirname, dp->d_name)){ if ((best == NULL) || (JLI_ExactVersionId( dp->d_name + offset, best + best_offset) > 0)) { if (best != NULL) JLI_MemFree(best); best = JLI_StringDup(dp->d_name); best_offset = offset; } } } } } while (dp != NULL); (void) closedir(dirp); if (best == NULL){ printf("%s[%d] [tid: %lu]: 目录[%]中没有找到合适的jre版本...\n", __FILE__, __LINE__, pthread_self(), dirname); return (NULL); } else { ret_str = JLI_MemAlloc(JLI_StrLen(dirname) + JLI_StrLen(best) + 2); sprintf(ret_str, "%s/%s", dirname, best); JLI_MemFree(best); printf("%s[%d] [tid: %lu]: 搜索到最合适的jre版本: %s...\n", __FILE__, __LINE__, pthread_self(), ret_str); return (ret_str); } }
/* * Local helper routine to return a string equivalent to the input string * s, but with quotes removed so the result is a string as would be found * in argv[]. The returned string should be freed by a call to JLI_MemFree(). * * The rules for quoting (and escaped quotes) are: * * 1 A double quotation mark preceded by a backslash, \", is interpreted as a * literal double quotation mark ("). * * 2 Backslashes are interpreted literally, unless they immediately precede a * double quotation mark. * * 3 If an even number of backslashes is followed by a double quotation mark, * then one backslash (\) is placed in the argv array for every pair of * backslashes (\\), and the double quotation mark (") is interpreted as a * string delimiter. * * 4 If an odd number of backslashes is followed by a double quotation mark, * then one backslash (\) is placed in the argv array for every pair of * backslashes (\\) and the double quotation mark is interpreted as an * escape sequence by the remaining backslash, causing a literal double * quotation mark (") to be placed in argv. */ static char* unquote(const char *s) { const char *p = s; /* Pointer to the tail of the original string */ char *un = (char*)JLI_MemAlloc(strlen(s) + 1); /* Ptr to unquoted string */ char *pun = un; /* Pointer to the tail of the unquoted string */ while (*p != '\0') { if (*p == '"') { p++; } else if (*p == '\\') { const char *q = p + strspn(p,"\\"); if (*q == '"') do { *pun++ = '\\'; p += 2; } while (*p == '\\' && p < q); else while (p < q) *pun++ = *p++; } else { *pun++ = *p++; } } *pun = '\0'; return un; }
void CreateExecutionEnvironment(int *_argc, char ***_argv, char jrepath[], jint so_jrepath, char jvmpath[], jint so_jvmpath, char **original_argv) { char * jvmtype; int i = 0; char** pargv = *_argv; int running = CURRENT_DATA_MODEL; int wanted = running; for (i = 0; i < *_argc ; i++) { if (strcmp(pargv[i], "-J-d64") == 0 || strcmp(pargv[i], "-d64") == 0) { wanted = 64; continue; } if (strcmp(pargv[i], "-J-d32") == 0 || strcmp(pargv[i], "-d32") == 0) { wanted = 32; continue; } } if (running != wanted) { fprintf(stderr, "This Java instance does not support a %d-bit JVM.\nPlease install the desired version.\n", wanted); exit(1); } /* Find out where the JRE is that we will be using. */ if (!GetJREPath(jrepath, so_jrepath)) { ReportErrorMessage("Error: could not find Java 2 Runtime Environment.", JNI_TRUE); exit(2); } /* Find the specified JVM type */ if (ReadKnownVMs(jrepath, (char*)GetArch(), JNI_FALSE) < 1) { ReportErrorMessage("Error: no known VMs. (check for corrupt jvm.cfg file)", JNI_TRUE); exit(1); } jvmtype = CheckJvmType(_argc, _argv, JNI_FALSE); jvmpath[0] = '\0'; if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) { char * message=NULL; const char * format = "Error: no `%s' JVM at `%s'."; message = (char *)JLI_MemAlloc((strlen(format)+strlen(jvmtype)+ strlen(jvmpath)) * sizeof(char)); sprintf(message,format, jvmtype, jvmpath); ReportErrorMessage(message, JNI_TRUE); exit(4); } /* If we got here, jvmpath has been correctly initialized. */ }
void SetJavaLauncherPlatformProps() { /* Linux only */ #ifdef __linux__ const char *substr = "-Dsun.java.launcher.pid="; char *pid_prop_str = (char *)JLI_MemAlloc(JLI_StrLen(substr) + MAX_PID_STR_SZ + 1); sprintf(pid_prop_str, "%s%d", substr, getpid()); AddOption(pid_prop_str, NULL); #endif }
static FileList FileList_new(int capacity) { FileList fl = NEW_(FileList); fl->capacity = capacity; fl->files = (char **) JLI_MemAlloc(capacity * sizeof(fl->files[0])); fl->size = 0; return fl; }
static void FileList_addSubstring(FileList fl, const char *beg, int len) { char *filename = (char *) JLI_MemAlloc(len+1); memcpy(filename, beg, len); filename[len] = '\0'; FileList_ensureCapacity(fl, fl->size+1); fl->files[fl->size++] = filename; }
/* * Wrapper for platform dependent unsetenv function. */ int UnsetEnv(char *name) { int ret; char *buf = JLI_MemAlloc(JLI_StrLen(name) + 2); buf = JLI_StrCat(JLI_StrCpy(buf, name), "="); ret = _putenv(buf); JLI_MemFree(buf); return (ret); }
/* * Wrapper for platform dependent unsetenv function. */ int UnsetEnv(char *name) { int ret; char *buf = JLI_MemAlloc(strlen(name) + 2); buf = strcat(strcpy(buf, name), "="); ret = _putenv(buf); JLI_MemFree(buf); return (ret); }
static char * wildcardConcat(const char *wildcard, const char *basename) { int wildlen = (int)JLI_StrLen(wildcard); int baselen = (int)JLI_StrLen(basename); char *filename = (char *) JLI_MemAlloc(wildlen + baselen); /* Replace the trailing '*' with basename */ memcpy(filename, wildcard, wildlen-1); memcpy(filename+wildlen-1, basename, baselen+1); return filename; }
int WINAPI WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow) { int margc; char** margv; const jboolean const_javaw = JNI_TRUE; __initenv = _environ; #else /* JAVAW */ int main(int argc, char **argv) { int margc; char** margv; const jboolean const_javaw = JNI_FALSE; #endif /* JAVAW */ #ifdef _WIN32 { int i = 0; if (getenv(JLDEBUG_ENV_ENTRY) != NULL) { printf("Windows original main args:\n"); for (i = 0 ; i < __argc ; i++) { printf("wwwd_args[%d] = %s\n", i, __argv[i]); } } } JLI_CmdToArgs(GetCommandLine()); margc = JLI_GetStdArgc(); // add one more to mark the end margv = (char **)JLI_MemAlloc((margc + 1) * (sizeof(char *))); { int i = 0; StdArg *stdargs = JLI_GetStdArgs(); for (i = 0 ; i < margc ; i++) { margv[i] = stdargs[i].arg; } margv[i] = NULL; } #else /* *NIXES */ margc = argc; margv = argv; #endif /* WIN32 */ return JLI_Launch(margc, margv, sizeof(const_jargs) / sizeof(char *), const_jargs, sizeof(const_appclasspath) / sizeof(char *), const_appclasspath, FULL_VERSION, DOT_VERSION, (const_progname != NULL) ? const_progname : *margv, (const_launcher != NULL) ? const_launcher : *margv, (const_jargs != NULL) ? JNI_TRUE : JNI_FALSE, const_cpwildcard, const_javaw, const_ergo_class); }
/* * Find a command in a directory, returning the path. */ static char * Resolve(char *indir, char *cmd) { char name[PATH_MAX + 2], *real; if ((JLI_StrLen(indir) + JLI_StrLen(cmd) + 1) > PATH_MAX) return 0; JLI_Snprintf(name, sizeof(name), "%s%c%s", indir, FILE_SEPARATOR, cmd); if (!ProgramExists(name)) return 0; real = JLI_MemAlloc(PATH_MAX + 2); if (!realpath(name, real)) JLI_StrCpy(real, name); return real; }
/* * As ReportErrorMessage2 (above) except the system message (if any) * associated with this error is written to a second %s format specifier * in the format argument. */ void ReportSysErrorMessage2(char * format, char * string, jboolean always) { int save_errno = errno; DWORD errval; int freeit = 0; char *errtext = NULL; if ((errval = GetLastError()) != 0) { /* Platform SDK / DOS Error */ int n = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM| FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, errval, 0, (LPTSTR)&errtext, 0, NULL); if (errtext == NULL || n == 0) { /* Paranoia check */ errtext = ""; n = 0; } else { freeit = 1; if (n > 2) { /* Drop final CR, LF */ if (errtext[n - 1] == '\n') n--; if (errtext[n - 1] == '\r') n--; errtext[n] = '\0'; } } } else /* C runtime error that has no corresponding DOS error code */ errtext = strerror(save_errno); #ifdef JAVAW { size_t size; char * message; size = strlen(format) + strlen(string) + strlen(errtext); message = (char*)JLI_MemAlloc(size*sizeof(char)); sprintf(message, (const char *)format, string, errtext); if (message != NULL) { MessageBox(NULL, message, "Java Virtual Machine Launcher", (MB_OK|MB_ICONSTOP|MB_APPLMODAL)); JLI_MemFree(message); } } #else if (always) { fprintf(stderr, (const char *)format, string, errtext); fprintf(stderr, "\n"); } #endif if (freeit) (void)LocalFree((HLOCAL)errtext); }
/* * Compute the name of the executable * * In order to re-exec securely we need the absolute path of the * executable. On Solaris getexecname(3c) may not return an absolute * path so we use dladdr to get the filename of the executable and * then use realpath to derive an absolute path. From Solaris 9 * onwards the filename returned in DL_info structure from dladdr is * an absolute pathname so technically realpath isn't required. * On Linux we read the executable name from /proc/self/exe. * As a fallback, and for platforms other than Solaris and Linux, * we use FindExecName to compute the executable name. */ static const char* SetExecname(char **argv) { char* exec_path = NULL; #if defined(__solaris__) { Dl_info dlinfo; int (*fptr)(); fptr = (int (*)())dlsym(RTLD_DEFAULT, "main"); if (fptr == NULL) { JLI_ReportErrorMessage(DLL_ERROR3, dlerror()); return JNI_FALSE; } if (dladdr((void*)fptr, &dlinfo)) { char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1); if (resolved != NULL) { exec_path = realpath(dlinfo.dli_fname, resolved); if (exec_path == NULL) { JLI_MemFree(resolved); } } } } #elif defined(__linux__) { const char* self = "/proc/self/exe"; char buf[PATH_MAX+1]; int len = readlink(self, buf, PATH_MAX); if (len >= 0) { buf[len] = '\0'; /* readlink doesn't nul terminate */ exec_path = JLI_StringDup(buf); } } #else /* !__solaris__ && !__linux */ { /* Not implemented */ } #endif if (exec_path == NULL) { exec_path = FindExecName(argv[0]); } execname = exec_path; return exec_path; }
/* * 搜索指定的jre环境 */ char* LocateJRE(manifest_info* info) { char *path; char *home; char *target = NULL; char *dp; char *cp; /* * Start by getting JAVA_VERSION_PATH */ if (info->jre_restrict_search) { path = JLI_StringDup(system_dir); } else if ((path = getenv("JAVA_VERSION_PATH")) != NULL) { path = JLI_StringDup(path); } else { if ((home = getenv("HOME")) != NULL) { path = (char *)JLI_MemAlloc(JLI_StrLen(home) + \ JLI_StrLen(system_dir) + JLI_StrLen(user_dir) + 2); sprintf(path, "%s%s:%s", home, user_dir, system_dir); } else { path = JLI_StringDup(system_dir); } } /* * Step through each directory on the path. Terminate the scan with * the first directory with an acceptable JRE. */ cp = dp = path; while (dp != NULL) { cp = JLI_StrChr(dp, (int)':'); if (cp != NULL) *cp = '\0'; if ((target = ProcessDir(info, dp)) != NULL) break; dp = cp; if (dp != NULL) dp++; } JLI_MemFree(path); return (target); }
/* * Find a path for the executable */ char * FindExecName(char *program) { char cwdbuf[PATH_MAX+2]; char *path; char *tmp_path; char *f; char *result = NULL; /* absolute path? */ if (*program == FILE_SEPARATOR || (FILE_SEPARATOR=='\\' && JLI_StrRChr(program, ':'))) return Resolve("", program+1); /* relative path? */ if (JLI_StrRChr(program, FILE_SEPARATOR) != 0) { char buf[PATH_MAX+2]; return Resolve(getcwd(cwdbuf, sizeof(cwdbuf)), program); } /* from search path? */ path = getenv("PATH"); if (!path || !*path) path = "."; tmp_path = JLI_MemAlloc(JLI_StrLen(path) + 2); JLI_StrCpy(tmp_path, path); for (f=tmp_path; *f && result==0; ) { char *s = f; while (*f && (*f != PATH_SEPARATOR)) ++f; if (*f) *f++ = 0; if (*s == FILE_SEPARATOR) result = Resolve(s, program); else { /* relative path element */ char dir[2*PATH_MAX]; JLI_Snprintf(dir, sizeof(dir), "%s%c%s", getcwd(cwdbuf, sizeof(cwdbuf)), FILE_SEPARATOR, s); result = Resolve(dir, program); } if (result != 0) break; } JLI_MemFree(tmp_path); return result; }
static char * FileList_join(FileList fl, char sep) { int i; int size; char *path; char *p; for (i = 0, size = 1; i < fl->size; i++) size += (int)JLI_StrLen(fl->files[i]) + 1; path = JLI_MemAlloc(size); for (i = 0, p = path; i < fl->size; i++) { int len = (int)JLI_StrLen(fl->files[i]); if (i > 0) *p++ = sep; memcpy(p, fl->files[i], len); p += len; } *p = '\0'; return path; }
void JLI_ReportErrorMessage(const char* fmt, ...) { va_list vl; va_start(vl,fmt); if (IsJavaw()) { char *message; /* get the length of the string we need */ int n = _vscprintf(fmt, vl); message = (char *)JLI_MemAlloc(n + 1); _vsnprintf(message, n, fmt, vl); message[n]='\0'; MessageBox(NULL, message, "Java Virtual Machine Launcher", (MB_OK|MB_ICONSTOP|MB_APPLMODAL)); JLI_MemFree(message); } else { vfprintf(stderr, fmt, vl); fprintf(stderr, "\n"); } va_end(vl); }
void ReportErrorMessage2(char * format, char * string, jboolean always) { /* * The format argument must be a printf format string with one %s * argument, which is passed the string argument. */ #ifdef JAVAW size_t size; char * message; size = strlen(format) + strlen(string); message = (char*)JLI_MemAlloc(size*sizeof(char)); sprintf(message, (const char *)format, string); if (message != NULL) { MessageBox(NULL, message, "Java Virtual Machine Launcher", (MB_OK|MB_ICONSTOP|MB_APPLMODAL)); JLI_MemFree(message); } #else if (always) { fprintf(stderr, (const char *)format, string); fprintf(stderr, "\n"); } #endif }
/* * 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; }
void CreateExecutionEnvironment(int *pargc, char ***pargv, char jrepath[], jint so_jrepath, char jvmpath[], jint so_jvmpath, char jvmcfg[], jint so_jvmcfg) { /* * First, determine if we are running the desired data model. If we * are running the desired data model, all the error messages * associated with calling GetJREPath, ReadKnownVMs, etc. should be * output, otherwise we simply exit with an error, as we no longer * support dual data models. */ jboolean jvmpathExists; /* Compute/set the name of the executable */ SetExecname(*pargv); /* Check data model flags, and exec process, if needed */ { char *arch = LIBARCHNAME; /* like sparc or sparcv9 */ char * jvmtype = NULL; int argc = *pargc; char **argv = *pargv; int running = CURRENT_DATA_MODEL; /* * As of jdk9, there is no support for dual mode operations, however * for legacy error reporting purposes and until -d options are supported * we need this. */ int wanted = running; #ifdef SETENV_REQUIRED jboolean mustsetenv = JNI_FALSE; char *runpath = NULL; /* existing effective LD_LIBRARY_PATH setting */ char* new_runpath = NULL; /* desired new LD_LIBRARY_PATH string */ char* newpath = NULL; /* path on new LD_LIBRARY_PATH */ char* lastslash = NULL; char** newenvp = NULL; /* current environment */ size_t new_runpath_size; #ifdef __solaris__ char* dmpath = NULL; /* data model specific LD_LIBRARY_PATH, Solaris only */ #endif /* __solaris__ */ #endif /* SETENV_REQUIRED */ char** newargv = NULL; int newargc = 0; /* * Starting in 1.5, all unix platforms accept the -d32 and -d64 * options. On platforms where only one data-model is supported * (e.g. ia-64 Linux), using the flag for the other data model is * an error and will terminate the program. */ { /* open new scope to declare local variables */ int i; newargv = (char **)JLI_MemAlloc((argc+1) * sizeof(char*)); newargv[newargc++] = argv[0]; /* scan for data model arguments and remove from argument list; last occurrence determines desired data model */ for (i=1; i < argc; i++) { if (JLI_StrCmp(argv[i], "-J-d64") == 0 || JLI_StrCmp(argv[i], "-d64") == 0) { wanted = 64; continue; } if (JLI_StrCmp(argv[i], "-J-d32") == 0 || JLI_StrCmp(argv[i], "-d32") == 0) { wanted = 32; continue; } newargv[newargc++] = argv[i]; if (IsJavaArgs()) { if (argv[i][0] != '-') continue; } else { if (JLI_StrCmp(argv[i], "-classpath") == 0 || JLI_StrCmp(argv[i], "-cp") == 0) { i++; if (i >= argc) break; newargv[newargc++] = argv[i]; continue; } if (argv[i][0] != '-') { i++; break; } } } /* copy rest of args [i .. argc) */ while (i < argc) { newargv[newargc++] = argv[i++]; } newargv[newargc] = NULL; /* * newargv has all proper arguments here */ argc = newargc; argv = newargv; } /* If the data model is not changing, it is an error if the jvmpath does not exist */ if (wanted == running) { /* Find out where the JRE is that we will be using. */ if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) { JLI_ReportErrorMessage(JRE_ERROR1); exit(2); } JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg", jrepath, FILESEP, FILESEP, arch, FILESEP); /* Find the specified JVM type */ if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) { JLI_ReportErrorMessage(CFG_ERROR7); exit(1); } jvmpath[0] = '\0'; jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE); if (JLI_StrCmp(jvmtype, "ERROR") == 0) { JLI_ReportErrorMessage(CFG_ERROR9); exit(4); } if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, 0 )) { JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); exit(4); } /* * we seem to have everything we need, so without further ado * we return back, otherwise proceed to set the environment. */ #ifdef SETENV_REQUIRED mustsetenv = RequiresSetenv(jvmpath); JLI_TraceLauncher("mustsetenv: %s\n", mustsetenv ? "TRUE" : "FALSE"); if (mustsetenv == JNI_FALSE) { JLI_MemFree(newargv); return; } #else JLI_MemFree(newargv); return; #endif /* SETENV_REQUIRED */ } else { /* do the same speculatively or exit */ JLI_ReportErrorMessage(JRE_ERROR2, wanted); exit(1); } #ifdef SETENV_REQUIRED if (mustsetenv) { /* * We will set the LD_LIBRARY_PATH as follows: * * o $JVMPATH (directory portion only) * o $JRE/lib/$LIBARCHNAME * o $JRE/../lib/$LIBARCHNAME * * followed by the user's previous effective LD_LIBRARY_PATH, if * any. */ #ifdef __solaris__ /* * Starting in Solaris 7, ld.so.1 supports three LD_LIBRARY_PATH * variables: * * 1. LD_LIBRARY_PATH -- used for 32 and 64 bit searches if * data-model specific variables are not set. * * 2. LD_LIBRARY_PATH_64 -- overrides and replaces LD_LIBRARY_PATH * for 64-bit binaries. * The vm uses LD_LIBRARY_PATH to set the java.library.path system * property. To shield the vm from the complication of multiple * LD_LIBRARY_PATH variables, if the appropriate data model * specific variable is set, we will act as if LD_LIBRARY_PATH had * the value of the data model specific variant and the data model * specific variant will be unset. Note that the variable for the * *wanted* data model must be used (if it is set), not simply the * current running data model. */ switch (wanted) { case 0: case 64: dmpath = getenv("LD_LIBRARY_PATH_64"); wanted = 64; break; default: JLI_ReportErrorMessage(JRE_ERROR3, __LINE__); exit(1); /* unknown value in wanted */ break; } /* * If dmpath is NULL, the relevant data model specific variable is * not set and normal LD_LIBRARY_PATH should be used. */ if (dmpath == NULL) { runpath = getenv("LD_LIBRARY_PATH"); } else { runpath = dmpath; } #else /* ! __solaris__ */ /* * If not on Solaris, assume only a single LD_LIBRARY_PATH * variable. */ runpath = getenv(LD_LIBRARY_PATH); #endif /* __solaris__ */ /* runpath contains current effective LD_LIBRARY_PATH setting */ jvmpath = JLI_StringDup(jvmpath); new_runpath_size = ((runpath != NULL) ? JLI_StrLen(runpath) : 0) + 2 * JLI_StrLen(jrepath) + 2 * JLI_StrLen(arch) + #ifdef AIX /* On AIX we additionally need 'jli' in the path because ld doesn't support $ORIGIN. */ JLI_StrLen(jrepath) + JLI_StrLen(arch) + JLI_StrLen("/lib//jli:") + #endif JLI_StrLen(jvmpath) + 52; new_runpath = JLI_MemAlloc(new_runpath_size); newpath = new_runpath + JLI_StrLen(LD_LIBRARY_PATH "="); /* * Create desired LD_LIBRARY_PATH value for target data model. */ { /* remove the name of the .so from the JVM path */ lastslash = JLI_StrRChr(jvmpath, '/'); if (lastslash) *lastslash = '\0'; sprintf(new_runpath, LD_LIBRARY_PATH "=" "%s:" "%s/lib/%s:" #ifdef AIX "%s/lib/%s/jli:" /* Needed on AIX because ld doesn't support $ORIGIN. */ #endif "%s/../lib/%s", jvmpath, jrepath, arch, #ifdef AIX jrepath, arch, #endif jrepath, arch ); /* * Check to make sure that the prefix of the current path is the * desired environment variable setting, though the RequiresSetenv * checks if the desired runpath exists, this logic does a more * comprehensive check. */ if (runpath != NULL && JLI_StrNCmp(newpath, runpath, JLI_StrLen(newpath)) == 0 && (runpath[JLI_StrLen(newpath)] == 0 || runpath[JLI_StrLen(newpath)] == ':') && (running == wanted) /* data model does not have to be changed */ #ifdef __solaris__ && (dmpath == NULL) /* data model specific variables not set */ #endif /* __solaris__ */ ) { JLI_MemFree(newargv); JLI_MemFree(new_runpath); return; } } /* * Place the desired environment setting onto the prefix of * LD_LIBRARY_PATH. Note that this prevents any possible infinite * loop of execv() because we test for the prefix, above. */ if (runpath != 0) { /* ensure storage for runpath + colon + NULL */ if ((JLI_StrLen(runpath) + 1 + 1) > new_runpath_size) { JLI_ReportErrorMessageSys(JRE_ERROR11); exit(1); } JLI_StrCat(new_runpath, ":"); JLI_StrCat(new_runpath, runpath); } if (putenv(new_runpath) != 0) { exit(1); /* problem allocating memory; LD_LIBRARY_PATH not set properly */ } /* * Unix systems document that they look at LD_LIBRARY_PATH only * once at startup, so we have to re-exec the current executable * to get the changed environment variable to have an effect. */ #ifdef __solaris__ /* * If dmpath is not NULL, remove the data model specific string * in the environment for the exec'ed child. */ if (dmpath != NULL) (void)UnsetEnv("LD_LIBRARY_PATH_64"); #endif /* __solaris */ newenvp = environ; } #endif /* SETENV_REQUIRED */ { char *newexec = execname; JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n"); (void) fflush(stdout); (void) fflush(stderr); #ifdef SETENV_REQUIRED if (mustsetenv) { execve(newexec, argv, newenvp); } else { execv(newexec, argv); } #else /* !SETENV_REQUIRED */ execv(newexec, argv); #endif /* SETENV_REQUIRED */ JLI_ReportErrorMessageSys(JRE_ERROR4, newexec); } exit(1); } }
/* * 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; }
void CreateExecutionEnvironment(int *_argc, char ***_argv, char jrepath[], jint so_jrepath, char jvmpath[], jint so_jvmpath, char **original_argv) { #ifndef GAMMA char * jvmtype; /* Find out where the JRE is that we will be using. */ if (!GetJREPath(jrepath, so_jrepath)) { ReportErrorMessage("Error: could not find Java SE Runtime Environment.", JNI_TRUE); exit(2); } /* Do this before we read jvm.cfg */ EnsureJreInstallation(jrepath); /* Find the specified JVM type */ if (ReadKnownVMs(jrepath, (char*)GetArch(), JNI_FALSE) < 1) { ReportErrorMessage("Error: no known VMs. (check for corrupt jvm.cfg file)", JNI_TRUE); exit(1); } jvmtype = CheckJvmType(_argc, _argv, JNI_FALSE); jvmpath[0] = '\0'; if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) { char * message=NULL; const char * format = "Error: no `%s' JVM at `%s'."; message = (char *)JLI_MemAlloc((strlen(format)+strlen(jvmtype)+ strlen(jvmpath)) * sizeof(char)); sprintf(message,format, jvmtype, jvmpath); ReportErrorMessage(message, JNI_TRUE); exit(4); } /* If we got here, jvmpath has been correctly initialized. */ #else /* ifndef GAMMA */ /* * gamma launcher is simpler in that it doesn't handle VM flavors, data * model, etc. Assuming everything is set-up correctly * all we need to do here is to return correct path names. See also * GetJVMPath() and GetApplicationHome(). */ { if (!GetJREPath(jrepath, so_jrepath) ) { ReportErrorMessage("Error: could not find Java SE Runtime Environment.", JNI_TRUE); exit(2); } if (!GetJVMPath(jrepath, NULL, jvmpath, so_jvmpath)) { char * message=NULL; const char * format = "Error: no JVM at `%s'."; message = (char *)JLI_MemAlloc((strlen(format)+ strlen(jvmpath)) * sizeof(char)); sprintf(message, format, jvmpath); ReportErrorMessage(message, JNI_TRUE); exit(4); } } #endif /* ifndef GAMMA */ }
/* * Given a path to a jre to execute, this routine checks if this process * is indeed that jre. If not, it exec's that jre. * * We want to actually check the paths rather than just the version string * built into the executable, so that given version specification will yield * the exact same Java environment, regardless of the version of the arbitrary * launcher we start with. */ void ExecJRE(char *jre, char **argv) { int len; char *progname; char path[MAXPATHLEN + 1]; /* * Determine the executable we are building (or in the rare case, running). */ #ifdef JAVA_ARGS /* javac, jar and friends. */ progname = "java"; #else /* java, oldjava, javaw and friends */ #ifdef PROGNAME progname = PROGNAME; #else { char *s; progname = *argv; if ((s = strrchr(progname, FILE_SEPARATOR)) != 0) { progname = s + 1; } } #endif /* PROGNAME */ #endif /* JAVA_ARGS */ /* * Resolve the real path to the currently running launcher. */ len = GetModuleFileName(NULL, path, MAXPATHLEN + 1); if (len == 0 || len > MAXPATHLEN) { ReportSysErrorMessage2( "Unable to resolve path to current %s executable: %s", progname, JNI_TRUE); exit(1); } if (_launcher_debug) { printf("ExecJRE: old: %s\n", path); printf("ExecJRE: new: %s\n", jre); } /* * If the path to the selected JRE directory is a match to the initial * portion of the path to the currently executing JRE, we have a winner! * If so, just return. (strnicmp() is the Windows equiv. of strncasecmp().) */ if (strnicmp(jre, path, strlen(jre)) == 0) return; /* I am the droid you were looking for */ /* * If this isn't the selected version, exec the selected version. */ (void)strcat(strcat(strcpy(path, jre), "\\bin\\"), progname); (void)strcat(path, ".exe"); /* * Although Windows has an execv() entrypoint, it doesn't actually * overlay a process: it can only create a new process and terminate * the old process. Therefore, any processes waiting on the initial * process wake up and they shouldn't. Hence, a chain of pseudo-zombie * processes must be retained to maintain the proper wait semantics. * Fortunately the image size of the launcher isn't too large at this * time. * * If it weren't for this semantic flaw, the code below would be ... * * execv(path, argv); * ReportErrorMessage2("Exec of %s failed\n", path, JNI_TRUE); * exit(1); * * The incorrect exec semantics could be addressed by: * * exit((int)spawnv(_P_WAIT, path, argv)); * * Unfortunately, a bug in Windows spawn/exec impementation prevents * this from completely working. All the Windows POSIX process creation * interfaces are implemented as wrappers around the native Windows * function CreateProcess(). CreateProcess() takes a single string * to specify command line options and arguments, so the POSIX routine * wrappers build a single string from the argv[] array and in the * process, any quoting information is lost. * * The solution to this to get the original command line, to process it * to remove the new multiple JRE options (if any) as was done for argv * in the common SelectVersion() routine and finally to pass it directly * to the native CreateProcess() Windows process control interface. */ { char *cmdline; char *p; char *np; char *ocl; char *ccl; char *unquoted; DWORD exitCode; STARTUPINFO si; PROCESS_INFORMATION pi; /* * The following code block gets and processes the original command * line, replacing the argv[0] equivalent in the command line with * the path to the new executable and removing the appropriate * Multiple JRE support options. Note that similar logic exists * in the platform independent SelectVersion routine, but is * replicated here due to the syntax of CreateProcess(). * * The magic "+ 4" characters added to the command line length are * 2 possible quotes around the path (argv[0]), a space after the * path and a terminating null character. */ ocl = GetCommandLine(); np = ccl = JLI_StringDup(ocl); p = nextarg(&np); /* Discard argv[0] */ cmdline = (char *)JLI_MemAlloc(strlen(path) + strlen(np) + 4); if (strchr(path, (int)' ') == NULL && strchr(path, (int)'\t') == NULL) cmdline = strcpy(cmdline, path); else cmdline = strcat(strcat(strcpy(cmdline, "\""), path), "\""); while (*np != (char)0) { /* While more command-line */ p = nextarg(&np); if (*p != (char)0) { /* If a token was isolated */ unquoted = unquote(p); if (*unquoted == '-') { /* Looks like an option */ if (strcmp(unquoted, "-classpath") == 0 || strcmp(unquoted, "-cp") == 0) { /* Unique cp syntax */ cmdline = strcat(strcat(cmdline, " "), p); p = nextarg(&np); if (*p != (char)0) /* If a token was isolated */ cmdline = strcat(strcat(cmdline, " "), p); } else if (strncmp(unquoted, "-version:", 9) != 0 && strcmp(unquoted, "-jre-restrict-search") != 0 && strcmp(unquoted, "-no-jre-restrict-search") != 0) { cmdline = strcat(strcat(cmdline, " "), p); } } else { /* End of options */ cmdline = strcat(strcat(cmdline, " "), p); cmdline = strcat(strcat(cmdline, " "), np); JLI_MemFree((void *)unquoted); break; } JLI_MemFree((void *)unquoted); } } JLI_MemFree((void *)ccl); if (_launcher_debug) { np = ccl = JLI_StringDup(cmdline); p = nextarg(&np); printf("ReExec Command: %s (%s)\n", path, p); printf("ReExec Args: %s\n", np); JLI_MemFree((void *)ccl); } (void)fflush(stdout); (void)fflush(stderr); /* * The following code is modeled after a model presented in the * Microsoft Technical Article "Moving Unix Applications to * Windows NT" (March 6, 1994) and "Creating Processes" on MSDN * (Februrary 2005). It approximates UNIX spawn semantics with * the parent waiting for termination of the child. */ memset(&si, 0, sizeof(si)); si.cb =sizeof(STARTUPINFO); memset(&pi, 0, sizeof(pi)); if (!CreateProcess((LPCTSTR)path, /* executable name */ (LPTSTR)cmdline, /* command line */ (LPSECURITY_ATTRIBUTES)NULL, /* process security attr. */ (LPSECURITY_ATTRIBUTES)NULL, /* thread security attr. */ (BOOL)TRUE, /* inherits system handles */ (DWORD)0, /* creation flags */ (LPVOID)NULL, /* environment block */ (LPCTSTR)NULL, /* current directory */ (LPSTARTUPINFO)&si, /* (in) startup information */ (LPPROCESS_INFORMATION)&pi)) { /* (out) process information */ ReportSysErrorMessage2("CreateProcess(%s, ...) failed: %s", path, JNI_TRUE); exit(1); } if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_FAILED) { if (GetExitCodeProcess(pi.hProcess, &exitCode) == FALSE) exitCode = 1; } else { ReportErrorMessage("WaitForSingleObject() failed.", JNI_TRUE); exitCode = 1; } CloseHandle(pi.hThread); CloseHandle(pi.hProcess); exit(exitCode); } }
/* * Just like JLI_ReportErrorMessage, except that it concatenates the system * error message if any, its upto the calling routine to correctly * format the separation of the messages. */ void JLI_ReportErrorMessageSys(const char *fmt, ...) { va_list vl; int save_errno = errno; DWORD errval; jboolean freeit = JNI_FALSE; char *errtext = NULL; va_start(vl, fmt); if ((errval = GetLastError()) != 0) { /* Platform SDK / DOS Error */ int n = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM| FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, errval, 0, (LPTSTR)&errtext, 0, NULL); if (errtext == NULL || n == 0) { /* Paranoia check */ errtext = ""; n = 0; } else { freeit = JNI_TRUE; if (n > 2) { /* Drop final CR, LF */ if (errtext[n - 1] == '\n') n--; if (errtext[n - 1] == '\r') n--; errtext[n] = '\0'; } } } else { /* C runtime error that has no corresponding DOS error code */ errtext = strerror(save_errno); } if (IsJavaw()) { char *message; int mlen; /* get the length of the string we need */ int len = mlen = _vscprintf(fmt, vl) + 1; if (freeit) { mlen += (int)JLI_StrLen(errtext); } message = (char *)JLI_MemAlloc(mlen); _vsnprintf(message, len, fmt, vl); message[len]='\0'; if (freeit) { JLI_StrCat(message, errtext); } MessageBox(NULL, message, "Java Virtual Machine Launcher", (MB_OK|MB_ICONSTOP|MB_APPLMODAL)); JLI_MemFree(message); } else { vfprintf(stderr, fmt, vl); if (freeit) { fprintf(stderr, "%s", errtext); } } if (freeit) { (void)LocalFree((HLOCAL)errtext); } va_end(vl); }
void CreateExecutionEnvironment(int *pargc, char ***pargv, char jrepath[], jint so_jrepath, char jvmpath[], jint so_jvmpath) { /* * First, determine if we are running the desired data model. If we * are running the desired data model, all the error messages * associated with calling GetJREPath, ReadKnownVMs, etc. should be * output. However, if we are not running the desired data model, * some of the errors should be suppressed since it is more * informative to issue an error message based on whether or not the * os/processor combination has dual mode capabilities. */ jboolean jvmpathExists; /* Compute/set the name of the executable */ SetExecname(*pargv); /* Check data model flags, and exec process, if needed */ { char *arch = (char *)GetArch(); /* like sparc or sparcv9 */ char * jvmtype = NULL; int argc = *pargc; char **argv = *pargv; int running = CURRENT_DATA_MODEL; int wanted = running; /* What data mode is being asked for? Current model is fine unless another model is asked for */ #ifdef SETENV_REQUIRED jboolean mustsetenv = JNI_FALSE; char *runpath = NULL; /* existing effective LD_LIBRARY_PATH setting */ char* new_runpath = NULL; /* desired new LD_LIBRARY_PATH string */ char* newpath = NULL; /* path on new LD_LIBRARY_PATH */ char* lastslash = NULL; char** newenvp = NULL; /* current environment */ #ifdef __solaris__ char* dmpath = NULL; /* data model specific LD_LIBRARY_PATH, Solaris only */ #endif /* __solaris__ */ #endif /* SETENV_REQUIRED */ char** newargv = NULL; int newargc = 0; /* * Starting in 1.5, all unix platforms accept the -d32 and -d64 * options. On platforms where only one data-model is supported * (e.g. ia-64 Linux), using the flag for the other data model is * an error and will terminate the program. */ { /* open new scope to declare local variables */ int i; newargv = (char **)JLI_MemAlloc((argc+1) * sizeof(char*)); newargv[newargc++] = argv[0]; /* scan for data model arguments and remove from argument list; last occurrence determines desired data model */ for (i=1; i < argc; i++) { if (JLI_StrCmp(argv[i], "-J-d64") == 0 || JLI_StrCmp(argv[i], "-d64") == 0) { wanted = 64; continue; } if (JLI_StrCmp(argv[i], "-J-d32") == 0 || JLI_StrCmp(argv[i], "-d32") == 0) { wanted = 32; continue; } newargv[newargc++] = argv[i]; if (IsJavaArgs()) { if (argv[i][0] != '-') continue; } else { if (JLI_StrCmp(argv[i], "-classpath") == 0 || JLI_StrCmp(argv[i], "-cp") == 0) { i++; if (i >= argc) break; newargv[newargc++] = argv[i]; continue; } if (argv[i][0] != '-') { i++; break; } } } /* copy rest of args [i .. argc) */ while (i < argc) { newargv[newargc++] = argv[i++]; } newargv[newargc] = NULL; /* * newargv has all proper arguments here */ argc = newargc; argv = newargv; } /* If the data model is not changing, it is an error if the jvmpath does not exist */ if (wanted == running) { /* Find out where the JRE is that we will be using. */ if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) { JLI_ReportErrorMessage(JRE_ERROR1); exit(2); } /* Find the specified JVM type */ if (ReadKnownVMs(jrepath, arch, JNI_FALSE) < 1) { JLI_ReportErrorMessage(CFG_ERROR7); exit(1); } jvmpath[0] = '\0'; jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE); if (JLI_StrCmp(jvmtype, "ERROR") == 0) { JLI_ReportErrorMessage(CFG_ERROR9); exit(4); } if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch )) { JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); exit(4); } /* * we seem to have everything we need, so without further ado * we return back, otherwise proceed to set the environment. */ #ifdef SETENV_REQUIRED mustsetenv = RequiresSetenv(wanted, jvmpath); JLI_TraceLauncher("mustsetenv: %s\n", mustsetenv ? "TRUE" : "FALSE"); if (mustsetenv == JNI_FALSE) { return; } #else return; #endif /* SETENV_REQUIRED */ } else { /* do the same speculatively or exit */ #ifdef DUAL_MODE if (running != wanted) { /* Find out where the JRE is that we will be using. */ if (!GetJREPath(jrepath, so_jrepath, GetArchPath(wanted), JNI_TRUE)) { /* give up and let other code report error message */ JLI_ReportErrorMessage(JRE_ERROR2, wanted); exit(1); } /* * Read in jvm.cfg for target data model and process vm * selection options. */ if (ReadKnownVMs(jrepath, GetArchPath(wanted), JNI_TRUE) < 1) { /* give up and let other code report error message */ JLI_ReportErrorMessage(JRE_ERROR2, wanted); exit(1); } jvmpath[0] = '\0'; jvmtype = CheckJvmType(pargc, pargv, JNI_TRUE); if (JLI_StrCmp(jvmtype, "ERROR") == 0) { JLI_ReportErrorMessage(CFG_ERROR9); exit(4); } /* exec child can do error checking on the existence of the path */ jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, GetArchPath(wanted)); #ifdef SETENV_REQUIRED mustsetenv = RequiresSetenv(wanted, jvmpath); #endif /* SETENV_REQUIRED */ } #else JLI_ReportErrorMessage(JRE_ERROR2, wanted); exit(1); #endif } #ifdef SETENV_REQUIRED if (mustsetenv) { /* * We will set the LD_LIBRARY_PATH as follows: * * o $JVMPATH (directory portion only) * o $JRE/lib/$LIBARCHNAME * o $JRE/../lib/$LIBARCHNAME * * followed by the user's previous effective LD_LIBRARY_PATH, if * any. */ #ifdef __solaris__ /* * Starting in Solaris 7, ld.so.1 supports three LD_LIBRARY_PATH * variables: * * 1. LD_LIBRARY_PATH -- used for 32 and 64 bit searches if * data-model specific variables are not set. * * 2. LD_LIBRARY_PATH_64 -- overrides and replaces LD_LIBRARY_PATH * for 64-bit binaries. * * 3. LD_LIBRARY_PATH_32 -- overrides and replaces LD_LIBRARY_PATH * for 32-bit binaries. * * The vm uses LD_LIBRARY_PATH to set the java.library.path system * property. To shield the vm from the complication of multiple * LD_LIBRARY_PATH variables, if the appropriate data model * specific variable is set, we will act as if LD_LIBRARY_PATH had * the value of the data model specific variant and the data model * specific variant will be unset. Note that the variable for the * *wanted* data model must be used (if it is set), not simply the * current running data model. */ switch (wanted) { case 0: if (running == 32) { dmpath = getenv("LD_LIBRARY_PATH_32"); wanted = 32; } else { dmpath = getenv("LD_LIBRARY_PATH_64"); wanted = 64; } break; case 32: dmpath = getenv("LD_LIBRARY_PATH_32"); break; case 64: dmpath = getenv("LD_LIBRARY_PATH_64"); break; default: JLI_ReportErrorMessage(JRE_ERROR3, __LINE__); exit(1); /* unknown value in wanted */ break; } /* * If dmpath is NULL, the relevant data model specific variable is * not set and normal LD_LIBRARY_PATH should be used. */ if (dmpath == NULL) { runpath = getenv("LD_LIBRARY_PATH"); } else { runpath = dmpath; } #else /* * If not on Solaris, assume only a single LD_LIBRARY_PATH * variable. */ runpath = getenv("LD_LIBRARY_PATH"); #endif /* __solaris__ */ /* runpath contains current effective LD_LIBRARY_PATH setting */ jvmpath = JLI_StringDup(jvmpath); new_runpath = JLI_MemAlloc(((runpath != NULL) ? JLI_StrLen(runpath) : 0) + 2 * JLI_StrLen(jrepath) + 2 * JLI_StrLen(arch) + JLI_StrLen(jvmpath) + 52); newpath = new_runpath + JLI_StrLen("LD_LIBRARY_PATH="); /* * Create desired LD_LIBRARY_PATH value for target data model. */ { /* remove the name of the .so from the JVM path */ lastslash = JLI_StrRChr(jvmpath, '/'); if (lastslash) *lastslash = '\0'; sprintf(new_runpath, "LD_LIBRARY_PATH=" "%s:" "%s/lib/%s:" "%s/../lib/%s", jvmpath, #ifdef DUAL_MODE jrepath, GetArchPath(wanted), jrepath, GetArchPath(wanted) #else jrepath, arch, jrepath, arch #endif ); /* * Check to make sure that the prefix of the current path is the * desired environment variable setting, though the RequiresSetenv * checks if the desired runpath exists, this logic does a more * comprehensive check. */ if (runpath != NULL && JLI_StrNCmp(newpath, runpath, JLI_StrLen(newpath)) == 0 && (runpath[JLI_StrLen(newpath)] == 0 || runpath[JLI_StrLen(newpath)] == ':') && (running == wanted) /* data model does not have to be changed */ #ifdef __solaris__ && (dmpath == NULL) /* data model specific variables not set */ #endif ) { return; } } /* * Place the desired environment setting onto the prefix of * LD_LIBRARY_PATH. Note that this prevents any possible infinite * loop of execv() because we test for the prefix, above. */ if (runpath != 0) { JLI_StrCat(new_runpath, ":"); JLI_StrCat(new_runpath, runpath); } if (putenv(new_runpath) != 0) { exit(1); /* problem allocating memory; LD_LIBRARY_PATH not set properly */ } /* * Unix systems document that they look at LD_LIBRARY_PATH only * once at startup, so we have to re-exec the current executable * to get the changed environment variable to have an effect. */ #ifdef __solaris__ /* * If dmpath is not NULL, remove the data model specific string * in the environment for the exec'ed child. */ if (dmpath != NULL) (void)UnsetEnv((wanted == 32) ? "LD_LIBRARY_PATH_32" : "LD_LIBRARY_PATH_64"); #endif newenvp = environ; } #endif /* SETENV_REQUIRED */ { char *newexec = execname; #ifdef DUAL_MODE /* * If the data model is being changed, the path to the * executable must be updated accordingly; the executable name * and directory the executable resides in are separate. In the * case of 32 => 64, the new bits are assumed to reside in, e.g. * "olddir/LIBARCH64NAME/execname"; in the case of 64 => 32, * the bits are assumed to be in "olddir/../execname". For example, * * olddir/sparcv9/execname * olddir/amd64/execname * * for Solaris SPARC and Linux amd64, respectively. */ if (running != wanted) { char *oldexec = JLI_StrCpy(JLI_MemAlloc(JLI_StrLen(execname) + 1), execname); char *olddir = oldexec; char *oldbase = JLI_StrRChr(oldexec, '/'); newexec = JLI_MemAlloc(JLI_StrLen(execname) + 20); *oldbase++ = 0; sprintf(newexec, "%s/%s/%s", olddir, ((wanted == 64) ? LIBARCH64NAME : ".."), oldbase); argv[0] = newexec; } #endif /* DUAL_MODE */ JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n"); (void) fflush(stdout); (void) fflush(stderr); #ifdef SETENV_REQUIRED if (mustsetenv) { execve(newexec, argv, newenvp); } else { execv(newexec, argv); } #else execv(newexec, argv); #endif /* SETENV_REQUIRED */ JLI_ReportErrorMessageSys(JRE_ERROR4, newexec); #ifdef DUAL_MODE if (running != wanted) { JLI_ReportErrorMessage(JRE_ERROR5, wanted, running); #ifdef __solaris__ #ifdef __sparc JLI_ReportErrorMessage(JRE_ERROR6); #else JLI_ReportErrorMessage(JRE_ERROR7); #endif /* __sparc */ } #endif /* __solaris__ */ #endif /* DUAL_MODE */ } exit(1); } }
void CreateExecutionEnvironment(int *pargc, char ***pargv, char jrepath[], jint so_jrepath, char jvmpath[], jint so_jvmpath, char jvmcfg[], jint so_jvmcfg) { /* * First, determine if we are running the desired data model. If we * are running the desired data model, all the error messages * associated with calling GetJREPath, ReadKnownVMs, etc. should be * output. However, if we are not running the desired data model, * some of the errors should be suppressed since it is more * informative to issue an error message based on whether or not the * os/processor combination has dual mode capabilities. */ jboolean jvmpathExists; /* Compute/set the name of the executable */ SetExecname(*pargv); /* Check data model flags, and exec process, if needed */ { char *arch = (char *)GetArch(); /* like sparc or sparcv9 */ char * jvmtype = NULL; int argc = *pargc; char **argv = *pargv; int running = CURRENT_DATA_MODEL; int wanted = running; /* What data mode is being asked for? Current model is fine unless another model is asked for */ char** newargv = NULL; int newargc = 0; /* * Starting in 1.5, all unix platforms accept the -d32 and -d64 * options. On platforms where only one data-model is supported * (e.g. ia-64 Linux), using the flag for the other data model is * an error and will terminate the program. */ { /* open new scope to declare local variables */ int i; newargv = (char **)JLI_MemAlloc((argc+1) * sizeof(char*)); newargv[newargc++] = argv[0]; /* scan for data model arguments and remove from argument list; last occurrence determines desired data model */ for (i=1; i < argc; i++) { if (JLI_StrCmp(argv[i], "-J-d64") == 0 || JLI_StrCmp(argv[i], "-d64") == 0) { wanted = 64; continue; } if (JLI_StrCmp(argv[i], "-J-d32") == 0 || JLI_StrCmp(argv[i], "-d32") == 0) { wanted = 32; continue; } newargv[newargc++] = argv[i]; if (IsJavaArgs()) { if (argv[i][0] != '-') continue; } else { if (JLI_StrCmp(argv[i], "-classpath") == 0 || JLI_StrCmp(argv[i], "-cp") == 0) { i++; if (i >= argc) break; newargv[newargc++] = argv[i]; continue; } if (argv[i][0] != '-') { i++; break; } } } /* copy rest of args [i .. argc) */ while (i < argc) { newargv[newargc++] = argv[i++]; } newargv[newargc] = NULL; /* * newargv has all proper arguments here */ argc = newargc; argv = newargv; } /* If the data model is not changing, it is an error if the jvmpath does not exist */ if (wanted == running) { /* Find out where the JRE is that we will be using. */ if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) { JLI_ReportErrorMessage(JRE_ERROR1); exit(2); } JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg", jrepath, FILESEP, FILESEP, "", ""); /* Find the specified JVM type */ if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) { JLI_ReportErrorMessage(CFG_ERROR7); exit(1); } jvmpath[0] = '\0'; jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE); if (JLI_StrCmp(jvmtype, "ERROR") == 0) { JLI_ReportErrorMessage(CFG_ERROR9); exit(4); } if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, wanted)) { JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); exit(4); } /* * Mac OS X requires the Cocoa event loop to be run on the "main" * thread. Spawn off a new thread to run main() and pass * this thread off to the Cocoa event loop. */ MacOSXStartup(argc, argv); /* * we seem to have everything we need, so without further ado * we return back, otherwise proceed to set the environment. */ return; } else { /* do the same speculatively or exit */ #if defined(DUAL_MODE) if (running != wanted) { /* Find out where the JRE is that we will be using. */ if (!GetJREPath(jrepath, so_jrepath, GetArchPath(wanted), JNI_TRUE)) { /* give up and let other code report error message */ JLI_ReportErrorMessage(JRE_ERROR2, wanted); exit(1); } JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg", jrepath, FILESEP, FILESEP, "", ""); /* * Read in jvm.cfg for target data model and process vm * selection options. */ if (ReadKnownVMs(jvmcfg, JNI_TRUE) < 1) { /* give up and let other code report error message */ JLI_ReportErrorMessage(JRE_ERROR2, wanted); exit(1); } jvmpath[0] = '\0'; jvmtype = CheckJvmType(pargc, pargv, JNI_TRUE); if (JLI_StrCmp(jvmtype, "ERROR") == 0) { JLI_ReportErrorMessage(CFG_ERROR9); exit(4); } /* exec child can do error checking on the existence of the path */ jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, GetArchPath(wanted), wanted); } #else /* ! DUAL_MODE */ JLI_ReportErrorMessage(JRE_ERROR2, wanted); exit(1); #endif /* DUAL_MODE */ } { char *newexec = execname; JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n"); (void) fflush(stdout); (void) fflush(stderr); /* * Use posix_spawn() instead of execv() on Mac OS X. * This allows us to choose which architecture the child process * should run as. */ { posix_spawnattr_t attr; size_t unused_size; pid_t unused_pid; #if defined(__i386__) || defined(__x86_64__) cpu_type_t cpu_type[] = { (wanted == 64) ? CPU_TYPE_X86_64 : CPU_TYPE_X86, (running== 64) ? CPU_TYPE_X86_64 : CPU_TYPE_X86 }; #else cpu_type_t cpu_type[] = { CPU_TYPE_ANY }; #endif /* __i386 .. */ posix_spawnattr_init(&attr); posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC); posix_spawnattr_setbinpref_np(&attr, sizeof(cpu_type) / sizeof(cpu_type_t), cpu_type, &unused_size); posix_spawn(&unused_pid, newexec, NULL, &attr, argv, environ); } JLI_ReportErrorMessageSys(JRE_ERROR4, newexec); #if defined(DUAL_MODE) if (running != wanted) { JLI_ReportErrorMessage(JRE_ERROR5, wanted, running); } #endif /* DUAL_MODE */ } exit(1); } }