duke@435: /* duke@435: * Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * duke@435: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@435: * CA 95054 USA or visit www.sun.com if you need additional information or duke@435: * have any questions. duke@435: * duke@435: */ duke@435: duke@435: /* duke@435: * Gamma (Hotspot internal engineering test) launcher based on 1.6.0-b28 JDK, duke@435: * search "GAMMA" for gamma specific changes. duke@435: */ duke@435: duke@435: #include "java.h" duke@435: #include duke@435: #include duke@435: #include duke@435: #include duke@435: #include duke@435: #include duke@435: #include duke@435: #include duke@435: #include duke@435: #include duke@435: #include duke@435: duke@435: #ifndef GAMMA duke@435: #include "manifest_info.h" duke@435: #include "version_comp.h" duke@435: #endif duke@435: duke@435: #define JVM_DLL "libjvm.so" duke@435: #define JAVA_DLL "libjava.so" duke@435: duke@435: #ifndef GAMMA /* launcher.make defines ARCH */ duke@435: duke@435: /* duke@435: * If a processor / os combination has the ability to run binaries of duke@435: * two data models and cohabitation of jre/jdk bits with both data duke@435: * models is supported, then DUAL_MODE is defined. When DUAL_MODE is duke@435: * defined, the architecture names for the narrow and wide version of duke@435: * the architecture are defined in BIG_ARCH and SMALL_ARCH. Currently duke@435: * only Solaris on sparc/sparcv9 and i586/amd64 is DUAL_MODE; linux duke@435: * i586/amd64 could be defined as DUAL_MODE but that is not the duke@435: * current policy. duke@435: */ duke@435: duke@435: #ifdef _LP64 duke@435: duke@435: # ifdef ia64 duke@435: # define ARCH "ia64" duke@435: # elif defined(amd64) duke@435: # define ARCH "amd64" duke@435: # elif defined(__sparc) duke@435: # define ARCH "sparcv9" duke@435: # else duke@435: # define ARCH "unknown" /* unknown 64-bit architecture */ duke@435: # endif duke@435: duke@435: #else /* 32-bit data model */ duke@435: duke@435: # ifdef i586 duke@435: # define ARCH "i386" duke@435: # elif defined(__sparc) duke@435: # define ARCH "sparc" duke@435: # endif duke@435: duke@435: #endif /* _LP64 */ duke@435: duke@435: #ifdef __sun duke@435: # define DUAL_MODE duke@435: # ifdef __sparc duke@435: # define BIG_ARCH "sparcv9" duke@435: # define SMALL_ARCH "sparc" duke@435: # else duke@435: # define BIG_ARCH "amd64" duke@435: # define SMALL_ARCH "i386" duke@435: # endif duke@435: # include duke@435: # include duke@435: # include duke@435: #else duke@435: # ifndef ARCH duke@435: # include duke@435: # endif duke@435: #endif duke@435: duke@435: #endif /* ifndef GAMMA */ duke@435: duke@435: /* pointer to environment */ duke@435: extern char **environ; duke@435: duke@435: #ifndef GAMMA duke@435: duke@435: /* duke@435: * A collection of useful strings. One should think of these as #define duke@435: * entries, but actual strings can be more efficient (with many compilers). duke@435: */ duke@435: #ifdef __linux__ duke@435: static const char *system_dir = "/usr/java"; duke@435: static const char *user_dir = "/java"; duke@435: #else /* Solaris */ duke@435: static const char *system_dir = "/usr/jdk"; duke@435: static const char *user_dir = "/jdk"; duke@435: #endif duke@435: duke@435: #endif /* ifndef GAMMA */ duke@435: duke@435: /* duke@435: * Flowchart of launcher execs and options processing on unix duke@435: * duke@435: * The selection of the proper vm shared library to open depends on duke@435: * several classes of command line options, including vm "flavor" duke@435: * options (-client, -server) and the data model options, -d32 and duke@435: * -d64, as well as a version specification which may have come from duke@435: * the command line or from the manifest of an executable jar file. duke@435: * The vm selection options are not passed to the running duke@435: * virtual machine; they must be screened out by the launcher. duke@435: * duke@435: * The version specification (if any) is processed first by the duke@435: * platform independent routine SelectVersion. This may result in duke@435: * the exec of the specified launcher version. duke@435: * duke@435: * Typically, the launcher execs at least once to ensure a suitable duke@435: * LD_LIBRARY_PATH is in effect for the process. The first exec duke@435: * screens out all the data model options; leaving the choice of data duke@435: * model implicit in the binary selected to run. However, in case no duke@435: * exec is done, the data model options are screened out before the vm duke@435: * is invoked. duke@435: * duke@435: * incoming argv ------------------------------ duke@435: * | | duke@435: * \|/ | duke@435: * CheckJVMType | duke@435: * (removes -client, -server, etc.) | duke@435: * \|/ duke@435: * CreateExecutionEnvironment duke@435: * (removes -d32 and -d64, duke@435: * determines desired data model, duke@435: * sets up LD_LIBRARY_PATH, duke@435: * and exec's) duke@435: * | duke@435: * -------------------------------------------- duke@435: * | duke@435: * \|/ duke@435: * exec child 1 incoming argv ----------------- duke@435: * | | duke@435: * \|/ | duke@435: * CheckJVMType | duke@435: * (removes -client, -server, etc.) | duke@435: * | \|/ duke@435: * | CreateExecutionEnvironment duke@435: * | (verifies desired data model duke@435: * | is running and acceptable duke@435: * | LD_LIBRARY_PATH; duke@435: * | no-op in child) duke@435: * | duke@435: * \|/ duke@435: * TranslateDashJArgs... duke@435: * (Prepare to pass args to vm) duke@435: * | duke@435: * | duke@435: * | duke@435: * \|/ duke@435: * ParseArguments duke@435: * (ignores -d32 and -d64, duke@435: * processes version options, duke@435: * creates argument list for vm, duke@435: * etc.) duke@435: * duke@435: */ duke@435: duke@435: static char *SetExecname(char **argv); duke@435: static char * GetExecname(); duke@435: static jboolean GetJVMPath(const char *jrepath, const char *jvmtype, duke@435: char *jvmpath, jint jvmpathsize, char * arch); duke@435: static jboolean GetJREPath(char *path, jint pathsize, char * arch, jboolean speculative); duke@435: duke@435: const char * duke@435: GetArch() duke@435: { duke@435: static char *arch = NULL; duke@435: static char buf[12]; duke@435: if (arch) { duke@435: return arch; duke@435: } duke@435: duke@435: #ifdef ARCH duke@435: strcpy(buf, ARCH); duke@435: #else duke@435: sysinfo(SI_ARCHITECTURE, buf, sizeof(buf)); duke@435: #endif duke@435: arch = buf; duke@435: return arch; duke@435: } duke@435: duke@435: void duke@435: CreateExecutionEnvironment(int *_argcp, duke@435: char ***_argvp, duke@435: char jrepath[], duke@435: jint so_jrepath, duke@435: char jvmpath[], duke@435: jint so_jvmpath, duke@435: char **original_argv) { duke@435: /* duke@435: * First, determine if we are running the desired data model. If we duke@435: * are running the desired data model, all the error messages duke@435: * associated with calling GetJREPath, ReadKnownVMs, etc. should be duke@435: * output. However, if we are not running the desired data model, duke@435: * some of the errors should be suppressed since it is more duke@435: * informative to issue an error message based on whether or not the duke@435: * os/processor combination has dual mode capabilities. duke@435: */ duke@435: duke@435: char *execname = NULL; duke@435: int original_argc = *_argcp; duke@435: jboolean jvmpathExists; duke@435: duke@435: /* Compute the name of the executable */ duke@435: execname = SetExecname(*_argvp); duke@435: duke@435: #ifndef GAMMA duke@435: /* Set the LD_LIBRARY_PATH environment variable, check data model duke@435: flags, and exec process, if needed */ duke@435: { duke@435: char *arch = (char *)GetArch(); /* like sparc or sparcv9 */ duke@435: char * jvmtype = NULL; duke@435: int argc = *_argcp; duke@435: char **argv = original_argv; duke@435: duke@435: char *runpath = NULL; /* existing effective LD_LIBRARY_PATH duke@435: setting */ duke@435: duke@435: int running = /* What data model is being ILP32 => duke@435: 32 bit vm; LP64 => 64 bit vm */ duke@435: #ifdef _LP64 duke@435: 64; duke@435: #else duke@435: 32; duke@435: #endif duke@435: duke@435: int wanted = running; /* What data mode is being duke@435: asked for? Current model is duke@435: fine unless another model duke@435: is asked for */ duke@435: duke@435: char* new_runpath = NULL; /* desired new LD_LIBRARY_PATH string */ duke@435: char* newpath = NULL; /* path on new LD_LIBRARY_PATH */ duke@435: char* lastslash = NULL; duke@435: duke@435: char** newenvp = NULL; /* current environment */ duke@435: duke@435: char** newargv = NULL; duke@435: int newargc = 0; duke@435: #ifdef __sun duke@435: char* dmpath = NULL; /* data model specific LD_LIBRARY_PATH, duke@435: Solaris only */ duke@435: #endif duke@435: duke@435: /* duke@435: * Starting in 1.5, all unix platforms accept the -d32 and -d64 duke@435: * options. On platforms where only one data-model is supported duke@435: * (e.g. ia-64 Linux), using the flag for the other data model is duke@435: * an error and will terminate the program. duke@435: */ duke@435: duke@435: { /* open new scope to declare local variables */ duke@435: int i; duke@435: duke@435: newargv = (char **)MemAlloc((argc+1) * sizeof(*newargv)); duke@435: newargv[newargc++] = argv[0]; duke@435: duke@435: /* scan for data model arguments and remove from argument list; duke@435: last occurrence determines desired data model */ duke@435: for (i=1; i < argc; i++) { duke@435: duke@435: if (strcmp(argv[i], "-J-d64") == 0 || strcmp(argv[i], "-d64") == 0) { duke@435: wanted = 64; duke@435: continue; duke@435: } duke@435: if (strcmp(argv[i], "-J-d32") == 0 || strcmp(argv[i], "-d32") == 0) { duke@435: wanted = 32; duke@435: continue; duke@435: } duke@435: newargv[newargc++] = argv[i]; duke@435: duke@435: #ifdef JAVA_ARGS duke@435: if (argv[i][0] != '-') duke@435: continue; duke@435: #else duke@435: if (strcmp(argv[i], "-classpath") == 0 || strcmp(argv[i], "-cp") == 0) { duke@435: i++; duke@435: if (i >= argc) break; duke@435: newargv[newargc++] = argv[i]; duke@435: continue; duke@435: } duke@435: if (argv[i][0] != '-') { i++; break; } duke@435: #endif duke@435: } duke@435: duke@435: /* copy rest of args [i .. argc) */ duke@435: while (i < argc) { duke@435: newargv[newargc++] = argv[i++]; duke@435: } duke@435: newargv[newargc] = NULL; duke@435: duke@435: /* duke@435: * newargv has all proper arguments here duke@435: */ duke@435: duke@435: argc = newargc; duke@435: argv = newargv; duke@435: } duke@435: duke@435: /* If the data model is not changing, it is an error if the duke@435: jvmpath does not exist */ duke@435: if (wanted == running) { duke@435: /* Find out where the JRE is that we will be using. */ duke@435: if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) { duke@435: fprintf(stderr, "Error: could not find Java 2 Runtime Environment.\n"); duke@435: exit(2); duke@435: } duke@435: duke@435: /* Find the specified JVM type */ duke@435: if (ReadKnownVMs(jrepath, arch, JNI_FALSE) < 1) { duke@435: fprintf(stderr, "Error: no known VMs. (check for corrupt jvm.cfg file)\n"); duke@435: exit(1); duke@435: } duke@435: duke@435: jvmpath[0] = '\0'; duke@435: jvmtype = CheckJvmType(_argcp, _argvp, JNI_FALSE); duke@435: duke@435: if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch )) { duke@435: fprintf(stderr, "Error: no `%s' JVM at `%s'.\n", jvmtype, jvmpath); duke@435: exit(4); duke@435: } duke@435: } else { /* do the same speculatively or exit */ duke@435: #ifdef DUAL_MODE duke@435: if (running != wanted) { duke@435: /* Find out where the JRE is that we will be using. */ duke@435: if (!GetJREPath(jrepath, so_jrepath, ((wanted==64)?BIG_ARCH:SMALL_ARCH), JNI_TRUE)) { duke@435: goto EndDataModelSpeculate; duke@435: } duke@435: duke@435: /* duke@435: * Read in jvm.cfg for target data model and process vm duke@435: * selection options. duke@435: */ duke@435: if (ReadKnownVMs(jrepath, ((wanted==64)?BIG_ARCH:SMALL_ARCH), JNI_TRUE) < 1) { duke@435: goto EndDataModelSpeculate; duke@435: } duke@435: jvmpath[0] = '\0'; duke@435: jvmtype = CheckJvmType(_argcp, _argvp, JNI_TRUE); duke@435: /* exec child can do error checking on the existence of the path */ duke@435: jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, duke@435: ((wanted==64)?BIG_ARCH:SMALL_ARCH)); duke@435: duke@435: } duke@435: EndDataModelSpeculate: /* give up and let other code report error message */ duke@435: ; duke@435: #else duke@435: fprintf(stderr, "Running a %d-bit JVM is not supported on this platform.\n", wanted); duke@435: exit(1); duke@435: #endif duke@435: } duke@435: duke@435: /* duke@435: * We will set the LD_LIBRARY_PATH as follows: duke@435: * duke@435: * o $JVMPATH (directory portion only) duke@435: * o $JRE/lib/$ARCH duke@435: * o $JRE/../lib/$ARCH duke@435: * duke@435: * followed by the user's previous effective LD_LIBRARY_PATH, if duke@435: * any. duke@435: */ duke@435: duke@435: #ifdef __sun duke@435: /* duke@435: * Starting in Solaris 7, ld.so.1 supports three LD_LIBRARY_PATH duke@435: * variables: duke@435: * duke@435: * 1. LD_LIBRARY_PATH -- used for 32 and 64 bit searches if duke@435: * data-model specific variables are not set. duke@435: * duke@435: * 2. LD_LIBRARY_PATH_64 -- overrides and replaces LD_LIBRARY_PATH duke@435: * for 64-bit binaries. duke@435: * duke@435: * 3. LD_LIBRARY_PATH_32 -- overrides and replaces LD_LIBRARY_PATH duke@435: * for 32-bit binaries. duke@435: * duke@435: * The vm uses LD_LIBRARY_PATH to set the java.library.path system duke@435: * property. To shield the vm from the complication of multiple duke@435: * LD_LIBRARY_PATH variables, if the appropriate data model duke@435: * specific variable is set, we will act as if LD_LIBRARY_PATH had duke@435: * the value of the data model specific variant and the data model duke@435: * specific variant will be unset. Note that the variable for the duke@435: * *wanted* data model must be used (if it is set), not simply the duke@435: * current running data model. duke@435: */ duke@435: duke@435: switch(wanted) { duke@435: case 0: duke@435: if(running == 32) { duke@435: dmpath = getenv("LD_LIBRARY_PATH_32"); duke@435: wanted = 32; duke@435: } duke@435: else { duke@435: dmpath = getenv("LD_LIBRARY_PATH_64"); duke@435: wanted = 64; duke@435: } duke@435: break; duke@435: duke@435: case 32: duke@435: dmpath = getenv("LD_LIBRARY_PATH_32"); duke@435: break; duke@435: duke@435: case 64: duke@435: dmpath = getenv("LD_LIBRARY_PATH_64"); duke@435: break; duke@435: duke@435: default: duke@435: fprintf(stderr, "Improper value at line %d.", __LINE__); duke@435: exit(1); /* unknown value in wanted */ duke@435: break; duke@435: } duke@435: duke@435: /* duke@435: * If dmpath is NULL, the relevant data model specific variable is duke@435: * not set and normal LD_LIBRARY_PATH should be used. duke@435: */ duke@435: if( dmpath == NULL) { duke@435: runpath = getenv("LD_LIBRARY_PATH"); duke@435: } duke@435: else { duke@435: runpath = dmpath; duke@435: } duke@435: #else duke@435: /* duke@435: * If not on Solaris, assume only a single LD_LIBRARY_PATH duke@435: * variable. duke@435: */ duke@435: runpath = getenv("LD_LIBRARY_PATH"); duke@435: #endif /* __sun */ duke@435: duke@435: #ifdef __linux duke@435: /* duke@435: * On linux, if a binary is running as sgid or suid, glibc sets duke@435: * LD_LIBRARY_PATH to the empty string for security purposes. (In duke@435: * contrast, on Solaris the LD_LIBRARY_PATH variable for a duke@435: * privileged binary does not lose its settings; but the dynamic duke@435: * linker does apply more scrutiny to the path.) The launcher uses duke@435: * the value of LD_LIBRARY_PATH to prevent an exec loop. duke@435: * Therefore, if we are running sgid or suid, this function's duke@435: * setting of LD_LIBRARY_PATH will be ineffective and we should duke@435: * return from the function now. Getting the right libraries to duke@435: * be found must be handled through other mechanisms. duke@435: */ duke@435: if((getgid() != getegid()) || (getuid() != geteuid()) ) { duke@435: return; duke@435: } duke@435: #endif duke@435: duke@435: /* runpath contains current effective LD_LIBRARY_PATH setting */ duke@435: duke@435: jvmpath = strdup(jvmpath); duke@435: new_runpath = MemAlloc( ((runpath!=NULL)?strlen(runpath):0) + duke@435: 2*strlen(jrepath) + 2*strlen(arch) + duke@435: strlen(jvmpath) + 52); duke@435: newpath = new_runpath + strlen("LD_LIBRARY_PATH="); duke@435: duke@435: duke@435: /* duke@435: * Create desired LD_LIBRARY_PATH value for target data model. duke@435: */ duke@435: { duke@435: /* remove the name of the .so from the JVM path */ duke@435: lastslash = strrchr(jvmpath, '/'); duke@435: if (lastslash) duke@435: *lastslash = '\0'; duke@435: duke@435: duke@435: /* jvmpath, ((running != wanted)?((wanted==64)?"/"BIG_ARCH:"/.."):""), */ duke@435: duke@435: sprintf(new_runpath, "LD_LIBRARY_PATH=" duke@435: "%s:" duke@435: "%s/lib/%s:" duke@435: "%s/../lib/%s", duke@435: jvmpath, duke@435: #ifdef DUAL_MODE duke@435: jrepath, ((wanted==64)?BIG_ARCH:SMALL_ARCH), duke@435: jrepath, ((wanted==64)?BIG_ARCH:SMALL_ARCH) duke@435: #else duke@435: jrepath, arch, duke@435: jrepath, arch duke@435: #endif duke@435: ); duke@435: duke@435: duke@435: /* duke@435: * Check to make sure that the prefix of the current path is the duke@435: * desired environment variable setting. duke@435: */ duke@435: if (runpath != NULL && duke@435: strncmp(newpath, runpath, strlen(newpath))==0 && duke@435: (runpath[strlen(newpath)] == 0 || runpath[strlen(newpath)] == ':') && duke@435: (running == wanted) /* data model does not have to be changed */ duke@435: #ifdef __sun duke@435: && (dmpath == NULL) /* data model specific variables not set */ duke@435: #endif duke@435: ) { duke@435: duke@435: return; duke@435: duke@435: } duke@435: } duke@435: duke@435: /* duke@435: * Place the desired environment setting onto the prefix of duke@435: * LD_LIBRARY_PATH. Note that this prevents any possible infinite duke@435: * loop of execv() because we test for the prefix, above. duke@435: */ duke@435: if (runpath != 0) { duke@435: strcat(new_runpath, ":"); duke@435: strcat(new_runpath, runpath); duke@435: } duke@435: duke@435: if( putenv(new_runpath) != 0) { duke@435: exit(1); /* problem allocating memory; LD_LIBRARY_PATH not set duke@435: properly */ duke@435: } duke@435: duke@435: /* duke@435: * Unix systems document that they look at LD_LIBRARY_PATH only duke@435: * once at startup, so we have to re-exec the current executable duke@435: * to get the changed environment variable to have an effect. duke@435: */ duke@435: duke@435: #ifdef __sun duke@435: /* duke@435: * If dmpath is not NULL, remove the data model specific string duke@435: * in the environment for the exec'ed child. duke@435: */ duke@435: duke@435: if( dmpath != NULL) duke@435: (void)UnsetEnv((wanted==32)?"LD_LIBRARY_PATH_32":"LD_LIBRARY_PATH_64"); duke@435: #endif duke@435: duke@435: newenvp = environ; duke@435: duke@435: { duke@435: char *newexec = execname; duke@435: #ifdef DUAL_MODE duke@435: /* duke@435: * If the data model is being changed, the path to the duke@435: * executable must be updated accordingly; the executable name duke@435: * and directory the executable resides in are separate. In the duke@435: * case of 32 => 64, the new bits are assumed to reside in, e.g. duke@435: * "olddir/BIGARCH/execname"; in the case of 64 => 32, duke@435: * the bits are assumed to be in "olddir/../execname". For example, duke@435: * duke@435: * olddir/sparcv9/execname duke@435: * olddir/amd64/execname duke@435: * duke@435: * for Solaris SPARC and Linux amd64, respectively. duke@435: */ duke@435: duke@435: if (running != wanted) { duke@435: char *oldexec = strcpy(MemAlloc(strlen(execname) + 1), execname); duke@435: char *olddir = oldexec; duke@435: char *oldbase = strrchr(oldexec, '/'); duke@435: duke@435: duke@435: newexec = MemAlloc(strlen(execname) + 20); duke@435: *oldbase++ = 0; duke@435: sprintf(newexec, "%s/%s/%s", olddir, duke@435: ((wanted==64) ? BIG_ARCH : ".."), oldbase); duke@435: argv[0] = newexec; duke@435: } duke@435: #endif duke@435: duke@435: execve(newexec, argv, newenvp); duke@435: perror("execve()"); duke@435: duke@435: fprintf(stderr, "Error trying to exec %s.\n", newexec); duke@435: fprintf(stderr, "Check if file exists and permissions are set correctly.\n"); duke@435: duke@435: #ifdef DUAL_MODE duke@435: if (running != wanted) { duke@435: fprintf(stderr, "Failed to start a %d-bit JVM process from a %d-bit JVM.\n", duke@435: wanted, running); duke@435: # ifdef __sun duke@435: duke@435: # ifdef __sparc duke@435: fprintf(stderr, "Verify all necessary J2SE components have been installed.\n" ); duke@435: fprintf(stderr, duke@435: "(Solaris SPARC 64-bit components must be installed after 32-bit components.)\n" ); duke@435: # else duke@435: fprintf(stderr, "Either 64-bit processes are not supported by this platform\n"); duke@435: fprintf(stderr, "or the 64-bit components have not been installed.\n"); duke@435: # endif duke@435: } duke@435: # endif duke@435: #endif duke@435: duke@435: } duke@435: duke@435: exit(1); duke@435: } duke@435: duke@435: #else /* ifndef GAMMA */ duke@435: duke@435: /* gamma launcher is simpler in that it doesn't handle VM flavors, data */ duke@435: /* model, LD_LIBRARY_PATH, etc. Assuming everything is set-up correctly */ duke@435: /* all we need to do here is to return correct path names. See also */ duke@435: /* GetJVMPath() and GetApplicationHome(). */ duke@435: duke@435: { char *arch = (char *)GetArch(); /* like sparc or sparcv9 */ duke@435: char *p; duke@435: duke@435: if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) { duke@435: fprintf(stderr, "Error: could not find Java 2 Runtime Environment.\n"); duke@435: exit(2); duke@435: } duke@435: duke@435: if (!GetJVMPath(jrepath, NULL, jvmpath, so_jvmpath, arch )) { duke@435: fprintf(stderr, "Error: no JVM at `%s'.\n", jvmpath); duke@435: exit(4); duke@435: } duke@435: } duke@435: duke@435: #endif /* ifndef GAMMA */ duke@435: } duke@435: duke@435: duke@435: /* duke@435: * On Solaris VM choosing is done by the launcher (java.c). duke@435: */ duke@435: static jboolean duke@435: GetJVMPath(const char *jrepath, const char *jvmtype, duke@435: char *jvmpath, jint jvmpathsize, char * arch) duke@435: { duke@435: struct stat s; duke@435: duke@435: #ifndef GAMMA duke@435: if (strchr(jvmtype, '/')) { duke@435: sprintf(jvmpath, "%s/" JVM_DLL, jvmtype); duke@435: } else { duke@435: sprintf(jvmpath, "%s/lib/%s/%s/" JVM_DLL, jrepath, arch, jvmtype); duke@435: } duke@435: #else duke@435: /* For gamma launcher, JVM is either built-in or in the same directory. */ duke@435: /* Either way we return "/libjvm.so" where is the */ duke@435: /* directory where gamma launcher is located. */ duke@435: duke@435: char *p; duke@435: duke@435: snprintf(jvmpath, jvmpathsize, "%s", GetExecname()); duke@435: p = strrchr(jvmpath, '/'); duke@435: if (p) { duke@435: /* replace executable name with libjvm.so */ duke@435: snprintf(p + 1, jvmpathsize - (p + 1 - jvmpath), "%s", JVM_DLL); duke@435: } else { duke@435: /* this case shouldn't happen */ duke@435: snprintf(jvmpath, jvmpathsize, "%s", JVM_DLL); duke@435: } duke@435: #endif duke@435: duke@435: if (_launcher_debug) duke@435: printf("Does `%s' exist ... ", jvmpath); duke@435: duke@435: if (stat(jvmpath, &s) == 0) { duke@435: if (_launcher_debug) duke@435: printf("yes.\n"); duke@435: return JNI_TRUE; duke@435: } else { duke@435: if (_launcher_debug) duke@435: printf("no.\n"); duke@435: return JNI_FALSE; duke@435: } duke@435: } duke@435: duke@435: /* duke@435: * Find path to JRE based on .exe's location or registry settings. duke@435: */ duke@435: static jboolean duke@435: GetJREPath(char *path, jint pathsize, char * arch, jboolean speculative) duke@435: { duke@435: char libjava[MAXPATHLEN]; duke@435: duke@435: if (GetApplicationHome(path, pathsize)) { duke@435: /* Is JRE co-located with the application? */ duke@435: sprintf(libjava, "%s/lib/%s/" JAVA_DLL, path, arch); duke@435: if (access(libjava, F_OK) == 0) { duke@435: goto found; duke@435: } duke@435: duke@435: /* Does the app ship a private JRE in /jre directory? */ duke@435: sprintf(libjava, "%s/jre/lib/%s/" JAVA_DLL, path, arch); duke@435: if (access(libjava, F_OK) == 0) { duke@435: strcat(path, "/jre"); duke@435: goto found; duke@435: } duke@435: } duke@435: duke@435: if (!speculative) duke@435: fprintf(stderr, "Error: could not find " JAVA_DLL "\n"); duke@435: return JNI_FALSE; duke@435: duke@435: found: duke@435: if (_launcher_debug) duke@435: printf("JRE path is %s\n", path); duke@435: return JNI_TRUE; duke@435: } duke@435: duke@435: jboolean duke@435: LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) duke@435: { duke@435: #ifdef GAMMA duke@435: /* JVM is directly linked with gamma launcher; no dlopen() */ duke@435: ifn->CreateJavaVM = JNI_CreateJavaVM; duke@435: ifn->GetDefaultJavaVMInitArgs = JNI_GetDefaultJavaVMInitArgs; duke@435: return JNI_TRUE; duke@435: #else duke@435: Dl_info dlinfo; duke@435: void *libjvm; duke@435: duke@435: if (_launcher_debug) { duke@435: printf("JVM path is %s\n", jvmpath); duke@435: } duke@435: duke@435: libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL); duke@435: if (libjvm == NULL) { duke@435: #if defined(__sparc) && !defined(_LP64) /* i.e. 32-bit sparc */ duke@435: FILE * fp; duke@435: Elf32_Ehdr elf_head; duke@435: int count; duke@435: int location; duke@435: duke@435: fp = fopen(jvmpath, "r"); duke@435: if(fp == NULL) duke@435: goto error; duke@435: duke@435: /* read in elf header */ duke@435: count = fread((void*)(&elf_head), sizeof(Elf32_Ehdr), 1, fp); duke@435: fclose(fp); duke@435: if(count < 1) duke@435: goto error; duke@435: duke@435: /* duke@435: * Check for running a server vm (compiled with -xarch=v8plus) duke@435: * on a stock v8 processor. In this case, the machine type in duke@435: * the elf header would not be included the architecture list duke@435: * provided by the isalist command, which is turn is gotten from duke@435: * sysinfo. This case cannot occur on 64-bit hardware and thus duke@435: * does not have to be checked for in binaries with an LP64 data duke@435: * model. duke@435: */ duke@435: if(elf_head.e_machine == EM_SPARC32PLUS) { duke@435: char buf[257]; /* recommended buffer size from sysinfo man duke@435: page */ duke@435: long length; duke@435: char* location; duke@435: duke@435: length = sysinfo(SI_ISALIST, buf, 257); duke@435: if(length > 0) { duke@435: location = strstr(buf, "sparcv8plus "); duke@435: if(location == NULL) { duke@435: fprintf(stderr, "SPARC V8 processor detected; Server compiler requires V9 or better.\n"); duke@435: fprintf(stderr, "Use Client compiler on V8 processors.\n"); duke@435: fprintf(stderr, "Could not create the Java virtual machine.\n"); duke@435: return JNI_FALSE; duke@435: } duke@435: } duke@435: } duke@435: #endif duke@435: fprintf(stderr, "dl failure on line %d", __LINE__); duke@435: goto error; duke@435: } duke@435: duke@435: ifn->CreateJavaVM = (CreateJavaVM_t) duke@435: dlsym(libjvm, "JNI_CreateJavaVM"); duke@435: if (ifn->CreateJavaVM == NULL) duke@435: goto error; duke@435: duke@435: ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t) duke@435: dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs"); duke@435: if (ifn->GetDefaultJavaVMInitArgs == NULL) duke@435: goto error; duke@435: duke@435: return JNI_TRUE; duke@435: duke@435: error: duke@435: fprintf(stderr, "Error: failed %s, because %s\n", jvmpath, dlerror()); duke@435: return JNI_FALSE; duke@435: #endif /* GAMMA */ duke@435: } duke@435: duke@435: /* duke@435: * Get the path to the file that has the usage message for -X options. duke@435: */ duke@435: void duke@435: GetXUsagePath(char *buf, jint bufsize) duke@435: { duke@435: static const char Xusage_txt[] = "/Xusage.txt"; duke@435: Dl_info dlinfo; duke@435: duke@435: /* we use RTLD_NOW because of problems with ld.so.1 and green threads */ duke@435: dladdr(dlsym(dlopen(JVM_DLL, RTLD_NOW), "JNI_CreateJavaVM"), &dlinfo); duke@435: strncpy(buf, (char *)dlinfo.dli_fname, bufsize - sizeof(Xusage_txt)); duke@435: duke@435: buf[bufsize-1] = '\0'; duke@435: strcpy(strrchr(buf, '/'), Xusage_txt); duke@435: } duke@435: duke@435: /* duke@435: * If app is "/foo/bin/javac", or "/foo/bin/sparcv9/javac" then put duke@435: * "/foo" into buf. duke@435: */ duke@435: jboolean duke@435: GetApplicationHome(char *buf, jint bufsize) duke@435: { duke@435: #ifdef __linux__ duke@435: char *execname = GetExecname(); duke@435: if (execname) { duke@435: strncpy(buf, execname, bufsize-1); duke@435: buf[bufsize-1] = '\0'; duke@435: } else { duke@435: return JNI_FALSE; duke@435: } duke@435: #else duke@435: Dl_info dlinfo; duke@435: duke@435: dladdr((void *)GetApplicationHome, &dlinfo); duke@435: if (realpath(dlinfo.dli_fname, buf) == NULL) { duke@435: fprintf(stderr, "Error: realpath(`%s') failed.\n", dlinfo.dli_fname); duke@435: return JNI_FALSE; duke@435: } duke@435: #endif duke@435: duke@435: #ifdef GAMMA duke@435: { duke@435: /* gamma launcher uses JAVA_HOME environment variable to find JDK/JRE */ duke@435: char* java_home_var = getenv("JAVA_HOME"); duke@435: if (java_home_var == NULL) { duke@435: printf("JAVA_HOME must point to a valid JDK/JRE to run gamma\n"); duke@435: return JNI_FALSE; duke@435: } duke@435: snprintf(buf, bufsize, "%s", java_home_var); duke@435: } duke@435: #else duke@435: if (strrchr(buf, '/') == 0) { duke@435: buf[0] = '\0'; duke@435: return JNI_FALSE; duke@435: } duke@435: *(strrchr(buf, '/')) = '\0'; /* executable file */ duke@435: if (strlen(buf) < 4 || strrchr(buf, '/') == 0) { duke@435: buf[0] = '\0'; duke@435: return JNI_FALSE; duke@435: } duke@435: if (strcmp("/bin", buf + strlen(buf) - 4) != 0) duke@435: *(strrchr(buf, '/')) = '\0'; /* sparcv9 or amd64 */ duke@435: if (strlen(buf) < 4 || strcmp("/bin", buf + strlen(buf) - 4) != 0) { duke@435: buf[0] = '\0'; duke@435: return JNI_FALSE; duke@435: } duke@435: *(strrchr(buf, '/')) = '\0'; /* bin */ duke@435: #endif /* GAMMA */ duke@435: duke@435: return JNI_TRUE; duke@435: } duke@435: duke@435: duke@435: /* duke@435: * Return true if the named program exists duke@435: */ duke@435: static int duke@435: ProgramExists(char *name) duke@435: { duke@435: struct stat sb; duke@435: if (stat(name, &sb) != 0) return 0; duke@435: if (S_ISDIR(sb.st_mode)) return 0; duke@435: return (sb.st_mode & S_IEXEC) != 0; duke@435: } duke@435: duke@435: duke@435: /* duke@435: * Find a command in a directory, returning the path. duke@435: */ duke@435: static char * duke@435: Resolve(char *indir, char *cmd) duke@435: { duke@435: char name[PATH_MAX + 2], *real; duke@435: duke@435: if ((strlen(indir) + strlen(cmd) + 1) > PATH_MAX) return 0; duke@435: sprintf(name, "%s%c%s", indir, FILE_SEPARATOR, cmd); duke@435: if (!ProgramExists(name)) return 0; duke@435: real = MemAlloc(PATH_MAX + 2); duke@435: if (!realpath(name, real)) duke@435: strcpy(real, name); duke@435: return real; duke@435: } duke@435: duke@435: duke@435: /* duke@435: * Find a path for the executable duke@435: */ duke@435: static char * duke@435: FindExecName(char *program) duke@435: { duke@435: char cwdbuf[PATH_MAX+2]; duke@435: char *path; duke@435: char *tmp_path; duke@435: char *f; duke@435: char *result = NULL; duke@435: duke@435: /* absolute path? */ duke@435: if (*program == FILE_SEPARATOR || duke@435: (FILE_SEPARATOR=='\\' && strrchr(program, ':'))) duke@435: return Resolve("", program+1); duke@435: duke@435: /* relative path? */ duke@435: if (strrchr(program, FILE_SEPARATOR) != 0) { duke@435: char buf[PATH_MAX+2]; duke@435: return Resolve(getcwd(cwdbuf, sizeof(cwdbuf)), program); duke@435: } duke@435: duke@435: /* from search path? */ duke@435: path = getenv("PATH"); duke@435: if (!path || !*path) path = "."; duke@435: tmp_path = MemAlloc(strlen(path) + 2); duke@435: strcpy(tmp_path, path); duke@435: duke@435: for (f=tmp_path; *f && result==0; ) { duke@435: char *s = f; duke@435: while (*f && (*f != PATH_SEPARATOR)) ++f; duke@435: if (*f) *f++ = 0; duke@435: if (*s == FILE_SEPARATOR) duke@435: result = Resolve(s, program); duke@435: else { duke@435: /* relative path element */ duke@435: char dir[2*PATH_MAX]; duke@435: sprintf(dir, "%s%c%s", getcwd(cwdbuf, sizeof(cwdbuf)), duke@435: FILE_SEPARATOR, s); duke@435: result = Resolve(dir, program); duke@435: } duke@435: if (result != 0) break; duke@435: } duke@435: duke@435: free(tmp_path); duke@435: return result; duke@435: } duke@435: duke@435: duke@435: /* Store the name of the executable once computed */ duke@435: static char *execname = NULL; duke@435: duke@435: /* duke@435: * Compute the name of the executable duke@435: * duke@435: * In order to re-exec securely we need the absolute path of the duke@435: * executable. On Solaris getexecname(3c) may not return an absolute duke@435: * path so we use dladdr to get the filename of the executable and duke@435: * then use realpath to derive an absolute path. From Solaris 9 duke@435: * onwards the filename returned in DL_info structure from dladdr is duke@435: * an absolute pathname so technically realpath isn't required. duke@435: * On Linux we read the executable name from /proc/self/exe. duke@435: * As a fallback, and for platforms other than Solaris and Linux, duke@435: * we use FindExecName to compute the executable name. duke@435: */ duke@435: static char * duke@435: SetExecname(char **argv) duke@435: { duke@435: char* exec_path = NULL; duke@435: duke@435: if (execname != NULL) /* Already determined */ duke@435: return (execname); duke@435: duke@435: #if defined(__sun) duke@435: { duke@435: Dl_info dlinfo; duke@435: if (dladdr((void*)&SetExecname, &dlinfo)) { duke@435: char *resolved = (char*)MemAlloc(PATH_MAX+1); duke@435: if (resolved != NULL) { duke@435: exec_path = realpath(dlinfo.dli_fname, resolved); duke@435: if (exec_path == NULL) { duke@435: free(resolved); duke@435: } duke@435: } duke@435: } duke@435: } duke@435: #elif defined(__linux__) duke@435: { duke@435: const char* self = "/proc/self/exe"; duke@435: char buf[PATH_MAX+1]; duke@435: int len = readlink(self, buf, PATH_MAX); duke@435: if (len >= 0) { duke@435: buf[len] = '\0'; /* readlink doesn't nul terminate */ duke@435: exec_path = strdup(buf); duke@435: } duke@435: } duke@435: #else /* !__sun && !__linux */ duke@435: { duke@435: /* Not implemented */ duke@435: } duke@435: #endif duke@435: duke@435: if (exec_path == NULL) { duke@435: exec_path = FindExecName(argv[0]); duke@435: } duke@435: execname = exec_path; duke@435: return exec_path; duke@435: } duke@435: duke@435: /* duke@435: * Return the name of the executable. Used in java_md.c to find the JRE area. duke@435: */ duke@435: static char * duke@435: GetExecname() { duke@435: return execname; duke@435: } duke@435: duke@435: void ReportErrorMessage(char * message, jboolean always) { duke@435: if (always) { duke@435: fprintf(stderr, "%s\n", message); duke@435: } duke@435: } duke@435: duke@435: void ReportErrorMessage2(char * format, char * string, jboolean always) { duke@435: if (always) { duke@435: fprintf(stderr, format, string); duke@435: fprintf(stderr, "\n"); duke@435: } duke@435: } duke@435: duke@435: void ReportExceptionDescription(JNIEnv * env) { duke@435: (*env)->ExceptionDescribe(env); duke@435: } duke@435: duke@435: /* duke@435: * Return JNI_TRUE for an option string that has no effect but should duke@435: * _not_ be passed on to the vm; return JNI_FALSE otherwise. On duke@435: * Solaris SPARC, this screening needs to be done if: duke@435: * 1) LD_LIBRARY_PATH does _not_ need to be reset and duke@435: * 2) -d32 or -d64 is passed to a binary with a matching data model duke@435: * (the exec in SetLibraryPath removes -d options and points the duke@435: * exec to the proper binary). When this exec is not done, these options duke@435: * would end up getting passed onto the vm. duke@435: */ duke@435: jboolean RemovableMachineDependentOption(char * option) { duke@435: /* duke@435: * Unconditionally remove both -d32 and -d64 options since only duke@435: * the last such options has an effect; e.g. duke@435: * java -d32 -d64 -d32 -version duke@435: * is equivalent to duke@435: * java -d32 -version duke@435: */ duke@435: duke@435: if( (strcmp(option, "-d32") == 0 ) || duke@435: (strcmp(option, "-d64") == 0 )) duke@435: return JNI_TRUE; duke@435: else duke@435: return JNI_FALSE; duke@435: } duke@435: duke@435: void PrintMachineDependentOptions() { duke@435: fprintf(stdout, duke@435: " -d32 use a 32-bit data model if available\n" duke@435: "\n" duke@435: " -d64 use a 64-bit data model if available\n"); duke@435: return; duke@435: } duke@435: duke@435: #ifndef GAMMA /* gamma launcher does not have ergonomics */ duke@435: duke@435: /* duke@435: * The following methods (down to ServerClassMachine()) answer duke@435: * the question about whether a machine is a "server-class" duke@435: * machine. A server-class machine is loosely defined as one duke@435: * with 2 or more processors and 2 gigabytes or more physical duke@435: * memory. The definition of a processor is a physical package, duke@435: * not a hyperthreaded chip masquerading as a multi-processor. duke@435: * The definition of memory is also somewhat fuzzy, since x86 duke@435: * machines seem not to report all the memory in their DIMMs, we duke@435: * think because of memory mapping of graphics cards, etc. duke@435: * duke@435: * This code is somewhat more confused with #ifdef's than we'd duke@435: * like because this file is used by both Solaris and Linux duke@435: * platforms, and so needs to be parameterized for SPARC and duke@435: * i586 hardware. The other Linux platforms (amd64 and ia64) duke@435: * don't even ask this question, because they only come with duke@435: * server JVMs. */ duke@435: duke@435: # define KB (1024UL) duke@435: # define MB (1024UL * KB) duke@435: # define GB (1024UL * MB) duke@435: duke@435: /* Compute physical memory by asking the OS */ duke@435: uint64_t duke@435: physical_memory(void) { duke@435: const uint64_t pages = (uint64_t) sysconf(_SC_PHYS_PAGES); duke@435: const uint64_t page_size = (uint64_t) sysconf(_SC_PAGESIZE); duke@435: const uint64_t result = pages * page_size; duke@435: # define UINT64_FORMAT "%" PRIu64 duke@435: duke@435: if (_launcher_debug) { duke@435: printf("pages: " UINT64_FORMAT duke@435: " page_size: " UINT64_FORMAT duke@435: " physical memory: " UINT64_FORMAT " (%.3fGB)\n", duke@435: pages, page_size, result, result / (double) GB); duke@435: } duke@435: return result; duke@435: } duke@435: duke@435: #if defined(__sun) && defined(__sparc) duke@435: duke@435: /* Methods for solaris-sparc: these are easy. */ duke@435: duke@435: /* Ask the OS how many processors there are. */ duke@435: unsigned long duke@435: physical_processors(void) { duke@435: const unsigned long sys_processors = sysconf(_SC_NPROCESSORS_CONF); duke@435: duke@435: if (_launcher_debug) { duke@435: printf("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors); duke@435: } duke@435: return sys_processors; duke@435: } duke@435: duke@435: /* The solaris-sparc version of the "server-class" predicate. */ duke@435: jboolean duke@435: solaris_sparc_ServerClassMachine(void) { duke@435: jboolean result = JNI_FALSE; duke@435: /* How big is a server class machine? */ duke@435: const unsigned long server_processors = 2UL; duke@435: const uint64_t server_memory = 2UL * GB; duke@435: const uint64_t actual_memory = physical_memory(); duke@435: duke@435: /* Is this a server class machine? */ duke@435: if (actual_memory >= server_memory) { duke@435: const unsigned long actual_processors = physical_processors(); duke@435: if (actual_processors >= server_processors) { duke@435: result = JNI_TRUE; duke@435: } duke@435: } duke@435: if (_launcher_debug) { duke@435: printf("solaris_" ARCH "_ServerClassMachine: %s\n", duke@435: (result == JNI_TRUE ? "JNI_TRUE" : "JNI_FALSE")); duke@435: } duke@435: return result; duke@435: } duke@435: duke@435: #endif /* __sun && __sparc */ duke@435: duke@435: #if defined(__sun) && defined(i586) duke@435: duke@435: /* duke@435: * A utility method for asking the CPU about itself. duke@435: * There's a corresponding version of linux-i586 duke@435: * because the compilers are different. duke@435: */ duke@435: void duke@435: get_cpuid(uint32_t arg, duke@435: uint32_t* eaxp, duke@435: uint32_t* ebxp, duke@435: uint32_t* ecxp, duke@435: uint32_t* edxp) { duke@435: #ifdef _LP64 duke@435: asm( duke@435: /* rbx is a callee-saved register */ duke@435: " movq %rbx, %r11 \n" duke@435: /* rdx and rcx are 3rd and 4th argument registers */ duke@435: " movq %rdx, %r10 \n" duke@435: " movq %rcx, %r9 \n" duke@435: " movl %edi, %eax \n" duke@435: " cpuid \n" duke@435: " movl %eax, (%rsi)\n" duke@435: " movl %ebx, (%r10)\n" duke@435: " movl %ecx, (%r9) \n" duke@435: " movl %edx, (%r8) \n" duke@435: /* Restore rbx */ duke@435: " movq %r11, %rbx"); duke@435: #else duke@435: /* EBX is a callee-saved register */ duke@435: asm(" pushl %ebx"); duke@435: /* Need ESI for storing through arguments */ duke@435: asm(" pushl %esi"); duke@435: asm(" movl 8(%ebp), %eax \n" duke@435: " cpuid \n" duke@435: " movl 12(%ebp), %esi \n" duke@435: " movl %eax, (%esi) \n" duke@435: " movl 16(%ebp), %esi \n" duke@435: " movl %ebx, (%esi) \n" duke@435: " movl 20(%ebp), %esi \n" duke@435: " movl %ecx, (%esi) \n" duke@435: " movl 24(%ebp), %esi \n" duke@435: " movl %edx, (%esi) "); duke@435: /* Restore ESI and EBX */ duke@435: asm(" popl %esi"); duke@435: /* Restore EBX */ duke@435: asm(" popl %ebx"); duke@435: #endif duke@435: } duke@435: duke@435: #endif /* __sun && i586 */ duke@435: duke@435: #if defined(__linux__) && defined(i586) duke@435: duke@435: /* duke@435: * A utility method for asking the CPU about itself. duke@435: * There's a corresponding version of solaris-i586 duke@435: * because the compilers are different. duke@435: */ duke@435: void duke@435: get_cpuid(uint32_t arg, duke@435: uint32_t* eaxp, duke@435: uint32_t* ebxp, duke@435: uint32_t* ecxp, duke@435: uint32_t* edxp) { duke@435: #ifdef _LP64 duke@435: __asm__ volatile (/* Instructions */ duke@435: " movl %4, %%eax \n" duke@435: " cpuid \n" duke@435: " movl %%eax, (%0)\n" duke@435: " movl %%ebx, (%1)\n" duke@435: " movl %%ecx, (%2)\n" duke@435: " movl %%edx, (%3)\n" duke@435: : /* Outputs */ duke@435: : /* Inputs */ duke@435: "r" (eaxp), duke@435: "r" (ebxp), duke@435: "r" (ecxp), duke@435: "r" (edxp), duke@435: "r" (arg) duke@435: : /* Clobbers */ duke@435: "%rax", "%rbx", "%rcx", "%rdx", "memory" duke@435: ); duke@435: #else duke@435: uint32_t value_of_eax = 0; duke@435: uint32_t value_of_ebx = 0; duke@435: uint32_t value_of_ecx = 0; duke@435: uint32_t value_of_edx = 0; duke@435: __asm__ volatile (/* Instructions */ duke@435: /* ebx is callee-save, so push it */ duke@435: /* even though it's in the clobbers section */ duke@435: " pushl %%ebx \n" duke@435: " movl %4, %%eax \n" duke@435: " cpuid \n" duke@435: " movl %%eax, %0 \n" duke@435: " movl %%ebx, %1 \n" duke@435: " movl %%ecx, %2 \n" duke@435: " movl %%edx, %3 \n" duke@435: /* restore ebx */ duke@435: " popl %%ebx \n" duke@435: duke@435: : /* Outputs */ duke@435: "=m" (value_of_eax), duke@435: "=m" (value_of_ebx), duke@435: "=m" (value_of_ecx), duke@435: "=m" (value_of_edx) duke@435: : /* Inputs */ duke@435: "m" (arg) duke@435: : /* Clobbers */ duke@435: "%eax", "%ebx", "%ecx", "%edx" duke@435: ); duke@435: *eaxp = value_of_eax; duke@435: *ebxp = value_of_ebx; duke@435: *ecxp = value_of_ecx; duke@435: *edxp = value_of_edx; duke@435: #endif duke@435: } duke@435: duke@435: #endif /* __linux__ && i586 */ duke@435: duke@435: #ifdef i586 duke@435: /* duke@435: * Routines shared by solaris-i586 and linux-i586. duke@435: */ duke@435: duke@435: enum HyperThreadingSupport_enum { duke@435: hts_supported = 1, duke@435: hts_too_soon_to_tell = 0, duke@435: hts_not_supported = -1, duke@435: hts_not_pentium4 = -2, duke@435: hts_not_intel = -3 duke@435: }; duke@435: typedef enum HyperThreadingSupport_enum HyperThreadingSupport; duke@435: duke@435: /* Determine if hyperthreading is supported */ duke@435: HyperThreadingSupport duke@435: hyperthreading_support(void) { duke@435: HyperThreadingSupport result = hts_too_soon_to_tell; duke@435: /* Bits 11 through 8 is family processor id */ duke@435: # define FAMILY_ID_SHIFT 8 duke@435: # define FAMILY_ID_MASK 0xf duke@435: /* Bits 23 through 20 is extended family processor id */ duke@435: # define EXT_FAMILY_ID_SHIFT 20 duke@435: # define EXT_FAMILY_ID_MASK 0xf duke@435: /* Pentium 4 family processor id */ duke@435: # define PENTIUM4_FAMILY_ID 0xf duke@435: /* Bit 28 indicates Hyper-Threading Technology support */ duke@435: # define HT_BIT_SHIFT 28 duke@435: # define HT_BIT_MASK 1 duke@435: uint32_t vendor_id[3] = { 0U, 0U, 0U }; duke@435: uint32_t value_of_eax = 0U; duke@435: uint32_t value_of_edx = 0U; duke@435: uint32_t dummy = 0U; duke@435: duke@435: /* Yes, this is supposed to be [0], [2], [1] */ duke@435: get_cpuid(0, &dummy, &vendor_id[0], &vendor_id[2], &vendor_id[1]); duke@435: if (_launcher_debug) { duke@435: printf("vendor: %c %c %c %c %c %c %c %c %c %c %c %c \n", duke@435: ((vendor_id[0] >> 0) & 0xff), duke@435: ((vendor_id[0] >> 8) & 0xff), duke@435: ((vendor_id[0] >> 16) & 0xff), duke@435: ((vendor_id[0] >> 24) & 0xff), duke@435: ((vendor_id[1] >> 0) & 0xff), duke@435: ((vendor_id[1] >> 8) & 0xff), duke@435: ((vendor_id[1] >> 16) & 0xff), duke@435: ((vendor_id[1] >> 24) & 0xff), duke@435: ((vendor_id[2] >> 0) & 0xff), duke@435: ((vendor_id[2] >> 8) & 0xff), duke@435: ((vendor_id[2] >> 16) & 0xff), duke@435: ((vendor_id[2] >> 24) & 0xff)); duke@435: } duke@435: get_cpuid(1, &value_of_eax, &dummy, &dummy, &value_of_edx); duke@435: if (_launcher_debug) { duke@435: printf("value_of_eax: 0x%x value_of_edx: 0x%x\n", duke@435: value_of_eax, value_of_edx); duke@435: } duke@435: if ((((value_of_eax >> FAMILY_ID_SHIFT) & FAMILY_ID_MASK) == PENTIUM4_FAMILY_ID) || duke@435: (((value_of_eax >> EXT_FAMILY_ID_SHIFT) & EXT_FAMILY_ID_MASK) != 0)) { duke@435: if ((((vendor_id[0] >> 0) & 0xff) == 'G') && duke@435: (((vendor_id[0] >> 8) & 0xff) == 'e') && duke@435: (((vendor_id[0] >> 16) & 0xff) == 'n') && duke@435: (((vendor_id[0] >> 24) & 0xff) == 'u') && duke@435: (((vendor_id[1] >> 0) & 0xff) == 'i') && duke@435: (((vendor_id[1] >> 8) & 0xff) == 'n') && duke@435: (((vendor_id[1] >> 16) & 0xff) == 'e') && duke@435: (((vendor_id[1] >> 24) & 0xff) == 'I') && duke@435: (((vendor_id[2] >> 0) & 0xff) == 'n') && duke@435: (((vendor_id[2] >> 8) & 0xff) == 't') && duke@435: (((vendor_id[2] >> 16) & 0xff) == 'e') && duke@435: (((vendor_id[2] >> 24) & 0xff) == 'l')) { duke@435: if (((value_of_edx >> HT_BIT_SHIFT) & HT_BIT_MASK) == HT_BIT_MASK) { duke@435: if (_launcher_debug) { duke@435: printf("Hyperthreading supported\n"); duke@435: } duke@435: result = hts_supported; duke@435: } else { duke@435: if (_launcher_debug) { duke@435: printf("Hyperthreading not supported\n"); duke@435: } duke@435: result = hts_not_supported; duke@435: } duke@435: } else { duke@435: if (_launcher_debug) { duke@435: printf("Not GenuineIntel\n"); duke@435: } duke@435: result = hts_not_intel; duke@435: } duke@435: } else { duke@435: if (_launcher_debug) { duke@435: printf("not Pentium 4 or extended\n"); duke@435: } duke@435: result = hts_not_pentium4; duke@435: } duke@435: return result; duke@435: } duke@435: duke@435: /* Determine how many logical processors there are per CPU */ duke@435: unsigned int duke@435: logical_processors_per_package(void) { duke@435: /* duke@435: * After CPUID with EAX==1, register EBX bits 23 through 16 duke@435: * indicate the number of logical processors per package duke@435: */ duke@435: # define NUM_LOGICAL_SHIFT 16 duke@435: # define NUM_LOGICAL_MASK 0xff duke@435: unsigned int result = 1U; duke@435: const HyperThreadingSupport hyperthreading = hyperthreading_support(); duke@435: duke@435: if (hyperthreading == hts_supported) { duke@435: uint32_t value_of_ebx = 0U; duke@435: uint32_t dummy = 0U; duke@435: duke@435: get_cpuid(1, &dummy, &value_of_ebx, &dummy, &dummy); duke@435: result = (value_of_ebx >> NUM_LOGICAL_SHIFT) & NUM_LOGICAL_MASK; duke@435: if (_launcher_debug) { duke@435: printf("logical processors per package: %u\n", result); duke@435: } duke@435: } duke@435: return result; duke@435: } duke@435: duke@435: /* Compute the number of physical processors, not logical processors */ duke@435: unsigned long duke@435: physical_processors(void) { duke@435: const long sys_processors = sysconf(_SC_NPROCESSORS_CONF); duke@435: unsigned long result = sys_processors; duke@435: duke@435: if (_launcher_debug) { duke@435: printf("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors); duke@435: } duke@435: if (sys_processors > 1) { duke@435: unsigned int logical_processors = logical_processors_per_package(); duke@435: if (logical_processors > 1) { duke@435: result = (unsigned long) sys_processors / logical_processors; duke@435: } duke@435: } duke@435: if (_launcher_debug) { duke@435: printf("physical processors: %lu\n", result); duke@435: } duke@435: return result; duke@435: } duke@435: duke@435: #endif /* i586 */ duke@435: duke@435: #if defined(__sun) && defined(i586) duke@435: duke@435: /* The definition of a server-class machine for solaris-i586/amd64 */ duke@435: jboolean duke@435: solaris_i586_ServerClassMachine(void) { duke@435: jboolean result = JNI_FALSE; duke@435: /* How big is a server class machine? */ duke@435: const unsigned long server_processors = 2UL; duke@435: const uint64_t server_memory = 2UL * GB; duke@435: /* duke@435: * We seem not to get our full complement of memory. duke@435: * We allow some part (1/8?) of the memory to be "missing", duke@435: * based on the sizes of DIMMs, and maybe graphics cards. duke@435: */ duke@435: const uint64_t missing_memory = 256UL * MB; duke@435: const uint64_t actual_memory = physical_memory(); duke@435: duke@435: /* Is this a server class machine? */ duke@435: if (actual_memory >= (server_memory - missing_memory)) { duke@435: const unsigned long actual_processors = physical_processors(); duke@435: if (actual_processors >= server_processors) { duke@435: result = JNI_TRUE; duke@435: } duke@435: } duke@435: if (_launcher_debug) { duke@435: printf("solaris_" ARCH "_ServerClassMachine: %s\n", duke@435: (result == JNI_TRUE ? "true" : "false")); duke@435: } duke@435: return result; duke@435: } duke@435: duke@435: #endif /* __sun && i586 */ duke@435: duke@435: #if defined(__linux__) && defined(i586) duke@435: duke@435: /* The definition of a server-class machine for linux-i586 */ duke@435: jboolean duke@435: linux_i586_ServerClassMachine(void) { duke@435: jboolean result = JNI_FALSE; duke@435: /* How big is a server class machine? */ duke@435: const unsigned long server_processors = 2UL; duke@435: const uint64_t server_memory = 2UL * GB; duke@435: /* duke@435: * We seem not to get our full complement of memory. duke@435: * We allow some part (1/8?) of the memory to be "missing", duke@435: * based on the sizes of DIMMs, and maybe graphics cards. duke@435: */ duke@435: const uint64_t missing_memory = 256UL * MB; duke@435: const uint64_t actual_memory = physical_memory(); duke@435: duke@435: /* Is this a server class machine? */ duke@435: if (actual_memory >= (server_memory - missing_memory)) { duke@435: const unsigned long actual_processors = physical_processors(); duke@435: if (actual_processors >= server_processors) { duke@435: result = JNI_TRUE; duke@435: } duke@435: } duke@435: if (_launcher_debug) { duke@435: printf("linux_" ARCH "_ServerClassMachine: %s\n", duke@435: (result == JNI_TRUE ? "true" : "false")); duke@435: } duke@435: return result; duke@435: } duke@435: duke@435: #endif /* __linux__ && i586 */ duke@435: duke@435: /* Dispatch to the platform-specific definition of "server-class" */ duke@435: jboolean duke@435: ServerClassMachine(void) { duke@435: jboolean result = JNI_FALSE; duke@435: #if defined(__sun) && defined(__sparc) duke@435: result = solaris_sparc_ServerClassMachine(); duke@435: #elif defined(__sun) && defined(i586) duke@435: result = solaris_i586_ServerClassMachine(); duke@435: #elif defined(__linux__) && defined(i586) duke@435: result = linux_i586_ServerClassMachine(); duke@435: #else duke@435: if (_launcher_debug) { duke@435: printf("ServerClassMachine: returns default value of %s\n", duke@435: (result == JNI_TRUE ? "true" : "false")); duke@435: } duke@435: #endif duke@435: return result; duke@435: } duke@435: duke@435: #endif /* ifndef GAMMA */ duke@435: duke@435: #ifndef GAMMA /* gamma launcher does not choose JDK/JRE/JVM */ duke@435: duke@435: /* duke@435: * Since using the file system as a registry is a bit risky, perform duke@435: * additional sanity checks on the identified directory to validate duke@435: * it as a valid jre/sdk. duke@435: * duke@435: * Return 0 if the tests fail; otherwise return non-zero (true). duke@435: * duke@435: * Note that checking for anything more than the existence of an duke@435: * executable object at bin/java relative to the path being checked duke@435: * will break the regression tests. duke@435: */ duke@435: static int duke@435: CheckSanity(char *path, char *dir) duke@435: { duke@435: char buffer[PATH_MAX]; duke@435: duke@435: if (strlen(path) + strlen(dir) + 11 > PATH_MAX) duke@435: return (0); /* Silently reject "impossibly" long paths */ duke@435: duke@435: (void)strcat(strcat(strcat(strcpy(buffer, path), "/"), dir), "/bin/java"); duke@435: return ((access(buffer, X_OK) == 0) ? 1 : 0); duke@435: } duke@435: duke@435: /* duke@435: * Determine if there is an acceptable JRE in the directory dirname. duke@435: * Upon locating the "best" one, return a fully qualified path to duke@435: * it. "Best" is defined as the most advanced JRE meeting the duke@435: * constraints contained in the manifest_info. If no JRE in this duke@435: * directory meets the constraints, return NULL. duke@435: * duke@435: * Note that we don't check for errors in reading the directory duke@435: * (which would be done by checking errno). This is because it duke@435: * doesn't matter if we get an error reading the directory, or duke@435: * we just don't find anything interesting in the directory. We duke@435: * just return NULL in either case. duke@435: * duke@435: * The historical names of j2sdk and j2re were changed to jdk and duke@435: * jre respecively as part of the 1.5 rebranding effort. Since the duke@435: * former names are legacy on Linux, they must be recognized for duke@435: * all time. Fortunately, this is a minor cost. duke@435: */ duke@435: static char duke@435: *ProcessDir(manifest_info *info, char *dirname) duke@435: { duke@435: DIR *dirp; duke@435: struct dirent *dp; duke@435: char *best = NULL; duke@435: int offset; duke@435: int best_offset = 0; duke@435: char *ret_str = NULL; duke@435: char buffer[PATH_MAX]; duke@435: duke@435: if ((dirp = opendir(dirname)) == NULL) duke@435: return (NULL); duke@435: duke@435: do { duke@435: if ((dp = readdir(dirp)) != NULL) { duke@435: offset = 0; duke@435: if ((strncmp(dp->d_name, "jre", 3) == 0) || duke@435: (strncmp(dp->d_name, "jdk", 3) == 0)) duke@435: offset = 3; duke@435: else if (strncmp(dp->d_name, "j2re", 4) == 0) duke@435: offset = 4; duke@435: else if (strncmp(dp->d_name, "j2sdk", 5) == 0) duke@435: offset = 5; duke@435: if (offset > 0) { duke@435: if ((acceptable_release(dp->d_name + offset, duke@435: info->jre_version)) && CheckSanity(dirname, dp->d_name)) duke@435: if ((best == NULL) || (exact_version_id( duke@435: dp->d_name + offset, best + best_offset) > 0)) { duke@435: if (best != NULL) duke@435: free(best); duke@435: best = strdup(dp->d_name); duke@435: best_offset = offset; duke@435: } duke@435: } duke@435: } duke@435: } while (dp != NULL); duke@435: (void) closedir(dirp); duke@435: if (best == NULL) duke@435: return (NULL); duke@435: else { duke@435: ret_str = MemAlloc(strlen(dirname) + strlen(best) + 2); duke@435: ret_str = strcat(strcat(strcpy(ret_str, dirname), "/"), best); duke@435: free(best); duke@435: return (ret_str); duke@435: } duke@435: } duke@435: duke@435: /* duke@435: * This is the global entry point. It examines the host for the optimal duke@435: * JRE to be used by scanning a set of directories. The set of directories duke@435: * is platform dependent and can be overridden by the environment duke@435: * variable JAVA_VERSION_PATH. duke@435: * duke@435: * This routine itself simply determines the set of appropriate duke@435: * directories before passing control onto ProcessDir(). duke@435: */ duke@435: char* duke@435: LocateJRE(manifest_info* info) duke@435: { duke@435: char *path; duke@435: char *home; duke@435: char *target = NULL; duke@435: char *dp; duke@435: char *cp; duke@435: duke@435: /* duke@435: * Start by getting JAVA_VERSION_PATH duke@435: */ duke@435: if (info->jre_restrict_search) duke@435: path = strdup(system_dir); duke@435: else if ((path = getenv("JAVA_VERSION_PATH")) != NULL) duke@435: path = strdup(path); duke@435: else duke@435: if ((home = getenv("HOME")) != NULL) { duke@435: path = (char *)MemAlloc(strlen(home) + 13); duke@435: path = strcat(strcat(strcat(strcpy(path, home), duke@435: user_dir), ":"), system_dir); duke@435: } else duke@435: path = strdup(system_dir); duke@435: duke@435: /* duke@435: * Step through each directory on the path. Terminate the scan with duke@435: * the first directory with an acceptable JRE. duke@435: */ duke@435: cp = dp = path; duke@435: while (dp != NULL) { duke@435: cp = strchr(dp, (int)':'); duke@435: if (cp != NULL) duke@435: *cp = (char)NULL; duke@435: if ((target = ProcessDir(info, dp)) != NULL) duke@435: break; duke@435: dp = cp; duke@435: if (dp != NULL) duke@435: dp++; duke@435: } duke@435: free(path); duke@435: return (target); duke@435: } duke@435: duke@435: /* duke@435: * Given a path to a jre to execute, this routine checks if this process duke@435: * is indeed that jre. If not, it exec's that jre. duke@435: * duke@435: * We want to actually check the paths rather than just the version string duke@435: * built into the executable, so that given version specification (and duke@435: * JAVA_VERSION_PATH) will yield the exact same Java environment, regardless duke@435: * of the version of the arbitrary launcher we start with. duke@435: */ duke@435: void duke@435: ExecJRE(char *jre, char **argv) duke@435: { duke@435: char wanted[PATH_MAX]; duke@435: char *execname; duke@435: char *progname; duke@435: duke@435: /* duke@435: * Resolve the real path to the directory containing the selected JRE. duke@435: */ duke@435: if (realpath(jre, wanted) == NULL) { duke@435: fprintf(stderr, "Unable to resolve %s\n", jre); duke@435: exit(1); duke@435: } duke@435: duke@435: /* duke@435: * Resolve the real path to the currently running launcher. duke@435: */ duke@435: execname = SetExecname(argv); duke@435: if (execname == NULL) { duke@435: fprintf(stderr, "Unable to resolve current executable\n"); duke@435: exit(1); duke@435: } duke@435: duke@435: /* duke@435: * If the path to the selected JRE directory is a match to the initial duke@435: * portion of the path to the currently executing JRE, we have a winner! duke@435: * If so, just return. duke@435: */ duke@435: if (strncmp(wanted, execname, strlen(wanted)) == 0) duke@435: return; /* I am the droid you were looking for */ duke@435: duke@435: /* duke@435: * If this isn't the selected version, exec the selected version. duke@435: */ duke@435: #ifdef JAVA_ARGS /* javac, jar and friends. */ duke@435: progname = "java"; duke@435: #else /* java, oldjava, javaw and friends */ duke@435: #ifdef PROGNAME duke@435: progname = PROGNAME; duke@435: #else duke@435: progname = *argv; duke@435: if ((s = strrchr(progname, FILE_SEPARATOR)) != 0) { duke@435: progname = s + 1; duke@435: } duke@435: #endif /* PROGNAME */ duke@435: #endif /* JAVA_ARGS */ duke@435: duke@435: /* duke@435: * This should never happen (because of the selection code in SelectJRE), duke@435: * but check for "impossibly" long path names just because buffer overruns duke@435: * can be so deadly. duke@435: */ duke@435: if (strlen(wanted) + strlen(progname) + 6 > PATH_MAX) { duke@435: fprintf(stderr, "Path length exceeds maximum length (PATH_MAX)\n"); duke@435: exit(1); duke@435: } duke@435: duke@435: /* duke@435: * Construct the path and exec it. duke@435: */ duke@435: (void)strcat(strcat(wanted, "/bin/"), progname); duke@435: argv[0] = progname; duke@435: if (_launcher_debug) { duke@435: int i; duke@435: printf("execv(\"%s\"", wanted); duke@435: for (i = 0; argv[i] != NULL; i++) duke@435: printf(", \"%s\"", argv[i]); duke@435: printf(")\n"); duke@435: } duke@435: execv(wanted, argv); duke@435: fprintf(stderr, "Exec of %s failed\n", wanted); duke@435: exit(1); duke@435: } duke@435: duke@435: #endif /* ifndef GAMMA */ duke@435: duke@435: /* duke@435: * "Borrowed" from Solaris 10 where the unsetenv() function is being added duke@435: * to libc thanks to SUSv3 (Standard Unix Specification, version 3). As duke@435: * such, in the fullness of time this will appear in libc on all relevant duke@435: * Solaris/Linux platforms and maybe even the Windows platform. At that duke@435: * time, this stub can be removed. duke@435: * duke@435: * This implementation removes the environment locking for multithreaded duke@435: * applications. (We don't have access to these mutexes within libc and duke@435: * the launcher isn't multithreaded.) Note that what remains is platform duke@435: * independent, because it only relies on attributes that a POSIX environment duke@435: * defines. duke@435: * duke@435: * Returns 0 on success, -1 on failure. duke@435: * duke@435: * Also removed was the setting of errno. The only value of errno set duke@435: * was EINVAL ("Invalid Argument"). duke@435: */ duke@435: duke@435: /* duke@435: * s1(environ) is name=value duke@435: * s2(name) is name(not the form of name=value). duke@435: * if names match, return value of 1, else return 0 duke@435: */ duke@435: static int duke@435: match_noeq(const char *s1, const char *s2) duke@435: { duke@435: while (*s1 == *s2++) { duke@435: if (*s1++ == '=') duke@435: return (1); duke@435: } duke@435: if (*s1 == '=' && s2[-1] == '\0') duke@435: return (1); duke@435: return (0); duke@435: } duke@435: duke@435: /* duke@435: * added for SUSv3 standard duke@435: * duke@435: * Delete entry from environ. duke@435: * Do not free() memory! Other threads may be using it. duke@435: * Keep it around forever. duke@435: */ duke@435: static int duke@435: borrowed_unsetenv(const char *name) duke@435: { duke@435: long idx; /* index into environ */ duke@435: duke@435: if (name == NULL || *name == '\0' || duke@435: strchr(name, '=') != NULL) { duke@435: return (-1); duke@435: } duke@435: duke@435: for (idx = 0; environ[idx] != NULL; idx++) { duke@435: if (match_noeq(environ[idx], name)) duke@435: break; duke@435: } duke@435: if (environ[idx] == NULL) { duke@435: /* name not found but still a success */ duke@435: return (0); duke@435: } duke@435: /* squeeze up one entry */ duke@435: do { duke@435: environ[idx] = environ[idx+1]; duke@435: } while (environ[++idx] != NULL); duke@435: duke@435: return (0); duke@435: } duke@435: /* --- End of "borrowed" code --- */ duke@435: duke@435: /* duke@435: * Wrapper for unsetenv() function. duke@435: */ duke@435: int duke@435: UnsetEnv(char *name) duke@435: { duke@435: return(borrowed_unsetenv(name)); duke@435: } ksrini@823: /* ksrini@823: * The implementation for finding classes from the bootstrap ksrini@823: * class loader, refer to java.h ksrini@823: */ ksrini@823: static FindClassFromBootLoader_t *findBootClass = NULL; ksrini@823: ksrini@823: jclass ksrini@823: FindBootStrapClass(JNIEnv *env, const char* classname) ksrini@823: { ksrini@823: if (findBootClass == NULL) { ksrini@823: findBootClass = (FindClassFromBootLoader_t *)dlsym(RTLD_DEFAULT, ksrini@823: "JVM_FindClassFromBootLoader"); ksrini@823: if (findBootClass == NULL) { ksrini@823: fprintf(stderr, "Error: could load method JVM_FindClassFromBootLoader"); ksrini@823: return NULL; ksrini@823: } ksrini@823: } ksrini@823: return findBootClass(env, classname, JNI_FALSE); ksrini@823: } ksrini@823: