Path: blob/master/src/java.base/unix/native/libjli/java_md.c
41119 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"383940#define JVM_DLL "libjvm.so"41#define JAVA_DLL "libjava.so"42#ifdef AIX43#define LD_LIBRARY_PATH "LIBPATH"44#else45#define LD_LIBRARY_PATH "LD_LIBRARY_PATH"46#endif4748/* help jettison the LD_LIBRARY_PATH settings in the future */49#ifndef SETENV_REQUIRED50#define SETENV_REQUIRED51#endif5253/*54* Flowchart of launcher execs and options processing on unix55*56* The selection of the proper vm shared library to open depends on57* several classes of command line options, including vm "flavor"58* options (-client, -server).59* The vm selection options are not passed to the running60* virtual machine; they must be screened out by the launcher.61*62* The version specification (if any) is processed first by the63* platform independent routine SelectVersion. This may result in64* the exec of the specified launcher version.65*66* Previously the launcher modified the LD_LIBRARY_PATH appropriately for the67* desired data model path, regardless if data models matched or not. The68* launcher subsequently exec'ed the desired executable, in order to make the69* LD_LIBRARY_PATH path available, for the runtime linker.70*71* Now, in most cases,the launcher will dlopen the target libjvm.so. All72* required libraries are loaded by the runtime linker, using the73* $RPATH/$ORIGIN baked into the shared libraries at compile time. Therefore,74* in most cases, the launcher will only exec, if the data models are75* mismatched, and will not set any environment variables, regardless of the76* data models.77*78* However, if the environment contains a LD_LIBRARY_PATH, this will cause the79* launcher to inspect the LD_LIBRARY_PATH. The launcher will check80* a. if the LD_LIBRARY_PATH's first component is the path to the desired81* libjvm.so82* b. if any other libjvm.so is found in any of the paths.83* If case b is true, then the launcher will set the LD_LIBRARY_PATH to the84* desired JRE and reexec, in order to propagate the environment.85*86* Main87* (incoming argv)88* |89* \|/90* CreateExecutionEnvironment91* (determines desired data model)92* |93* |94* \|/95* Have Desired Model ? --> NO --> Exit(with error)96* |97* |98* \|/99* YES100* |101* |102* \|/103* CheckJvmType104* (removes -client, -server, etc.)105* |106* |107* \|/108* TranslateDashJArgs...109* (Prepare to pass args to vm)110* |111* |112* \|/113* ParseArguments114* |115* |116* \|/117* RequiresSetenv118* Is LD_LIBRARY_PATH119* and friends set ? --> NO --> Continue120* YES121* |122* |123* \|/124* Path is desired JRE ? YES --> Continue125* NO126* |127* |128* \|/129* Paths have well known130* jvm paths ? --> NO --> Error/Exit131* YES132* |133* |134* \|/135* Does libjvm.so exist136* in any of them ? --> NO --> Continue137* YES138* |139* |140* \|/141* Set the LD_LIBRARY_PATH142* |143* |144* \|/145* Re-exec146* |147* |148* \|/149* Main150*/151152/* Store the name of the executable once computed */153static char *execname = NULL;154155/*156* execname accessor from other parts of platform dependent logic157*/158const char *159GetExecName() {160return execname;161}162163#ifdef SETENV_REQUIRED164static jboolean165JvmExists(const char *path) {166char tmp[PATH_MAX + 1];167struct stat statbuf;168JLI_Snprintf(tmp, PATH_MAX, "%s/%s", path, JVM_DLL);169if (stat(tmp, &statbuf) == 0) {170return JNI_TRUE;171}172return JNI_FALSE;173}174/*175* contains a lib/{server,client}/libjvm.so ?176*/177static jboolean178ContainsLibJVM(const char *env) {179/* the usual suspects */180char clientPattern[] = "lib/client";181char serverPattern[] = "lib/server";182char *envpath;183char *path;184char* save_ptr = NULL;185jboolean clientPatternFound;186jboolean serverPatternFound;187188/* fastest path */189if (env == NULL) {190return JNI_FALSE;191}192193/* to optimize for time, test if any of our usual suspects are present. */194clientPatternFound = JLI_StrStr(env, clientPattern) != NULL;195serverPatternFound = JLI_StrStr(env, serverPattern) != NULL;196if (clientPatternFound == JNI_FALSE && serverPatternFound == JNI_FALSE) {197return JNI_FALSE;198}199200/*201* we have a suspicious path component, check if it contains a libjvm.so202*/203envpath = JLI_StringDup(env);204for (path = strtok_r(envpath, ":", &save_ptr); path != NULL; path = strtok_r(NULL, ":", &save_ptr)) {205if (clientPatternFound && JLI_StrStr(path, clientPattern) != NULL) {206if (JvmExists(path)) {207JLI_MemFree(envpath);208return JNI_TRUE;209}210}211if (serverPatternFound && JLI_StrStr(path, serverPattern) != NULL) {212if (JvmExists(path)) {213JLI_MemFree(envpath);214return JNI_TRUE;215}216}217}218JLI_MemFree(envpath);219return JNI_FALSE;220}221222/*223* Test whether the environment variable needs to be set, see flowchart.224*/225static jboolean226RequiresSetenv(const char *jvmpath) {227char jpath[PATH_MAX + 1];228char *llp;229char *dmllp = NULL;230char *p; /* a utility pointer */231232#ifdef MUSL_LIBC233/*234* The musl library loader requires LD_LIBRARY_PATH to be set in order235* to correctly resolve the dependency libjava.so has on libjvm.so.236*/237return JNI_TRUE;238#endif239240#ifdef AIX241/* We always have to set the LIBPATH on AIX because ld doesn't support $ORIGIN. */242return JNI_TRUE;243#endif244245llp = getenv("LD_LIBRARY_PATH");246/* no environment variable is a good environment variable */247if (llp == NULL && dmllp == NULL) {248return JNI_FALSE;249}250#ifdef __linux251/*252* On linux, if a binary is running as sgid or suid, glibc sets253* LD_LIBRARY_PATH to the empty string for security purposes. (In contrast,254* on Solaris the LD_LIBRARY_PATH variable for a privileged binary does not255* lose its settings; but the dynamic linker does apply more scrutiny to the256* path.) The launcher uses the value of LD_LIBRARY_PATH to prevent an exec257* loop, here and further downstream. Therefore, if we are running sgid or258* suid, this function's setting of LD_LIBRARY_PATH will be ineffective and259* we should case a return from the calling function. Getting the right260* libraries will be handled by the RPATH. In reality, this check is261* redundant, as the previous check for a non-null LD_LIBRARY_PATH will262* return back to the calling function forthwith, it is left here to safe263* guard against any changes, in the glibc's existing security policy.264*/265if ((getgid() != getegid()) || (getuid() != geteuid())) {266return JNI_FALSE;267}268#endif /* __linux */269270/*271* Prevent recursions. Since LD_LIBRARY_PATH is the one which will be set by272* previous versions of the JRE, thus it is the only path that matters here.273* So we check to see if the desired JRE is set.274*/275JLI_StrNCpy(jpath, jvmpath, PATH_MAX);276p = JLI_StrRChr(jpath, '/');277*p = '\0';278if (llp != NULL && JLI_StrNCmp(llp, jpath, JLI_StrLen(jpath)) == 0) {279return JNI_FALSE;280}281282/* scrutinize all the paths further */283if (llp != NULL && ContainsLibJVM(llp)) {284return JNI_TRUE;285}286if (dmllp != NULL && ContainsLibJVM(dmllp)) {287return JNI_TRUE;288}289return JNI_FALSE;290}291#endif /* SETENV_REQUIRED */292293void294CreateExecutionEnvironment(int *pargc, char ***pargv,295char jrepath[], jint so_jrepath,296char jvmpath[], jint so_jvmpath,297char jvmcfg[], jint so_jvmcfg) {298299char * jvmtype = NULL;300int argc = *pargc;301char **argv = *pargv;302303#ifdef SETENV_REQUIRED304jboolean mustsetenv = JNI_FALSE;305char *runpath = NULL; /* existing effective LD_LIBRARY_PATH setting */306char* new_runpath = NULL; /* desired new LD_LIBRARY_PATH string */307char* newpath = NULL; /* path on new LD_LIBRARY_PATH */308char* lastslash = NULL;309char** newenvp = NULL; /* current environment */310size_t new_runpath_size;311#endif /* SETENV_REQUIRED */312313/* Compute/set the name of the executable */314SetExecname(*pargv);315316/* Check to see if the jvmpath exists */317/* Find out where the JRE is that we will be using. */318if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE)) {319JLI_ReportErrorMessage(JRE_ERROR1);320exit(2);321}322JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%sjvm.cfg",323jrepath, FILESEP, FILESEP);324/* Find the specified JVM type */325if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {326JLI_ReportErrorMessage(CFG_ERROR7);327exit(1);328}329330jvmpath[0] = '\0';331jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE);332if (JLI_StrCmp(jvmtype, "ERROR") == 0) {333JLI_ReportErrorMessage(CFG_ERROR9);334exit(4);335}336337if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) {338JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);339exit(4);340}341/*342* we seem to have everything we need, so without further ado343* we return back, otherwise proceed to set the environment.344*/345#ifdef SETENV_REQUIRED346mustsetenv = RequiresSetenv(jvmpath);347JLI_TraceLauncher("mustsetenv: %s\n", mustsetenv ? "TRUE" : "FALSE");348349if (mustsetenv == JNI_FALSE) {350return;351}352#else353return;354#endif /* SETENV_REQUIRED */355356#ifdef SETENV_REQUIRED357if (mustsetenv) {358/*359* We will set the LD_LIBRARY_PATH as follows:360*361* o $JVMPATH (directory portion only)362* o $JRE/lib363* o $JRE/../lib364*365* followed by the user's previous effective LD_LIBRARY_PATH, if366* any.367*/368369runpath = getenv(LD_LIBRARY_PATH);370371/* runpath contains current effective LD_LIBRARY_PATH setting */372{ /* New scope to declare local variable */373char *new_jvmpath = JLI_StringDup(jvmpath);374new_runpath_size = ((runpath != NULL) ? JLI_StrLen(runpath) : 0) +3752 * JLI_StrLen(jrepath) +376JLI_StrLen(new_jvmpath) + 52;377new_runpath = JLI_MemAlloc(new_runpath_size);378newpath = new_runpath + JLI_StrLen(LD_LIBRARY_PATH "=");379380381/*382* Create desired LD_LIBRARY_PATH value for target data model.383*/384{385/* remove the name of the .so from the JVM path */386lastslash = JLI_StrRChr(new_jvmpath, '/');387if (lastslash)388*lastslash = '\0';389390sprintf(new_runpath, LD_LIBRARY_PATH "="391"%s:"392"%s/lib:"393"%s/../lib",394new_jvmpath,395jrepath,396jrepath397);398399JLI_MemFree(new_jvmpath);400401/*402* Check to make sure that the prefix of the current path is the403* desired environment variable setting, though the RequiresSetenv404* checks if the desired runpath exists, this logic does a more405* comprehensive check.406*/407if (runpath != NULL &&408JLI_StrNCmp(newpath, runpath, JLI_StrLen(newpath)) == 0 &&409(runpath[JLI_StrLen(newpath)] == 0 ||410runpath[JLI_StrLen(newpath)] == ':')) {411JLI_MemFree(new_runpath);412return;413}414}415}416417/*418* Place the desired environment setting onto the prefix of419* LD_LIBRARY_PATH. Note that this prevents any possible infinite420* loop of execv() because we test for the prefix, above.421*/422if (runpath != 0) {423/* ensure storage for runpath + colon + NULL */424if ((JLI_StrLen(runpath) + 1 + 1) > new_runpath_size) {425JLI_ReportErrorMessageSys(JRE_ERROR11);426exit(1);427}428JLI_StrCat(new_runpath, ":");429JLI_StrCat(new_runpath, runpath);430}431432if (putenv(new_runpath) != 0) {433/* problem allocating memory; LD_LIBRARY_PATH not set properly */434exit(1);435}436437/*438* Unix systems document that they look at LD_LIBRARY_PATH only439* once at startup, so we have to re-exec the current executable440* to get the changed environment variable to have an effect.441*/442443newenvp = environ;444}445#endif /* SETENV_REQUIRED */446{447char *newexec = execname;448JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n");449(void) fflush(stdout);450(void) fflush(stderr);451#ifdef SETENV_REQUIRED452if (mustsetenv) {453execve(newexec, argv, newenvp);454} else {455execv(newexec, argv);456}457#else /* !SETENV_REQUIRED */458execv(newexec, argv);459#endif /* SETENV_REQUIRED */460JLI_ReportErrorMessageSys(JRE_ERROR4, newexec);461}462exit(1);463}464465466static jboolean467GetJVMPath(const char *jrepath, const char *jvmtype,468char *jvmpath, jint jvmpathsize)469{470struct stat s;471472if (JLI_StrChr(jvmtype, '/')) {473JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);474} else {475JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtype);476}477478JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);479480if (stat(jvmpath, &s) == 0) {481JLI_TraceLauncher("yes.\n");482return JNI_TRUE;483} else {484JLI_TraceLauncher("no.\n");485return JNI_FALSE;486}487}488489/*490* Find path to JRE based on .exe's location or registry settings.491*/492static jboolean493GetJREPath(char *path, jint pathsize, jboolean speculative)494{495char libjava[MAXPATHLEN];496struct stat s;497498if (GetApplicationHome(path, pathsize)) {499/* Is JRE co-located with the application? */500JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);501if (access(libjava, F_OK) == 0) {502JLI_TraceLauncher("JRE path is %s\n", path);503return JNI_TRUE;504}505/* ensure storage for path + /jre + NULL */506if ((JLI_StrLen(path) + 4 + 1) > (size_t) pathsize) {507JLI_TraceLauncher("Insufficient space to store JRE path\n");508return JNI_FALSE;509}510/* Does the app ship a private JRE in <apphome>/jre directory? */511JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);512if (access(libjava, F_OK) == 0) {513JLI_StrCat(path, "/jre");514JLI_TraceLauncher("JRE path is %s\n", path);515return JNI_TRUE;516}517}518519if (GetApplicationHomeFromDll(path, pathsize)) {520JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);521if (stat(libjava, &s) == 0) {522JLI_TraceLauncher("JRE path is %s\n", path);523return JNI_TRUE;524}525}526527if (!speculative)528JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);529return JNI_FALSE;530}531532jboolean533LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)534{535void *libjvm;536537JLI_TraceLauncher("JVM path is %s\n", jvmpath);538539libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);540if (libjvm == NULL) {541JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);542JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());543return JNI_FALSE;544}545546ifn->CreateJavaVM = (CreateJavaVM_t)547dlsym(libjvm, "JNI_CreateJavaVM");548if (ifn->CreateJavaVM == NULL) {549JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());550return JNI_FALSE;551}552553ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)554dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");555if (ifn->GetDefaultJavaVMInitArgs == NULL) {556JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());557return JNI_FALSE;558}559560ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)561dlsym(libjvm, "JNI_GetCreatedJavaVMs");562if (ifn->GetCreatedJavaVMs == NULL) {563JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());564return JNI_FALSE;565}566567return JNI_TRUE;568}569570/*571* Compute the name of the executable572*573* In order to re-exec securely we need the absolute path of the574* executable. On Solaris getexecname(3c) may not return an absolute575* path so we use dladdr to get the filename of the executable and576* then use realpath to derive an absolute path. From Solaris 9577* onwards the filename returned in DL_info structure from dladdr is578* an absolute pathname so technically realpath isn't required.579* On Linux we read the executable name from /proc/self/exe.580* As a fallback, and for platforms other than Solaris and Linux,581* we use FindExecName to compute the executable name.582*/583const char*584SetExecname(char **argv)585{586char* exec_path = NULL;587#if defined(__ANDROID__) //Since both __ANDROID__ and __linux__ are defined, we must let the preprocessor preprocess the __ANDRIOD__ part first588char *__java_home = getenv("JAVA_HOME");589// From http://hg.openjdk.java.net/mobile/jdk9/jdk/file/17bb8a98d5e3/src/java.base/unix/native/libjli/java_md_solinux.c#l844590/* For Android, 'self' would point to /system/bin/app_process591* since we are really executing a Dalvik program at this point.592* argv[0] points to the Dalvik application name and we set the593* path to __java_home.594*/595char buf[PATH_MAX+1];596char *p = NULL;597if ((p = JLI_StrRChr(argv[0], '/')) != 0) {598/* may be running from command line */599p++;600if ((JLI_StrLen(p) == 4) && JLI_StrCmp(p, "java") == 0) {601/* started as 'java'. Must be command line */602JLI_TraceLauncher("SetExecName maybe command line = %s\n", argv[0]);603if (*argv[0] != '/') {604char *curdir = NULL;605/* get absolute path */606getcwd(buf, PATH_MAX);607curdir = JLI_StringDup(buf);608JLI_Snprintf(buf, PATH_MAX, "%s/%s", curdir, argv[0]);609JLI_MemFree(curdir);610} else {611JLI_Snprintf(buf, PATH_MAX, "%s", argv[0]);612}613} else {614/* Not command line, see if __java_home set */615if (__java_home != NULL) {616JLI_TraceLauncher("SetExecName not java = %s\n", __java_home);617JLI_Snprintf(buf, PATH_MAX, "%s/bin/java", __java_home);618} else {619/* Fake it as best we can or should we punt? */620JLI_TraceLauncher("SetExecName fake it = %s\n", argv[0]);621JLI_Snprintf(buf, PATH_MAX, "/data/data/%s/storage/jvm/bin/java",622argv[0]);623}624}625} else {626/* Not started as 'java', see if __java_home set */627if (__java_home != NULL) {628JLI_TraceLauncher("SetExecName not command line = %s\n", __java_home);629JLI_Snprintf(buf, PATH_MAX, "%s/bin/java", __java_home);630} else {631/* Fake it as best we can or should we punt? */632JLI_TraceLauncher("SetExecName fake it 2 = %s\n", argv[0]);633JLI_Snprintf(buf, PATH_MAX, "/data/data/%s/storage/jvm/bin/java",634argv[0]);635}636}637exec_path = JLI_StringDup(buf);638#elif defined(__linux__)639{640const char* self = "/proc/self/exe";641char buf[PATH_MAX+1];642int len = readlink(self, buf, PATH_MAX);643if (len >= 0) {644buf[len] = '\0'; /* readlink(2) doesn't NUL terminate */645exec_path = JLI_StringDup(buf);646}647}648#endif649650if (exec_path == NULL) {651exec_path = FindExecName(argv[0]);652}653execname = exec_path;654return exec_path;655}656657/* --- Splash Screen shared library support --- */658static const char* SPLASHSCREEN_SO = JNI_LIB_NAME("splashscreen");659static void* hSplashLib = NULL;660661void* SplashProcAddress(const char* name) {662if (!hSplashLib) {663int ret;664char jrePath[MAXPATHLEN];665char splashPath[MAXPATHLEN];666667if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) {668JLI_ReportErrorMessage(JRE_ERROR1);669return NULL;670}671ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s",672jrePath, SPLASHSCREEN_SO);673674if (ret >= (int) sizeof(splashPath)) {675JLI_ReportErrorMessage(JRE_ERROR11);676return NULL;677}678if (ret < 0) {679JLI_ReportErrorMessage(JRE_ERROR13);680return NULL;681}682hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL);683JLI_TraceLauncher("Info: loaded %s\n", splashPath);684}685if (hSplashLib) {686void* sym = dlsym(hSplashLib, name);687return sym;688} else {689return NULL;690}691}692693/*694* Signature adapter for pthread_create() or thr_create().695*/696static void* ThreadJavaMain(void* args) {697return (void*)(intptr_t)JavaMain(args);698}699700/*701* Block current thread and continue execution in a new thread.702*/703int704CallJavaMainInNewThread(jlong stack_size, void* args) {705int rslt;706pthread_t tid;707pthread_attr_t attr;708pthread_attr_init(&attr);709pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);710711if (stack_size > 0) {712pthread_attr_setstacksize(&attr, stack_size);713}714pthread_attr_setguardsize(&attr, 0); // no pthread guard page on java threads715716if (pthread_create(&tid, &attr, ThreadJavaMain, args) == 0) {717void* tmp;718pthread_join(tid, &tmp);719rslt = (int)(intptr_t)tmp;720} else {721/*722* Continue execution in current thread if for some reason (e.g. out of723* memory/LWP) a new thread can't be created. This will likely fail724* later in JavaMain as JNI_CreateJavaVM needs to create quite a725* few new threads, anyway, just give it a try..726*/727rslt = JavaMain(args);728}729730pthread_attr_destroy(&attr);731return rslt;732}733734/* Coarse estimation of number of digits assuming the worst case is a 64-bit pid. */735#define MAX_PID_STR_SZ 20736737int738JVMInit(InvocationFunctions* ifn, jlong threadStackSize,739int argc, char **argv,740int mode, char *what, int ret)741{742ShowSplashScreen();743return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);744}745746void747PostJVMInit(JNIEnv *env, jclass mainClass, JavaVM *vm)748{749// stubbed out for windows and *nixes.750}751752void753RegisterThread()754{755// stubbed out for windows and *nixes.756}757758/*759* on unix, we return a false to indicate this option is not applicable760*/761jboolean762ProcessPlatformOption(const char *arg)763{764return JNI_FALSE;765}766767768