void* SplashProcAddress(const char* name) { if (!hSplashLib) { int ret; char jrePath[MAXPATHLEN]; char splashPath[MAXPATHLEN]; if (!GetJREPath(jrePath, sizeof(jrePath), GetArch(), JNI_FALSE)) { JLI_ReportErrorMessage(JRE_ERROR1); return NULL; } ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s/%s", jrePath, GetArch(), SPLASHSCREEN_SO); if (ret >= (int) sizeof(splashPath)) { JLI_ReportErrorMessage(JRE_ERROR11); return NULL; } if (ret < 0) { JLI_ReportErrorMessage(JRE_ERROR13); return NULL; } hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL); JLI_TraceLauncher("Info: loaded %s\n", splashPath); } if (hSplashLib) { void* sym = dlsym(hSplashLib, name); return sym; } else { return NULL; } }
/* * Load a jvm from "jvmpath" and initialize the invocation functions. */ jboolean LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) { HINSTANCE handle; JLI_TraceLauncher("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. * */ LoadMSVCRT(); /* Load the Java VM DLL */ if ((handle = LoadLibrary(jvmpath)) == 0) { JLI_ReportErrorMessage(DLL_ERROR4, (char *)jvmpath); 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) { JLI_ReportErrorMessage(JNI_ERROR1, (char *)jvmpath); 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. * The makefiles will provide the correct lib contained in quotes in the * macro MSVCR_DLL_NAME. */ #ifdef MSVCR_DLL_NAME if (GetJREPath(crtpath, MAXPATHLEN)) { if (JLI_StrLen(crtpath) + JLI_StrLen("\\bin\\") + JLI_StrLen(MSVCR_DLL_NAME) >= MAXPATHLEN) { JLI_ReportErrorMessage(JRE_ERROR11); return JNI_FALSE; } (void)JLI_StrCat(crtpath, "\\bin\\" MSVCR_DLL_NAME); /* Add crt dll */ JLI_TraceLauncher("CRT path is %s\n", crtpath); if (_access(crtpath, 0) == 0) { if (LoadLibrary(crtpath) == 0) { JLI_ReportErrorMessage(DLL_ERROR4, crtpath); return JNI_FALSE; } } } #endif /* MSVCR_DLL_NAME */ #ifdef MSVCP_DLL_NAME if (GetJREPath(crtpath, MAXPATHLEN)) { if (JLI_StrLen(crtpath) + JLI_StrLen("\\bin\\") + JLI_StrLen(MSVCP_DLL_NAME) >= MAXPATHLEN) { JLI_ReportErrorMessage(JRE_ERROR11); return JNI_FALSE; } (void)JLI_StrCat(crtpath, "\\bin\\" MSVCP_DLL_NAME); /* Add prt dll */ JLI_TraceLauncher("PRT path is %s\n", crtpath); if (_access(crtpath, 0) == 0) { if (LoadLibrary(crtpath) == 0) { JLI_ReportErrorMessage(DLL_ERROR4, crtpath); return JNI_FALSE; } } } #endif /* MSVCP_DLL_NAME */ loaded = 1; } return JNI_TRUE; }
/* * Find path to JRE based on .exe's location or registry settings. */ jboolean GetJREPath(char *path, jint pathsize) { char javadll[MAXPATHLEN]; struct stat s; if (GetApplicationHome(path, pathsize)) { /* Is JRE co-located with the application? */ JLI_Snprintf(javadll, sizeof(javadll), "%s\\bin\\" JAVA_DLL, path); if (stat(javadll, &s) == 0) { JLI_TraceLauncher("JRE path is %s\n", path); return JNI_TRUE; } /* Does this app ship a private JRE in <apphome>\jre directory? */ JLI_Snprintf(javadll, sizeof (javadll), "%s\\jre\\bin\\" JAVA_DLL, path); if (stat(javadll, &s) == 0) { JLI_StrCat(path, "\\jre"); JLI_TraceLauncher("JRE path is %s\n", path); return JNI_TRUE; } } /* Look for a public JRE on this machine. */ if (GetPublicJREHome(path, pathsize)) { JLI_TraceLauncher("JRE path is %s\n", path); return JNI_TRUE; } JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); return JNI_FALSE; }
/* * 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; }
/* * Find path to JRE based on .exe's location or registry settings. */ static jboolean GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative) { char libjava[MAXPATHLEN]; if (GetApplicationHome(path, pathsize)) { /* Is JRE co-located with the application? */ JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/%s/" JAVA_DLL, path, arch); if (access(libjava, F_OK) == 0) { JLI_TraceLauncher("JRE path is %s\n", path); return JNI_TRUE; } /* Does the app ship a private JRE in <apphome>/jre directory? */ JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/%s/" JAVA_DLL, path, arch); if (access(libjava, F_OK) == 0) { JLI_StrCat(path, "/jre"); JLI_TraceLauncher("JRE path is %s\n", path); return JNI_TRUE; } } if (!speculative) JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); return JNI_FALSE; }
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. * This is clearly completely specific to the exact compiler version * which isn't very nice, but its hardly the only place. * No attempt to look for compiler versions in between 2003 and 2010 * as we aren't supporting building with those. */ #ifdef _MSC_VER #if _MSC_VER < 1400 #define CRT_DLL "msvcr71.dll" #endif #if _MSC_VER >= 1600 #define CRT_DLL "msvcr100.dll" #endif #ifdef CRT_DLL if (GetJREPath(crtpath, MAXPATHLEN)) { if (JLI_StrLen(crtpath) + JLI_StrLen("\\bin\\") + JLI_StrLen(CRT_DLL) >= MAXPATHLEN) { JLI_ReportErrorMessage(JRE_ERROR11); return JNI_FALSE; } (void)JLI_StrCat(crtpath, "\\bin\\" CRT_DLL); /* Add crt dll */ JLI_TraceLauncher("CRT path is %s\n", crtpath); if (_access(crtpath, 0) == 0) { if (LoadLibrary(crtpath) == 0) { JLI_ReportErrorMessage(DLL_ERROR4, crtpath); return JNI_FALSE; } } } #endif /* CRT_DLL */ #endif /* _MSC_VER */ loaded = 1; } return JNI_TRUE; }
/* * Find path to JRE based on .exe's location or registry settings. */ static jboolean GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative) { char libjava[MAXPATHLEN]; if (GetApplicationHome(path, pathsize)) { /* Is JRE co-located with the application? */ JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path); if (access(libjava, F_OK) == 0) { return JNI_TRUE; } /* ensure storage for path + /jre + NULL */ if ((JLI_StrLen(path) + 4 + 1) > pathsize) { JLI_TraceLauncher("Insufficient space to store JRE path\n"); return JNI_FALSE; } /* Does the app ship a private JRE in <apphome>/jre directory? */ JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path); if (access(libjava, F_OK) == 0) { JLI_StrCat(path, "/jre"); JLI_TraceLauncher("JRE path is %s\n", path); return JNI_TRUE; } } /* try to find ourselves instead */ Dl_info selfInfo; dladdr(&GetJREPath, &selfInfo); char *realPathToSelf = realpath(selfInfo.dli_fname, path); if (realPathToSelf != path) { return JNI_FALSE; } size_t pathLen = strlen(realPathToSelf); if (pathLen == 0) { return JNI_FALSE; } const char lastPathComponent[] = "/lib/jli/libjli.dylib"; size_t sizeOfLastPathComponent = sizeof(lastPathComponent) - 1; if (pathLen < sizeOfLastPathComponent) { return JNI_FALSE; } size_t indexOfLastPathComponent = pathLen - sizeOfLastPathComponent; if (0 == strncmp(realPathToSelf + indexOfLastPathComponent, lastPathComponent, sizeOfLastPathComponent - 1)) { realPathToSelf[indexOfLastPathComponent + 1] = '\0'; return JNI_TRUE; } if (!speculative) JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); return JNI_FALSE; }
void* SplashProcAddress(const char* name) { if (!hSplashLib) { char jrePath[PATH_MAX]; if (!GetJREPath(jrePath, sizeof(jrePath), GetArch(), JNI_FALSE)) { JLI_ReportErrorMessage(JRE_ERROR1); return NULL; } char splashPath[PATH_MAX]; const int ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s", jrePath, SPLASHSCREEN_SO); if (ret >= (int)sizeof(splashPath)) { JLI_ReportErrorMessage(JRE_ERROR11); return NULL; } if (ret < 0) { JLI_ReportErrorMessage(JRE_ERROR13); return NULL; } hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL); // It's OK if dlopen() fails. The splash screen library binary file // might have been stripped out from the JRE image to reduce its size // (e.g. on embedded platforms). if (hSplashLib) { if (!SetJavaVMValue()) { dlclose(hSplashLib); hSplashLib = NULL; } } } if (hSplashLib) { void* sym = dlsym(hSplashLib, name); return sym; } else { return NULL; } }
jboolean LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) { Dl_info dlinfo; void *libjvm; JLI_TraceLauncher("JVM path is %s\n", jvmpath); libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL); if (libjvm == NULL) { JLI_ReportErrorMessage(DLL_ERROR1, __LINE__); JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); return JNI_FALSE; } ifn->CreateJavaVM = (CreateJavaVM_t) dlsym(libjvm, "JNI_CreateJavaVM"); if (ifn->CreateJavaVM == NULL) { JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); return JNI_FALSE; } ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t) dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs"); if (ifn->GetDefaultJavaVMInitArgs == NULL) { JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); return JNI_FALSE; } ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t) dlsym(libjvm, "JNI_GetCreatedJavaVMs"); if (ifn->GetCreatedJavaVMs == NULL) { JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); return JNI_FALSE; } return JNI_TRUE; }
jclass FindBootStrapClass(JNIEnv *env, const char* classname) { if (findBootClass == NULL) { findBootClass = (FindClassFromBootLoader_t *)dlsym(RTLD_DEFAULT, "JVM_FindClassFromBootLoader"); if (findBootClass == NULL) { JLI_ReportErrorMessage(DLL_ERROR4, "JVM_FindClassFromBootLoader"); return NULL; } } return findBootClass(env, classname); }
static InvocationFunctions *GetExportedJNIFunctions() { if (sExportedJNIFunctions != NULL) return sExportedJNIFunctions; char jrePath[PATH_MAX]; jboolean gotJREPath = GetJREPath(jrePath, sizeof(jrePath), GetArch(), JNI_FALSE); if (!gotJREPath) { JLI_ReportErrorMessage("Failed to GetJREPath()"); return NULL; } char *preferredJVM = sPreferredJVMType; if (preferredJVM == NULL) { #if defined(__i386__) preferredJVM = "client"; #elif defined(__x86_64__) preferredJVM = "server"; #else #error "Unknown architecture - needs definition" #endif } char jvmPath[PATH_MAX]; jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), GetArch(), CURRENT_DATA_MODEL); if (!gotJVMPath) { JLI_ReportErrorMessage("Failed to GetJVMPath()"); return NULL; } InvocationFunctions *fxns = malloc(sizeof(InvocationFunctions)); jboolean vmLoaded = LoadJavaVM(jvmPath, fxns); if (!vmLoaded) { JLI_ReportErrorMessage("Failed to LoadJavaVM()"); return NULL; } return sExportedJNIFunctions = fxns; }
jclass FindBootStrapClass(JNIEnv *env, const char* classname) { if (findBootClass == NULL) { printf("%s[%d] [tid: %lu]: 试图获取函数[JVM_FindClassFromBootLoader]的指针(地址)...\n", __FILE__, __LINE__, pthread_self()); findBootClass = (FindClassFromBootLoader_t *)dlsym(RTLD_DEFAULT, "JVM_FindClassFromBootLoader"); if (findBootClass == NULL) { JLI_ReportErrorMessage(DLL_ERROR4, "JVM_FindClassFromBootLoader"); return NULL; } } return findBootClass(env, classname); }
/* * Find path to JRE based on .exe's location or registry settings. */ jboolean GetJREPath(char *path, jint pathsize) { char javadll[MAXPATHLEN]; struct stat s; if (GetApplicationHome(path, pathsize)) { /* Is JRE co-located with the application? */ JLI_Snprintf(javadll, sizeof(javadll), "%s\\bin\\" JAVA_DLL, path); if (stat(javadll, &s) == 0) { JLI_TraceLauncher("JRE path is %s\n", path); return JNI_TRUE; } /* ensure storage for path + \jre + NULL */ if ((JLI_StrLen(path) + 4 + 1) > (size_t) pathsize) { JLI_TraceLauncher("Insufficient space to store JRE path\n"); return JNI_FALSE; } /* Does this app ship a private JRE in <apphome>\jre directory? */ JLI_Snprintf(javadll, sizeof (javadll), "%s\\jre\\bin\\" JAVA_DLL, path); if (stat(javadll, &s) == 0) { JLI_StrCat(path, "\\jre"); JLI_TraceLauncher("JRE path is %s\n", path); return JNI_TRUE; } } /* Try getting path to JRE from path to JLI.DLL */ if (GetApplicationHomeFromDll(path, pathsize)) { JLI_Snprintf(javadll, sizeof(javadll), "%s\\bin\\" JAVA_DLL, path); if (stat(javadll, &s) == 0) { JLI_TraceLauncher("JRE path is %s\n", path); return JNI_TRUE; } } #ifdef USE_REGISTRY_LOOKUP /* Lookup public JRE using Windows registry. */ if (GetPublicJREHome(path, pathsize)) { JLI_TraceLauncher("JRE path is %s\n", path); return JNI_TRUE; } #endif JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); return JNI_FALSE; }
/* * 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; }
jclass FindBootStrapClass(JNIEnv *env, const char *classname) { HMODULE hJvm; if (findBootClass == NULL) { hJvm = GetModuleHandle(JVM_DLL); if (hJvm == NULL) return NULL; /* need to use the demangled entry point */ findBootClass = (FindClassFromBootLoader_t *)GetProcAddress(hJvm, "JVM_FindClassFromBootLoader"); if (findBootClass == NULL) { JLI_ReportErrorMessage(DLL_ERROR4, "JVM_FindClassFromBootLoader"); return NULL; } } return findBootClass(env, classname); }
/* * Find path to JRE based on .exe's location or registry settings. */ static jboolean GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative) { char libjava[MAXPATHLEN]; struct stat s; if (GetApplicationHome(path, pathsize)) { /* Is JRE co-located with the application? */ JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/%s/" JAVA_DLL, path, arch); if (access(libjava, F_OK) == 0) { JLI_TraceLauncher("JRE path is %s\n", path); return JNI_TRUE; } /* ensure storage for path + /jre + NULL */ if ((JLI_StrLen(path) + 4 + 1) > (size_t) pathsize) { JLI_TraceLauncher("Insufficient space to store JRE path\n"); return JNI_FALSE; } /* Does the app ship a private JRE in <apphome>/jre directory? */ JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/%s/" JAVA_DLL, path, arch); if (access(libjava, F_OK) == 0) { JLI_StrCat(path, "/jre"); JLI_TraceLauncher("JRE path is %s\n", path); return JNI_TRUE; } } if (GetApplicationHomeFromDll(path, pathsize)) { JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/%s/" JAVA_DLL, path, arch); if (stat(libjava, &s) == 0) { JLI_TraceLauncher("JRE path is %s\n", path); return JNI_TRUE; } } if (!speculative) JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); return JNI_FALSE; }
/* * 使用指定的jvm版本来运行java程序 * * ****************************************************************************** * 函数原型: char *realpath(const char *path, char *resolved_path); * 函数说明: 用来将参数path所指的相对路径转换成绝对路径后存于参数resolved_path所指的字符串数组或指针中 * 函数返回: 成功则返回指向resolved_path的指针,失败返回NULL,错误代码存于errno * * ****************************************************************************** * 函数原型: int execve(const char * filename,char * const argv[],char * const envp[]); * 函数说明: execve用来执行参数filename字符串所代表的文件路径,第二个参数是利用数组指针来传递给执行文件,并且需要以 * 空指针(NULL)结束,最后一个参数则为传递给执行文件的新环境变量数组.exec函数一共有六个,其中execve为内核 * 级系统调用,其他(execl,execle,execlp,execv,execvp)都是调用execve的库函数 * 函数返回: 如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中 */ void ExecJRE(char *jre, char **argv) { char wanted[PATH_MAX]; const char* progname = GetProgramName(); const char* execname = NULL; /* * 转换成绝对路径 */ if (realpath(jre, wanted) == NULL) { JLI_ReportErrorMessage(JRE_ERROR9, jre); exit(1); } /* * 获取启动当前JVM进程的命令 */ SetExecname(argv); execname = GetExecName(); if (execname == NULL) { JLI_ReportErrorMessage(JRE_ERROR10); exit(1); } /* * 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. */ if (JLI_StrNCmp(wanted, execname, JLI_StrLen(wanted)) == 0) return; /* I am the droid you were looking for */ /* * This should never happen (because of the selection code in SelectJRE), * but check for "impossibly" long path names just because buffer overruns * can be so deadly. */ if (JLI_StrLen(wanted) + JLI_StrLen(progname) + 6 > PATH_MAX) { JLI_ReportErrorMessage(JRE_ERROR11); exit(1); } /* * Construct the path and exec it. */ (void)JLI_StrCat(JLI_StrCat(wanted, "/bin/"), progname); argv[0] = JLI_StringDup(progname); if (JLI_IsTraceLauncher()) { int i; printf("ReExec Command: %s (%s)\n", wanted, argv[0]); printf("ReExec Args:"); for (i = 1; argv[i] != NULL; i++) printf(" %s", argv[i]); printf("\n"); } JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n"); //刷当前进程的标准输出/错误输出流 (void)fflush(stdout); (void)fflush(stderr); //执行新的可执行程序 execv(wanted, argv); JLI_ReportErrorMessageSys(JRE_ERROR12, wanted); exit(1); }
jboolean LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) { Dl_info dlinfo; void *libjvm; JLI_TraceLauncher("JVM path is %s\n", jvmpath); libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL); if (libjvm == NULL) { #if defined(__solaris__) && defined(__sparc) && !defined(_LP64) /* i.e. 32-bit sparc */ FILE * fp; Elf32_Ehdr elf_head; int count; int location; fp = fopen(jvmpath, "r"); if (fp == NULL) { JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); return JNI_FALSE; } /* read in elf header */ count = fread((void*)(&elf_head), sizeof(Elf32_Ehdr), 1, fp); fclose(fp); if (count < 1) { JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); return JNI_FALSE; } /* * Check for running a server vm (compiled with -xarch=v8plus) * on a stock v8 processor. In this case, the machine type in * the elf header would not be included the architecture list * provided by the isalist command, which is turn is gotten from * sysinfo. This case cannot occur on 64-bit hardware and thus * does not have to be checked for in binaries with an LP64 data * model. */ if (elf_head.e_machine == EM_SPARC32PLUS) { char buf[257]; /* recommended buffer size from sysinfo man page */ long length; char* location; length = sysinfo(SI_ISALIST, buf, 257); if (length > 0) { location = JLI_StrStr(buf, "sparcv8plus "); if (location == NULL) { JLI_ReportErrorMessage(JVM_ERROR3); return JNI_FALSE; } } } #endif JLI_ReportErrorMessage(DLL_ERROR1, __LINE__); JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); return JNI_FALSE; } ifn->CreateJavaVM = (CreateJavaVM_t) dlsym(libjvm, "JNI_CreateJavaVM"); if (ifn->CreateJavaVM == NULL) { JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); return JNI_FALSE; } ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t) dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs"); if (ifn->GetDefaultJavaVMInitArgs == NULL) { JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); return JNI_FALSE; } return JNI_TRUE; }
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); } }
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, 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); } }
/* * 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 path[MAXPATHLEN + 1]; const char *progname = GetProgramName(); /* * Resolve the real path to the currently running launcher. */ len = GetModuleFileName(NULL, path, MAXPATHLEN + 1); if (len == 0 || len > MAXPATHLEN) { JLI_ReportErrorMessageSys(JRE_ERROR9, progname); exit(1); } JLI_TraceLauncher("ExecJRE: old: %s\n", path); JLI_TraceLauncher("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. */ if (JLI_StrNCaseCmp(jre, path, JLI_StrLen(jre)) == 0) return; /* I am the droid you were looking for */ /* * If this isn't the selected version, exec the selected version. */ JLI_Snprintf(path, sizeof(path), "%s\\bin\\%s.exe", jre, progname); /* * 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); * JLI_ReportErrorMessage("Error: Exec of %s failed\n", path); * 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(JLI_StrLen(path) + JLI_StrLen(np) + 4); if (JLI_StrChr(path, (int)' ') == NULL && JLI_StrChr(path, (int)'\t') == NULL) cmdline = JLI_StrCpy(cmdline, path); else cmdline = JLI_StrCat(JLI_StrCat(JLI_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 (JLI_StrCmp(unquoted, "-classpath") == 0 || JLI_StrCmp(unquoted, "-cp") == 0) { /* Unique cp syntax */ cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), p); p = nextarg(&np); if (*p != (char)0) /* If a token was isolated */ cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), p); } else if (JLI_StrNCmp(unquoted, "-version:", 9) != 0 && JLI_StrCmp(unquoted, "-jre-restrict-search") != 0 && JLI_StrCmp(unquoted, "-no-jre-restrict-search") != 0) { cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), p); } } else { /* End of options */ cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), p); cmdline = JLI_StrCat(JLI_StrCat(cmdline, " "), np); JLI_MemFree((void *)unquoted); break; } JLI_MemFree((void *)unquoted); } } JLI_MemFree((void *)ccl); if (JLI_IsTraceLauncher()) { 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 */ JLI_ReportErrorMessageSys(SYS_ERROR1, path); exit(1); } if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_FAILED) { if (GetExitCodeProcess(pi.hProcess, &exitCode) == FALSE) exitCode = 1; } else { JLI_ReportErrorMessage(SYS_ERROR2); exitCode = 1; } CloseHandle(pi.hThread); CloseHandle(pi.hProcess); exit(exitCode); } }
static jboolean GetPublicJREHome(char *buf, jint bufsize) { HKEY key, subkey; char version[MAXPATHLEN]; /* * Note: There is a very similar implementation of the following * registry reading code in the Windows java control panel (javacp.cpl). * If there are bugs here, a similar bug probably exists there. Hence, * changes here require inspection there. */ /* Find the current version of the JRE */ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, JRE_KEY, 0, KEY_READ, &key) != 0) { JLI_ReportErrorMessage(REG_ERROR1, JRE_KEY); return JNI_FALSE; } if (!GetStringFromRegistry(key, "CurrentVersion", version, sizeof(version))) { JLI_ReportErrorMessage(REG_ERROR2, JRE_KEY); RegCloseKey(key); return JNI_FALSE; } if (JLI_StrCmp(version, GetDotVersion()) != 0) { JLI_ReportErrorMessage(REG_ERROR3, JRE_KEY, version, GetDotVersion() ); RegCloseKey(key); return JNI_FALSE; } /* Find directory where the current version is installed. */ if (RegOpenKeyEx(key, version, 0, KEY_READ, &subkey) != 0) { JLI_ReportErrorMessage(REG_ERROR1, JRE_KEY, version); RegCloseKey(key); return JNI_FALSE; } if (!GetStringFromRegistry(subkey, "JavaHome", buf, bufsize)) { JLI_ReportErrorMessage(REG_ERROR4, JRE_KEY, version); RegCloseKey(key); RegCloseKey(subkey); return JNI_FALSE; } if (JLI_IsTraceLauncher()) { char micro[MAXPATHLEN]; if (!GetStringFromRegistry(subkey, "MicroVersion", micro, sizeof(micro))) { printf("Warning: Can't read MicroVersion\n"); micro[0] = '\0'; } printf("Version major.minor.micro = %s.%s\n", version, micro); } RegCloseKey(key); RegCloseKey(subkey); return JNI_TRUE; }
void CreateExecutionEnvironment(int *pargc, char ***pargv, char *jrepath, jint so_jrepath, char *jvmpath, jint so_jvmpath) { char * jvmtype; int i = 0; int running = CURRENT_DATA_MODEL; int wanted = running; char** argv = *pargv; for (i = 0; i < *pargc ; 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; } } if (running != wanted) { JLI_ReportErrorMessage(JRE_ERROR2, wanted); exit(1); } /* Find out where the JRE is that we will be using. */ if (!GetJREPath(jrepath, so_jrepath)) { JLI_ReportErrorMessage(JRE_ERROR1); exit(2); } /* Find the specified JVM type */ if (ReadKnownVMs(jrepath, (char*)GetArch(), JNI_FALSE) < 1) { JLI_ReportErrorMessage(CFG_ERROR7); exit(1); } jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE); if (JLI_StrCmp(jvmtype, "ERROR") == 0) { JLI_ReportErrorMessage(CFG_ERROR9); exit(4); } jvmpath[0] = '\0'; if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) { JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath); exit(4); } /* If we got here, jvmpath has been correctly initialized. */ /* Check if we need preload AWT */ #ifdef ENABLE_AWT_PRELOAD argv = *pargv; for (i = 0; i < *pargc ; i++) { /* Tests the "turn on" parameter only if not set yet. */ if (awtPreloadD3D < 0) { if (GetBoolParamValue(PARAM_PRELOAD_D3D, argv[i]) == 1) { awtPreloadD3D = 1; } } /* Test parameters which can disable preloading if not already disabled. */ if (awtPreloadD3D != 0) { if (GetBoolParamValue(PARAM_NODDRAW, argv[i]) == 1 || GetBoolParamValue(PARAM_D3D, argv[i]) == 0 || GetBoolParamValue(PARAM_OPENGL, argv[i]) == 1) { awtPreloadD3D = 0; /* no need to test the rest of the parameters */ break; } } } #endif /* ENABLE_AWT_PRELOAD */ }
/* * Starts AWT preloading */ int AWTPreload(const char *funcName) { int result = -1; /* load AWT library once (if several preload function should be called) */ if (hPreloadAwt == NULL) { /* awt.dll is not loaded yet */ char libraryPath[MAXPATHLEN]; size_t jrePathLen = 0; HMODULE hJava = NULL; HMODULE hVerify = NULL; while (1) { /* awt.dll depends on jvm.dll & java.dll; * jvm.dll is already loaded, so we need only java.dll; * java.dll depends on MSVCRT lib & verify.dll. */ if (!GetJREPath(libraryPath, MAXPATHLEN)) { break; } /* save path length */ jrePathLen = JLI_StrLen(libraryPath); if (jrePathLen + JLI_StrLen("\\bin\\verify.dll") >= MAXPATHLEN) { /* jre path is too long, the library path will not fit there; * report and abort preloading */ JLI_ReportErrorMessage(JRE_ERROR11); break; } /* load msvcrt 1st */ LoadMSVCRT(); /* load verify.dll */ JLI_StrCat(libraryPath, "\\bin\\verify.dll"); hVerify = LoadLibrary(libraryPath); if (hVerify == NULL) { break; } /* restore jrePath */ libraryPath[jrePathLen] = 0; /* load java.dll */ JLI_StrCat(libraryPath, "\\bin\\" JAVA_DLL); hJava = LoadLibrary(libraryPath); if (hJava == NULL) { break; } /* restore jrePath */ libraryPath[jrePathLen] = 0; /* load awt.dll */ JLI_StrCat(libraryPath, "\\bin\\awt.dll"); hPreloadAwt = LoadLibrary(libraryPath); if (hPreloadAwt == NULL) { break; } /* get "preloadStop" func ptr */ fnPreloadStop = (FnPreloadStop *)GetProcAddress(hPreloadAwt, "preloadStop"); break; } } if (hPreloadAwt != NULL) { FnPreloadStart *fnInit = (FnPreloadStart *)GetProcAddress(hPreloadAwt, funcName); if (fnInit != NULL) { /* don't forget to stop preloading */ awtPreloaded = 1; result = fnInit(); } } return result; }