Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/bin/java_md_solinux.c
32285 views
/*1* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include "java.h"26#include "jvm_md.h"27#include <dirent.h>28#include <dlfcn.h>29#include <fcntl.h>30#include <inttypes.h>31#include <stdio.h>32#include <string.h>33#include <stdlib.h>34#include <sys/stat.h>35#include <unistd.h>36#include <sys/types.h>37#include "manifest_info.h"38#include "version_comp.h"394041#define JVM_DLL "libjvm.so"42#define JAVA_DLL "libjava.so"43#ifdef AIX44#define LD_LIBRARY_PATH "LIBPATH"45#else46#define LD_LIBRARY_PATH "LD_LIBRARY_PATH"47#endif4849/* help jettison the LD_LIBRARY_PATH settings in the future */50#ifndef SETENV_REQUIRED51#define SETENV_REQUIRED52#endif53/*54* If a processor / os combination has the ability to run binaries of55* two data models and cohabitation of jre/jdk bits with both data56* models is supported, then DUAL_MODE is defined. When DUAL_MODE is57* defined, the architecture names for the narrow and wide version of58* the architecture are defined in LIBARCH64NAME and LIBARCH32NAME.59* Currently only Solaris on sparc/sparcv9 and i586/amd64 is DUAL_MODE;60* linux i586/amd64 could be defined as DUAL_MODE but that is not the61* current policy.62*/6364#ifdef __solaris__65# ifndef LIBARCH32NAME66# error "The macro LIBARCH32NAME was not defined on the compile line"67# endif68# ifndef LIBARCH64NAME69# error "The macro LIBARCH64NAME was not defined on the compile line"70# endif71# include <sys/systeminfo.h>72# include <sys/elf.h>73# include <stdio.h>74#endif7576/*77* Flowchart of launcher execs and options processing on unix78*79* The selection of the proper vm shared library to open depends on80* several classes of command line options, including vm "flavor"81* options (-client, -server) and the data model options, -d32 and82* -d64, as well as a version specification which may have come from83* the command line or from the manifest of an executable jar file.84* The vm selection options are not passed to the running85* virtual machine; they must be screened out by the launcher.86*87* The version specification (if any) is processed first by the88* platform independent routine SelectVersion. This may result in89* the exec of the specified launcher version.90*91* Previously the launcher modified the LD_LIBRARY_PATH appropriately for the92* desired data model path, regardless if data models matched or not. The93* launcher subsequently exec'ed the desired executable, in order to make the94* LD_LIBRARY_PATH path available, for the runtime linker.95*96* Now, in most cases,the launcher will dlopen the target libjvm.so. All97* required libraries are loaded by the runtime linker, using the98* $RPATH/$ORIGIN baked into the shared libraries at compile time. Therefore,99* in most cases, the launcher will only exec, if the data models are100* mismatched, and will not set any environment variables, regardless of the101* data models.102*103* However, if the environment contains a LD_LIBRARY_PATH, this will cause the104* launcher to inspect the LD_LIBRARY_PATH. The launcher will check105* a. if the LD_LIBRARY_PATH's first component is the the path to the desired106* libjvm.so107* b. if any other libjvm.so is found in any of the paths.108* If case b is true, then the launcher will set the LD_LIBRARY_PATH to the109* desired JRE and reexec, in order to propagate the environment.110*111* Main112* (incoming argv)113* |114* \|/115* SelectVersion116* (selects the JRE version, note: not data model)117* |118* \|/119* CreateExecutionEnvironment120* (determines desired data model)121* |122* |123* \|/124* Have Desired Model ? --> NO --> Is Dual-Mode ? --> NO --> Exit(with error)125* | |126* | |127* | \|/128* | YES129* | |130* | |131* | \|/132* | CheckJvmType133* | (removes -client, -server etc.)134* | |135* | |136* \|/ \|/137* YES Find the desired executable/library138* | |139* | |140* \|/ \|/141* CheckJvmType RequiresSetenv142* (removes -client, -server, etc.)143* |144* |145* \|/146* TranslateDashJArgs...147* (Prepare to pass args to vm)148* |149* |150* \|/151* ParseArguments152* (removes -d32 and -d64 if any,153* processes version options,154* creates argument list for vm,155* etc.)156* |157* |158* \|/159* RequiresSetenv160* Is LD_LIBRARY_PATH161* and friends set ? --> NO --> Have Desired Model ? NO --> Re-exec --> Main162* YES YES --> Continue163* |164* |165* \|/166* Path is desired JRE ? YES --> Have Desired Model ? NO --> Re-exec --> Main167* NO YES --> Continue168* |169* |170* \|/171* Paths have well known172* jvm paths ? --> NO --> Have Desired Model ? NO --> Re-exec --> Main173* YES YES --> Continue174* |175* |176* \|/177* Does libjvm.so exit178* in any of them ? --> NO --> Have Desired Model ? NO --> Re-exec --> Main179* YES YES --> Continue180* |181* |182* \|/183* Set the LD_LIBRARY_PATH184* |185* |186* \|/187* Re-exec188* |189* |190* \|/191* Main192*/193194#define GetArch() GetArchPath(CURRENT_DATA_MODEL)195196/* Store the name of the executable once computed */197static char *execname = NULL;198199/*200* execname accessor from other parts of platform dependent logic201*/202const char *203GetExecName() {204return execname;205}206207const char *208GetArchPath(int nbits)209{210switch(nbits) {211#ifdef DUAL_MODE212case 32:213return LIBARCH32NAME;214case 64:215return LIBARCH64NAME;216#endif /* DUAL_MODE */217default:218return LIBARCHNAME;219}220}221222#ifdef SETENV_REQUIRED223static jboolean224JvmExists(const char *path) {225char tmp[PATH_MAX + 1];226struct stat statbuf;227JLI_Snprintf(tmp, PATH_MAX, "%s/%s", path, JVM_DLL);228if (stat(tmp, &statbuf) == 0) {229return JNI_TRUE;230}231return JNI_FALSE;232}233/*234* contains a lib/$LIBARCH/{server,client}/libjvm.so ?235*/236static jboolean237ContainsLibJVM(int wanted, const char *env) {238char clientPattern[PATH_MAX + 1];239char serverPattern[PATH_MAX + 1];240char *envpath;241char *path;242char* save_ptr = NULL;243jboolean clientPatternFound;244jboolean serverPatternFound;245246/* fastest path */247if (env == NULL) {248return JNI_FALSE;249}250251/* the usual suspects */252JLI_Snprintf(clientPattern, PATH_MAX, "lib/%s/client", GetArchPath(wanted));253JLI_Snprintf(serverPattern, PATH_MAX, "lib/%s/server", GetArchPath(wanted));254255/* to optimize for time, test if any of our usual suspects are present. */256clientPatternFound = JLI_StrStr(env, clientPattern) != NULL;257serverPatternFound = JLI_StrStr(env, serverPattern) != NULL;258if (clientPatternFound == JNI_FALSE && serverPatternFound == JNI_FALSE) {259return JNI_FALSE;260}261262/*263* we have a suspicious path component, check if it contains a libjvm.so264*/265envpath = JLI_StringDup(env);266for (path = strtok_r(envpath, ":", &save_ptr); path != NULL; path = strtok_r(NULL, ":", &save_ptr)) {267if (clientPatternFound && JLI_StrStr(path, clientPattern) != NULL) {268if (JvmExists(path)) {269JLI_MemFree(envpath);270return JNI_TRUE;271}272}273if (serverPatternFound && JLI_StrStr(path, serverPattern) != NULL) {274if (JvmExists(path)) {275JLI_MemFree(envpath);276return JNI_TRUE;277}278}279}280JLI_MemFree(envpath);281return JNI_FALSE;282}283284/*285* Test whether the environment variable needs to be set, see flowchart.286*/287static jboolean288RequiresSetenv(int wanted, const char *jvmpath) {289char jpath[PATH_MAX + 1];290char *llp;291char *dmllp = NULL;292char *p; /* a utility pointer */293294#ifdef AIX295/* We always have to set the LIBPATH on AIX because ld doesn't support $ORIGIN. */296return JNI_TRUE;297#endif298299llp = getenv("LD_LIBRARY_PATH");300#ifdef __solaris__301dmllp = (CURRENT_DATA_MODEL == 32)302? getenv("LD_LIBRARY_PATH_32")303: getenv("LD_LIBRARY_PATH_64");304#endif /* __solaris__ */305/* no environment variable is a good environment variable */306if (llp == NULL && dmllp == NULL) {307return JNI_FALSE;308}309#ifdef __linux310/*311* On linux, if a binary is running as sgid or suid, glibc sets312* LD_LIBRARY_PATH to the empty string for security purposes. (In contrast,313* on Solaris the LD_LIBRARY_PATH variable for a privileged binary does not314* lose its settings; but the dynamic linker does apply more scrutiny to the315* path.) The launcher uses the value of LD_LIBRARY_PATH to prevent an exec316* loop, here and further downstream. Therefore, if we are running sgid or317* suid, this function's setting of LD_LIBRARY_PATH will be ineffective and318* we should case a return from the calling function. Getting the right319* libraries will be handled by the RPATH. In reality, this check is320* redundant, as the previous check for a non-null LD_LIBRARY_PATH will321* return back to the calling function forthwith, it is left here to safe322* guard against any changes, in the glibc's existing security policy.323*/324if ((getgid() != getegid()) || (getuid() != geteuid())) {325return JNI_FALSE;326}327#endif /* __linux */328329/*330* Prevent recursions. Since LD_LIBRARY_PATH is the one which will be set by331* previous versions of the JRE, thus it is the only path that matters here.332* So we check to see if the desired JRE is set.333*/334JLI_StrNCpy(jpath, jvmpath, PATH_MAX);335p = JLI_StrRChr(jpath, '/');336*p = '\0';337if (llp != NULL && JLI_StrNCmp(llp, jpath, JLI_StrLen(jpath)) == 0) {338return JNI_FALSE;339}340341/* scrutinize all the paths further */342if (llp != NULL && ContainsLibJVM(wanted, llp)) {343return JNI_TRUE;344}345if (dmllp != NULL && ContainsLibJVM(wanted, dmllp)) {346return JNI_TRUE;347}348return JNI_FALSE;349}350#endif /* SETENV_REQUIRED */351352void353CreateExecutionEnvironment(int *pargc, char ***pargv,354char jrepath[], jint so_jrepath,355char jvmpath[], jint so_jvmpath,356char jvmcfg[], jint so_jvmcfg) {357/*358* First, determine if we are running the desired data model. If we359* are running the desired data model, all the error messages360* associated with calling GetJREPath, ReadKnownVMs, etc. should be361* output. However, if we are not running the desired data model,362* some of the errors should be suppressed since it is more363* informative to issue an error message based on whether or not the364* os/processor combination has dual mode capabilities.365*/366jboolean jvmpathExists;367368/* Compute/set the name of the executable */369SetExecname(*pargv);370371/* Check data model flags, and exec process, if needed */372{373char *arch = (char *)GetArch(); /* like sparc or sparcv9 */374char * jvmtype = NULL;375int argc = *pargc;376char **argv = *pargv;377int running = CURRENT_DATA_MODEL;378379int wanted = running; /* What data mode is being380asked for? Current model is381fine unless another model382is asked for */383#ifdef SETENV_REQUIRED384jboolean mustsetenv = JNI_FALSE;385char *runpath = NULL; /* existing effective LD_LIBRARY_PATH setting */386char* new_runpath = NULL; /* desired new LD_LIBRARY_PATH string */387char* newpath = NULL; /* path on new LD_LIBRARY_PATH */388char* lastslash = NULL;389char** newenvp = NULL; /* current environment */390#ifdef __solaris__391char* dmpath = NULL; /* data model specific LD_LIBRARY_PATH,392Solaris only */393#endif /* __solaris__ */394#endif /* SETENV_REQUIRED */395396char** newargv = NULL;397int newargc = 0;398399/*400* Starting in 1.5, all unix platforms accept the -d32 and -d64401* options. On platforms where only one data-model is supported402* (e.g. ia-64 Linux), using the flag for the other data model is403* an error and will terminate the program.404*/405406{ /* open new scope to declare local variables */407int i;408409newargv = (char **)JLI_MemAlloc((argc+1) * sizeof(char*));410newargv[newargc++] = argv[0];411412/* scan for data model arguments and remove from argument list;413last occurrence determines desired data model */414for (i=1; i < argc; i++) {415416if (JLI_StrCmp(argv[i], "-J-d64") == 0 || JLI_StrCmp(argv[i], "-d64") == 0) {417wanted = 64;418continue;419}420if (JLI_StrCmp(argv[i], "-J-d32") == 0 || JLI_StrCmp(argv[i], "-d32") == 0) {421wanted = 32;422continue;423}424newargv[newargc++] = argv[i];425426if (IsJavaArgs()) {427if (argv[i][0] != '-') continue;428} else {429if (JLI_StrCmp(argv[i], "-classpath") == 0 || JLI_StrCmp(argv[i], "-cp") == 0) {430i++;431if (i >= argc) break;432newargv[newargc++] = argv[i];433continue;434}435if (argv[i][0] != '-') { i++; break; }436}437}438439/* copy rest of args [i .. argc) */440while (i < argc) {441newargv[newargc++] = argv[i++];442}443newargv[newargc] = NULL;444445/*446* newargv has all proper arguments here447*/448449argc = newargc;450argv = newargv;451}452453/* If the data model is not changing, it is an error if the454jvmpath does not exist */455if (wanted == running) {456/* Find out where the JRE is that we will be using. */457if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) {458JLI_ReportErrorMessage(JRE_ERROR1);459exit(2);460}461JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg",462jrepath, FILESEP, FILESEP, arch, FILESEP);463/* Find the specified JVM type */464if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {465JLI_ReportErrorMessage(CFG_ERROR7);466exit(1);467}468469jvmpath[0] = '\0';470jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE);471if (JLI_StrCmp(jvmtype, "ERROR") == 0) {472JLI_ReportErrorMessage(CFG_ERROR9);473exit(4);474}475476if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, 0 )) {477JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);478exit(4);479}480/*481* we seem to have everything we need, so without further ado482* we return back, otherwise proceed to set the environment.483*/484#ifdef SETENV_REQUIRED485mustsetenv = RequiresSetenv(wanted, jvmpath);486JLI_TraceLauncher("mustsetenv: %s\n", mustsetenv ? "TRUE" : "FALSE");487488if (mustsetenv == JNI_FALSE) {489JLI_MemFree(newargv);490return;491}492#else493JLI_MemFree(newargv);494return;495#endif /* SETENV_REQUIRED */496} else { /* do the same speculatively or exit */497#ifdef DUAL_MODE498if (running != wanted) {499/* Find out where the JRE is that we will be using. */500if (!GetJREPath(jrepath, so_jrepath, GetArchPath(wanted), JNI_TRUE)) {501/* give up and let other code report error message */502JLI_ReportErrorMessage(JRE_ERROR2, wanted);503exit(1);504}505JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg",506jrepath, FILESEP, FILESEP, GetArchPath(wanted), FILESEP);507/*508* Read in jvm.cfg for target data model and process vm509* selection options.510*/511if (ReadKnownVMs(jvmcfg, JNI_TRUE) < 1) {512/* give up and let other code report error message */513JLI_ReportErrorMessage(JRE_ERROR2, wanted);514exit(1);515}516jvmpath[0] = '\0';517jvmtype = CheckJvmType(pargc, pargv, JNI_TRUE);518if (JLI_StrCmp(jvmtype, "ERROR") == 0) {519JLI_ReportErrorMessage(CFG_ERROR9);520exit(4);521}522523/* exec child can do error checking on the existence of the path */524jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, GetArchPath(wanted), 0);525#ifdef SETENV_REQUIRED526mustsetenv = RequiresSetenv(wanted, jvmpath);527#endif /* SETENV_REQUIRED */528}529#else /* ! DUALMODE */530JLI_ReportErrorMessage(JRE_ERROR2, wanted);531exit(1);532#endif /* DUAL_MODE */533}534#ifdef SETENV_REQUIRED535if (mustsetenv) {536/*537* We will set the LD_LIBRARY_PATH as follows:538*539* o $JVMPATH (directory portion only)540* o $JRE/lib/$LIBARCHNAME541* o $JRE/../lib/$LIBARCHNAME542*543* followed by the user's previous effective LD_LIBRARY_PATH, if544* any.545*/546547#ifdef __solaris__548/*549* Starting in Solaris 7, ld.so.1 supports three LD_LIBRARY_PATH550* variables:551*552* 1. LD_LIBRARY_PATH -- used for 32 and 64 bit searches if553* data-model specific variables are not set.554*555* 2. LD_LIBRARY_PATH_64 -- overrides and replaces LD_LIBRARY_PATH556* for 64-bit binaries.557*558* 3. LD_LIBRARY_PATH_32 -- overrides and replaces LD_LIBRARY_PATH559* for 32-bit binaries.560*561* The vm uses LD_LIBRARY_PATH to set the java.library.path system562* property. To shield the vm from the complication of multiple563* LD_LIBRARY_PATH variables, if the appropriate data model564* specific variable is set, we will act as if LD_LIBRARY_PATH had565* the value of the data model specific variant and the data model566* specific variant will be unset. Note that the variable for the567* *wanted* data model must be used (if it is set), not simply the568* current running data model.569*/570571switch (wanted) {572case 0:573if (running == 32) {574dmpath = getenv("LD_LIBRARY_PATH_32");575wanted = 32;576} else {577dmpath = getenv("LD_LIBRARY_PATH_64");578wanted = 64;579}580break;581582case 32:583dmpath = getenv("LD_LIBRARY_PATH_32");584break;585586case 64:587dmpath = getenv("LD_LIBRARY_PATH_64");588break;589590default:591JLI_ReportErrorMessage(JRE_ERROR3, __LINE__);592exit(1); /* unknown value in wanted */593break;594}595596/*597* If dmpath is NULL, the relevant data model specific variable is598* not set and normal LD_LIBRARY_PATH should be used.599*/600if (dmpath == NULL) {601runpath = getenv("LD_LIBRARY_PATH");602} else {603runpath = dmpath;604}605#else /* ! __solaris__ */606/*607* If not on Solaris, assume only a single LD_LIBRARY_PATH608* variable.609*/610runpath = getenv(LD_LIBRARY_PATH);611#endif /* __solaris__ */612613/* runpath contains current effective LD_LIBRARY_PATH setting */614615jvmpath = JLI_StringDup(jvmpath);616size_t new_runpath_size = ((runpath != NULL) ? JLI_StrLen(runpath) : 0) +6172 * JLI_StrLen(jrepath) + 2 * JLI_StrLen(arch) +618#ifdef AIX619/* On AIX we additionally need 'jli' in the path because ld doesn't support $ORIGIN. */620JLI_StrLen(jrepath) + JLI_StrLen(arch) + JLI_StrLen("/lib//jli:") +621#endif622JLI_StrLen(jvmpath) + 52;623new_runpath = JLI_MemAlloc(new_runpath_size);624newpath = new_runpath + JLI_StrLen(LD_LIBRARY_PATH "=");625626627/*628* Create desired LD_LIBRARY_PATH value for target data model.629*/630{631/* remove the name of the .so from the JVM path */632lastslash = JLI_StrRChr(jvmpath, '/');633if (lastslash)634*lastslash = '\0';635636sprintf(new_runpath, LD_LIBRARY_PATH "="637"%s:"638"%s/lib/%s:"639#ifdef AIX640"%s/lib/%s/jli:" /* Needed on AIX because ld doesn't support $ORIGIN. */641#endif642"%s/../lib/%s",643jvmpath,644#ifdef DUAL_MODE645jrepath, GetArchPath(wanted),646jrepath, GetArchPath(wanted)647#else /* !DUAL_MODE */648jrepath, arch,649#ifdef AIX650jrepath, arch,651#endif652jrepath, arch653#endif /* DUAL_MODE */654);655656657/*658* Check to make sure that the prefix of the current path is the659* desired environment variable setting, though the RequiresSetenv660* checks if the desired runpath exists, this logic does a more661* comprehensive check.662*/663if (runpath != NULL &&664JLI_StrNCmp(newpath, runpath, JLI_StrLen(newpath)) == 0 &&665(runpath[JLI_StrLen(newpath)] == 0 || runpath[JLI_StrLen(newpath)] == ':') &&666(running == wanted) /* data model does not have to be changed */667#ifdef __solaris__668&& (dmpath == NULL) /* data model specific variables not set */669#endif /* __solaris__ */670) {671JLI_MemFree(newargv);672JLI_MemFree(new_runpath);673return;674}675}676677/*678* Place the desired environment setting onto the prefix of679* LD_LIBRARY_PATH. Note that this prevents any possible infinite680* loop of execv() because we test for the prefix, above.681*/682if (runpath != 0) {683/* ensure storage for runpath + colon + NULL */684if ((JLI_StrLen(runpath) + 1 + 1) > new_runpath_size) {685JLI_ReportErrorMessageSys(JRE_ERROR11);686exit(1);687}688JLI_StrCat(new_runpath, ":");689JLI_StrCat(new_runpath, runpath);690}691692if (putenv(new_runpath) != 0) {693exit(1); /* problem allocating memory; LD_LIBRARY_PATH not set694properly */695}696697/*698* Unix systems document that they look at LD_LIBRARY_PATH only699* once at startup, so we have to re-exec the current executable700* to get the changed environment variable to have an effect.701*/702703#ifdef __solaris__704/*705* If dmpath is not NULL, remove the data model specific string706* in the environment for the exec'ed child.707*/708if (dmpath != NULL)709(void)UnsetEnv((wanted == 32) ? "LD_LIBRARY_PATH_32" : "LD_LIBRARY_PATH_64");710#endif /* __solaris */711712newenvp = environ;713}714#endif /* SETENV_REQUIRED */715{716char *newexec = execname;717#ifdef DUAL_MODE718/*719* If the data model is being changed, the path to the720* executable must be updated accordingly; the executable name721* and directory the executable resides in are separate. In the722* case of 32 => 64, the new bits are assumed to reside in, e.g.723* "olddir/LIBARCH64NAME/execname"; in the case of 64 => 32,724* the bits are assumed to be in "olddir/../execname". For example,725*726* olddir/sparcv9/execname727* olddir/amd64/execname728*729* for Solaris SPARC and Linux amd64, respectively.730*/731732if (running != wanted) {733char *oldexec = JLI_StrCpy(JLI_MemAlloc(JLI_StrLen(execname) + 1), execname);734char *olddir = oldexec;735char *oldbase = JLI_StrRChr(oldexec, '/');736737738newexec = JLI_MemAlloc(JLI_StrLen(execname) + 20);739*oldbase++ = 0;740sprintf(newexec, "%s/%s/%s", olddir,741((wanted == 64) ? LIBARCH64NAME : ".."), oldbase);742argv[0] = newexec;743}744#endif /* DUAL_MODE */745JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n");746(void) fflush(stdout);747(void) fflush(stderr);748#ifdef SETENV_REQUIRED749if (mustsetenv) {750execve(newexec, argv, newenvp);751} else {752execv(newexec, argv);753}754#else /* !SETENV_REQUIRED */755execv(newexec, argv);756#endif /* SETENV_REQUIRED */757JLI_ReportErrorMessageSys(JRE_ERROR4, newexec);758759#ifdef DUAL_MODE760if (running != wanted) {761JLI_ReportErrorMessage(JRE_ERROR5, wanted, running);762#ifdef __solaris__763#ifdef __sparc764JLI_ReportErrorMessage(JRE_ERROR6);765#else /* ! __sparc__ */766JLI_ReportErrorMessage(JRE_ERROR7);767#endif /* __sparc */768#endif /* __solaris__ */769}770#endif /* DUAL_MODE */771772}773exit(1);774}775}776777/*778* On Solaris VM choosing is done by the launcher (java.c),779* bitsWanted is used by MacOSX, on Solaris and Linux this.780* parameter is unused.781*/782static jboolean783GetJVMPath(const char *jrepath, const char *jvmtype,784char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)785{786struct stat s;787788if (JLI_StrChr(jvmtype, '/')) {789JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);790} else {791JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/%s/" JVM_DLL, jrepath, arch, jvmtype);792}793794JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);795796if (stat(jvmpath, &s) == 0) {797JLI_TraceLauncher("yes.\n");798return JNI_TRUE;799} else {800JLI_TraceLauncher("no.\n");801return JNI_FALSE;802}803}804805/*806* Find path to JRE based on .exe's location or registry settings.807*/808static jboolean809GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)810{811char libjava[MAXPATHLEN];812813if (GetApplicationHome(path, pathsize)) {814/* Is JRE co-located with the application? */815JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/%s/" JAVA_DLL, path, arch);816if (access(libjava, F_OK) == 0) {817JLI_TraceLauncher("JRE path is %s\n", path);818return JNI_TRUE;819}820/* ensure storage for path + /jre + NULL */821if ((JLI_StrLen(path) + 4 + 1) > pathsize) {822JLI_TraceLauncher("Insufficient space to store JRE path\n");823return JNI_FALSE;824}825/* Does the app ship a private JRE in <apphome>/jre directory? */826JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/%s/" JAVA_DLL, path, arch);827if (access(libjava, F_OK) == 0) {828JLI_StrCat(path, "/jre");829JLI_TraceLauncher("JRE path is %s\n", path);830return JNI_TRUE;831}832}833834if (!speculative)835JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);836return JNI_FALSE;837}838839jboolean840LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)841{842void *libjvm;843844JLI_TraceLauncher("JVM path is %s\n", jvmpath);845846libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);847if (libjvm == NULL) {848#if defined(__solaris__) && defined(__sparc) && !defined(_LP64) /* i.e. 32-bit sparc */849FILE * fp;850Elf32_Ehdr elf_head;851int count;852int location;853854fp = fopen(jvmpath, "r");855if (fp == NULL) {856JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());857return JNI_FALSE;858}859860/* read in elf header */861count = fread((void*)(&elf_head), sizeof(Elf32_Ehdr), 1, fp);862fclose(fp);863if (count < 1) {864JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());865return JNI_FALSE;866}867868/*869* Check for running a server vm (compiled with -xarch=v8plus)870* on a stock v8 processor. In this case, the machine type in871* the elf header would not be included the architecture list872* provided by the isalist command, which is turn is gotten from873* sysinfo. This case cannot occur on 64-bit hardware and thus874* does not have to be checked for in binaries with an LP64 data875* model.876*/877if (elf_head.e_machine == EM_SPARC32PLUS) {878char buf[257]; /* recommended buffer size from sysinfo man879page */880long length;881char* location;882883length = sysinfo(SI_ISALIST, buf, 257);884if (length > 0) {885location = JLI_StrStr(buf, "sparcv8plus ");886if (location == NULL) {887JLI_ReportErrorMessage(JVM_ERROR3);888return JNI_FALSE;889}890}891}892#endif893JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);894JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());895return JNI_FALSE;896}897898ifn->CreateJavaVM = (CreateJavaVM_t)899dlsym(libjvm, "JNI_CreateJavaVM");900if (ifn->CreateJavaVM == NULL) {901JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());902return JNI_FALSE;903}904905ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)906dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");907if (ifn->GetDefaultJavaVMInitArgs == NULL) {908JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());909return JNI_FALSE;910}911912ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)913dlsym(libjvm, "JNI_GetCreatedJavaVMs");914if (ifn->GetCreatedJavaVMs == NULL) {915JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());916return JNI_FALSE;917}918919return JNI_TRUE;920}921922/*923* Compute the name of the executable924*925* In order to re-exec securely we need the absolute path of the926* executable. On Solaris getexecname(3c) may not return an absolute927* path so we use dladdr to get the filename of the executable and928* then use realpath to derive an absolute path. From Solaris 9929* onwards the filename returned in DL_info structure from dladdr is930* an absolute pathname so technically realpath isn't required.931* On Linux we read the executable name from /proc/self/exe.932* As a fallback, and for platforms other than Solaris and Linux,933* we use FindExecName to compute the executable name.934*/935const char*936SetExecname(char **argv)937{938char* exec_path = NULL;939#if defined(__solaris__)940{941Dl_info dlinfo;942int (*fptr)();943944fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");945if (fptr == NULL) {946JLI_ReportErrorMessage(DLL_ERROR3, dlerror());947return JNI_FALSE;948}949950if (dladdr((void*)fptr, &dlinfo)) {951char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1);952if (resolved != NULL) {953exec_path = realpath(dlinfo.dli_fname, resolved);954if (exec_path == NULL) {955JLI_MemFree(resolved);956}957}958}959}960#elif defined(__ANDROID__)961char *__java_home = getenv("JAVA_HOME");962// From http://hg.openjdk.java.net/mobile/jdk9/jdk/file/17bb8a98d5e3/src/java.base/unix/native/libjli/java_md_solinux.c#l844963/* For Android, 'self' would point to /system/bin/app_process964* since we are really executing a Dalvik program at this point.965* argv[0] points to the Dalvik application name and we set the966* path to __java_home.967*/968char buf[PATH_MAX+1];969char *p = NULL;970if ((p = JLI_StrRChr(argv[0], '/')) != 0) {971/* may be running from command line */972p++;973if ((JLI_StrLen(p) == 4) && JLI_StrCmp(p, "java") == 0) {974/* started as 'java'. Must be command line */975JLI_TraceLauncher("SetExecName maybe command line = %s\n", argv[0]);976if (*argv[0] != '/') {977char *curdir = NULL;978/* get absolute path */979getcwd(buf, PATH_MAX);980curdir = JLI_StringDup(buf);981JLI_Snprintf(buf, PATH_MAX, "%s/%s", curdir, argv[0]);982JLI_MemFree(curdir);983} else {984JLI_Snprintf(buf, PATH_MAX, "%s", argv[0]);985}986} else {987/* Not command line, see if __java_home set */988if (__java_home != NULL) {989JLI_TraceLauncher("SetExecName not java = %s\n", __java_home);990JLI_Snprintf(buf, PATH_MAX, "%s/bin/java", __java_home);991} else {992/* Fake it as best we can or should we punt? */993JLI_TraceLauncher("SetExecName fake it = %s\n", argv[0]);994JLI_Snprintf(buf, PATH_MAX, "/data/data/%s/storage/jvm/bin/java",995argv[0]);996}997}998} else {999/* Not started as 'java', see if __java_home set */1000if (__java_home != NULL) {1001JLI_TraceLauncher("SetExecName not command line = %s\n", __java_home);1002JLI_Snprintf(buf, PATH_MAX, "%s/bin/java", __java_home);1003} else {1004/* Fake it as best we can or should we punt? */1005JLI_TraceLauncher("SetExecName fake it 2 = %s\n", argv[0]);1006JLI_Snprintf(buf, PATH_MAX, "/data/data/%s/storage/jvm/bin/java",1007argv[0]);1008}1009}1010exec_path = JLI_StringDup(buf);1011#elif defined(__linux__)1012{1013const char* self = "/proc/self/exe";1014char buf[PATH_MAX+1];1015int len = readlink(self, buf, PATH_MAX);1016if (len >= 0) {1017buf[len] = '\0'; /* readlink(2) doesn't NUL terminate */1018exec_path = JLI_StringDup(buf);1019}1020}1021#else /* !__solaris__ && !__linux__ */1022{1023/* Not implemented */1024}1025#endif10261027if (exec_path == NULL) {1028exec_path = FindExecName(argv[0]);1029}1030execname = exec_path;1031return exec_path;1032}10331034/* --- Splash Screen shared library support --- */1035static const char* SPLASHSCREEN_SO = JNI_LIB_NAME("splashscreen");1036static void* hSplashLib = NULL;10371038void* SplashProcAddress(const char* name) {1039if (!hSplashLib) {1040int ret;1041char jrePath[MAXPATHLEN];1042char splashPath[MAXPATHLEN];10431044if (!GetJREPath(jrePath, sizeof(jrePath), GetArch(), JNI_FALSE)) {1045JLI_ReportErrorMessage(JRE_ERROR1);1046return NULL;1047}1048ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s/%s",1049jrePath, GetArch(), SPLASHSCREEN_SO);10501051if (ret >= (int) sizeof(splashPath)) {1052JLI_ReportErrorMessage(JRE_ERROR11);1053return NULL;1054}1055if (ret < 0) {1056JLI_ReportErrorMessage(JRE_ERROR13);1057return NULL;1058}1059hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL);1060JLI_TraceLauncher("Info: loaded %s\n", splashPath);1061}1062if (hSplashLib) {1063void* sym = dlsym(hSplashLib, name);1064return sym;1065} else {1066return NULL;1067}1068}10691070void SplashFreeLibrary() {1071if (hSplashLib) {1072dlclose(hSplashLib);1073hSplashLib = NULL;1074}1075}10761077/*1078* Block current thread and continue execution in a new thread1079*/1080int1081ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) {1082int rslt;1083#ifndef __solaris__1084pthread_t tid;1085pthread_attr_t attr;1086pthread_attr_init(&attr);1087pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);10881089if (stack_size > 0) {1090pthread_attr_setstacksize(&attr, stack_size);1091}10921093if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) {1094void * tmp;1095pthread_join(tid, &tmp);1096rslt = (int)tmp;1097} else {1098/*1099* Continue execution in current thread if for some reason (e.g. out of1100* memory/LWP) a new thread can't be created. This will likely fail1101* later in continuation as JNI_CreateJavaVM needs to create quite a1102* few new threads, anyway, just give it a try..1103*/1104rslt = continuation(args);1105}11061107pthread_attr_destroy(&attr);1108#else /* __solaris__ */1109thread_t tid;1110long flags = 0;1111if (thr_create(NULL, stack_size, (void *(*)(void *))continuation, args, flags, &tid) == 0) {1112void * tmp;1113thr_join(tid, NULL, &tmp);1114rslt = (int)tmp;1115} else {1116/* See above. Continue in current thread if thr_create() failed */1117rslt = continuation(args);1118}1119#endif /* !__solaris__ */1120return rslt;1121}11221123/* Coarse estimation of number of digits assuming the worst case is a 64-bit pid. */1124#define MAX_PID_STR_SZ 2011251126void SetJavaLauncherPlatformProps() {1127/* Linux only */1128#ifdef __linux__1129const char *substr = "-Dsun.java.launcher.pid=";1130char *pid_prop_str = (char *)JLI_MemAlloc(JLI_StrLen(substr) + MAX_PID_STR_SZ + 1);1131sprintf(pid_prop_str, "%s%d", substr, getpid());1132AddOption(pid_prop_str, NULL);1133#endif /* __linux__ */1134}11351136int1137JVMInit(InvocationFunctions* ifn, jlong threadStackSize,1138int argc, char **argv,1139int mode, char *what, int ret)1140{1141ShowSplashScreen();1142return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);1143}11441145void1146PostJVMInit(JNIEnv *env, jstring mainClass, JavaVM *vm)1147{1148// stubbed out for windows and *nixes.1149}11501151void1152RegisterThread()1153{1154// stubbed out for windows and *nixes.1155}11561157/*1158* on unix, we return a false to indicate this option is not applicable1159*/1160jboolean1161ProcessPlatformOption(const char *arg)1162{1163return JNI_FALSE;1164}11651166#ifndef __solaris__11671168/*1169* Provide a CounterGet() implementation based on gettimeofday() which1170* is universally available, even though it may not be 'high resolution'1171* compared to platforms that provide gethrtime() (like Solaris). It is1172* also subject to time-of-day changes, but alternatives may not be1173* known to be available at either build time or run time.1174*/1175uint64_t CounterGet() {1176uint64_t result = 0;1177struct timeval tv;1178if (gettimeofday(&tv, NULL) != -1) {1179result = 1000000LL * (uint64_t)tv.tv_sec;1180result += (uint64_t)tv.tv_usec;1181}1182return result;1183}11841185#endif // !__solaris__118611871188