src/os/posix/launcher/java_md.c

changeset 2327
cb2d0a362639
child 2369
aa6e219afbf1
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/os/posix/launcher/java_md.c	Thu Dec 02 05:45:54 2010 -0800
     1.3 @@ -0,0 +1,1878 @@
     1.4 +/*
     1.5 + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.23 + * or visit www.oracle.com if you need additional information or have any
    1.24 + * questions.
    1.25 + *
    1.26 + */
    1.27 +
    1.28 +
    1.29 +#include "java.h"
    1.30 +#include <dirent.h>
    1.31 +#include <dlfcn.h>
    1.32 +#include <fcntl.h>
    1.33 +#include <inttypes.h>
    1.34 +#include <stdio.h>
    1.35 +#include <string.h>
    1.36 +#include <stdlib.h>
    1.37 +#include <limits.h>
    1.38 +#include <sys/stat.h>
    1.39 +#include <unistd.h>
    1.40 +#include <sys/types.h>
    1.41 +
    1.42 +#ifndef GAMMA
    1.43 +#include "manifest_info.h"
    1.44 +#include "version_comp.h"
    1.45 +#endif
    1.46 +
    1.47 +#ifdef __linux__
    1.48 +#include <pthread.h>
    1.49 +#else
    1.50 +#include <thread.h>
    1.51 +#endif
    1.52 +
    1.53 +#define JVM_DLL "libjvm.so"
    1.54 +#define JAVA_DLL "libjava.so"
    1.55 +
    1.56 +#ifndef GAMMA   /* launcher.make defines ARCH */
    1.57 +/*
    1.58 + * If a processor / os combination has the ability to run binaries of
    1.59 + * two data models and cohabitation of jre/jdk bits with both data
    1.60 + * models is supported, then DUAL_MODE is defined.  When DUAL_MODE is
    1.61 + * defined, the architecture names for the narrow and wide version of
    1.62 + * the architecture are defined in LIBARCH64NAME and LIBARCH32NAME.  Currently
    1.63 + * only Solaris on sparc/sparcv9 and i586/amd64 is DUAL_MODE; linux
    1.64 + * i586/amd64 could be defined as DUAL_MODE but that is not the
    1.65 + * current policy.
    1.66 + */
    1.67 +
    1.68 +#ifndef LIBARCHNAME
    1.69 +#  error "The macro LIBARCHNAME was not defined on the compile line"
    1.70 +#endif
    1.71 +
    1.72 +#ifdef __sun
    1.73 +#  define DUAL_MODE
    1.74 +#  ifndef LIBARCH32NAME
    1.75 +#    error "The macro LIBARCH32NAME was not defined on the compile line"
    1.76 +#  endif
    1.77 +#  ifndef LIBARCH64NAME
    1.78 +#    error "The macro LIBARCH64NAME was not defined on the compile line"
    1.79 +#  endif
    1.80 +#  include <sys/systeminfo.h>
    1.81 +#  include <sys/elf.h>
    1.82 +#  include <stdio.h>
    1.83 +#endif
    1.84 +
    1.85 +#endif /* ifndef GAMMA */
    1.86 +
    1.87 +/* pointer to environment */
    1.88 +extern char **environ;
    1.89 +
    1.90 +#ifndef GAMMA
    1.91 +/*
    1.92 + *      A collection of useful strings. One should think of these as #define
    1.93 + *      entries, but actual strings can be more efficient (with many compilers).
    1.94 + */
    1.95 +#ifdef __linux__
    1.96 +static const char *system_dir   = "/usr/java";
    1.97 +static const char *user_dir     = "/java";
    1.98 +#else /* Solaris */
    1.99 +static const char *system_dir   = "/usr/jdk";
   1.100 +static const char *user_dir     = "/jdk";
   1.101 +#endif
   1.102 +
   1.103 +#endif /* ifndef GAMMA */
   1.104 +
   1.105 +/*
   1.106 + * Flowchart of launcher execs and options processing on unix
   1.107 + *
   1.108 + * The selection of the proper vm shared library to open depends on
   1.109 + * several classes of command line options, including vm "flavor"
   1.110 + * options (-client, -server) and the data model options, -d32  and
   1.111 + * -d64, as well as a version specification which may have come from
   1.112 + * the command line or from the manifest of an executable jar file.
   1.113 + * The vm selection options are not passed to the running
   1.114 + * virtual machine; they must be screened out by the launcher.
   1.115 + *
   1.116 + * The version specification (if any) is processed first by the
   1.117 + * platform independent routine SelectVersion.  This may result in
   1.118 + * the exec of the specified launcher version.
   1.119 + *
   1.120 + * Typically, the launcher execs at least once to ensure a suitable
   1.121 + * LD_LIBRARY_PATH is in effect for the process.  The first exec
   1.122 + * screens out all the data model options; leaving the choice of data
   1.123 + * model implicit in the binary selected to run.  However, in case no
   1.124 + * exec is done, the data model options are screened out before the vm
   1.125 + * is invoked.
   1.126 + *
   1.127 + *  incoming argv ------------------------------
   1.128 + *  |                                          |
   1.129 + * \|/                                         |
   1.130 + * CheckJVMType                                |
   1.131 + * (removes -client, -server, etc.)            |
   1.132 + *                                            \|/
   1.133 + *                                            CreateExecutionEnvironment
   1.134 + *                                            (removes -d32 and -d64,
   1.135 + *                                             determines desired data model,
   1.136 + *                                             sets up LD_LIBRARY_PATH,
   1.137 + *                                             and exec's)
   1.138 + *                                             |
   1.139 + *  --------------------------------------------
   1.140 + *  |
   1.141 + * \|/
   1.142 + * exec child 1 incoming argv -----------------
   1.143 + *  |                                          |
   1.144 + * \|/                                         |
   1.145 + * CheckJVMType                                |
   1.146 + * (removes -client, -server, etc.)            |
   1.147 + *  |                                         \|/
   1.148 + *  |                                          CreateExecutionEnvironment
   1.149 + *  |                                          (verifies desired data model
   1.150 + *  |                                           is running and acceptable
   1.151 + *  |                                           LD_LIBRARY_PATH;
   1.152 + *  |                                           no-op in child)
   1.153 + *  |
   1.154 + * \|/
   1.155 + * TranslateDashJArgs...
   1.156 + * (Prepare to pass args to vm)
   1.157 + *  |
   1.158 + *  |
   1.159 + *  |
   1.160 + * \|/
   1.161 + * ParseArguments
   1.162 + * (ignores -d32 and -d64,
   1.163 + *  processes version options,
   1.164 + *  creates argument list for vm,
   1.165 + *  etc.)
   1.166 + *
   1.167 + */
   1.168 +
   1.169 +static char *SetExecname(char **argv);
   1.170 +static char * GetExecname();
   1.171 +static jboolean GetJVMPath(const char *jrepath, const char *jvmtype,
   1.172 +                           char *jvmpath, jint jvmpathsize, char * arch);
   1.173 +static jboolean GetJREPath(char *path, jint pathsize, char * arch, jboolean speculative);
   1.174 +
   1.175 +#ifndef GAMMA
   1.176 +const char *
   1.177 +GetArch()
   1.178 +{
   1.179 +    return LIBARCHNAME;
   1.180 +}
   1.181 +#endif /* ifndef GAMMA */
   1.182 +
   1.183 +void
   1.184 +CreateExecutionEnvironment(int *_argcp,
   1.185 +                           char ***_argvp,
   1.186 +                           char jrepath[],
   1.187 +                           jint so_jrepath,
   1.188 +                           char jvmpath[],
   1.189 +                           jint so_jvmpath,
   1.190 +                           char **original_argv) {
   1.191 +  /*
   1.192 +   * First, determine if we are running the desired data model.  If we
   1.193 +   * are running the desired data model, all the error messages
   1.194 +   * associated with calling GetJREPath, ReadKnownVMs, etc. should be
   1.195 +   * output.  However, if we are not running the desired data model,
   1.196 +   * some of the errors should be suppressed since it is more
   1.197 +   * informative to issue an error message based on whether or not the
   1.198 +   * os/processor combination has dual mode capabilities.
   1.199 +   */
   1.200 +
   1.201 +    char *execname = NULL;
   1.202 +    int original_argc = *_argcp;
   1.203 +    jboolean jvmpathExists;
   1.204 +
   1.205 +    /* Compute the name of the executable */
   1.206 +    execname = SetExecname(*_argvp);
   1.207 +
   1.208 +#ifndef GAMMA
   1.209 +    /* Set the LD_LIBRARY_PATH environment variable, check data model
   1.210 +       flags, and exec process, if needed */
   1.211 +    {
   1.212 +      char *arch        = (char *)GetArch(); /* like sparc or sparcv9 */
   1.213 +      char * jvmtype    = NULL;
   1.214 +      int argc          = *_argcp;
   1.215 +      char **argv       = original_argv;
   1.216 +
   1.217 +      char *runpath     = NULL; /* existing effective LD_LIBRARY_PATH
   1.218 +                                   setting */
   1.219 +
   1.220 +      int running       =       /* What data model is being ILP32 =>
   1.221 +                                   32 bit vm; LP64 => 64 bit vm */
   1.222 +#ifdef _LP64
   1.223 +        64;
   1.224 +#else
   1.225 +      32;
   1.226 +#endif
   1.227 +
   1.228 +      int wanted        = running;      /* What data mode is being
   1.229 +                                           asked for? Current model is
   1.230 +                                           fine unless another model
   1.231 +                                           is asked for */
   1.232 +
   1.233 +      char* new_runpath = NULL; /* desired new LD_LIBRARY_PATH string */
   1.234 +      char* newpath     = NULL; /* path on new LD_LIBRARY_PATH */
   1.235 +      char* lastslash   = NULL;
   1.236 +
   1.237 +      char** newenvp    = NULL; /* current environment */
   1.238 +
   1.239 +      char** newargv    = NULL;
   1.240 +      int    newargc    = 0;
   1.241 +#ifdef __sun
   1.242 +      char*  dmpath     = NULL;  /* data model specific LD_LIBRARY_PATH,
   1.243 +                                    Solaris only */
   1.244 +#endif
   1.245 +
   1.246 +      /*
   1.247 +       * Starting in 1.5, all unix platforms accept the -d32 and -d64
   1.248 +       * options.  On platforms where only one data-model is supported
   1.249 +       * (e.g. ia-64 Linux), using the flag for the other data model is
   1.250 +       * an error and will terminate the program.
   1.251 +       */
   1.252 +
   1.253 +      { /* open new scope to declare local variables */
   1.254 +        int i;
   1.255 +
   1.256 +        newargv = (char **)JLI_MemAlloc((argc+1) * sizeof(*newargv));
   1.257 +        newargv[newargc++] = argv[0];
   1.258 +
   1.259 +        /* scan for data model arguments and remove from argument list;
   1.260 +           last occurrence determines desired data model */
   1.261 +        for (i=1; i < argc; i++) {
   1.262 +
   1.263 +          if (strcmp(argv[i], "-J-d64") == 0 || strcmp(argv[i], "-d64") == 0) {
   1.264 +            wanted = 64;
   1.265 +            continue;
   1.266 +          }
   1.267 +          if (strcmp(argv[i], "-J-d32") == 0 || strcmp(argv[i], "-d32") == 0) {
   1.268 +            wanted = 32;
   1.269 +            continue;
   1.270 +          }
   1.271 +          newargv[newargc++] = argv[i];
   1.272 +
   1.273 +#ifdef JAVA_ARGS
   1.274 +          if (argv[i][0] != '-')
   1.275 +            continue;
   1.276 +#else
   1.277 +          if (strcmp(argv[i], "-classpath") == 0 || strcmp(argv[i], "-cp") == 0) {
   1.278 +            i++;
   1.279 +            if (i >= argc) break;
   1.280 +            newargv[newargc++] = argv[i];
   1.281 +            continue;
   1.282 +          }
   1.283 +          if (argv[i][0] != '-') { i++; break; }
   1.284 +#endif
   1.285 +        }
   1.286 +
   1.287 +        /* copy rest of args [i .. argc) */
   1.288 +        while (i < argc) {
   1.289 +          newargv[newargc++] = argv[i++];
   1.290 +        }
   1.291 +        newargv[newargc] = NULL;
   1.292 +
   1.293 +        /*
   1.294 +         * newargv has all proper arguments here
   1.295 +         */
   1.296 +
   1.297 +        argc = newargc;
   1.298 +        argv = newargv;
   1.299 +      }
   1.300 +
   1.301 +      /* If the data model is not changing, it is an error if the
   1.302 +         jvmpath does not exist */
   1.303 +      if (wanted == running) {
   1.304 +        /* Find out where the JRE is that we will be using. */
   1.305 +        if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) {
   1.306 +          fprintf(stderr, "Error: could not find Java 2 Runtime Environment.\n");
   1.307 +          exit(2);
   1.308 +        }
   1.309 +
   1.310 +        /* Find the specified JVM type */
   1.311 +        if (ReadKnownVMs(jrepath, arch, JNI_FALSE) < 1) {
   1.312 +          fprintf(stderr, "Error: no known VMs. (check for corrupt jvm.cfg file)\n");
   1.313 +          exit(1);
   1.314 +        }
   1.315 +
   1.316 +        jvmpath[0] = '\0';
   1.317 +        jvmtype = CheckJvmType(_argcp, _argvp, JNI_FALSE);
   1.318 +
   1.319 +        if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch )) {
   1.320 +          fprintf(stderr, "Error: no `%s' JVM at `%s'.\n", jvmtype, jvmpath);
   1.321 +          exit(4);
   1.322 +        }
   1.323 +      } else {  /* do the same speculatively or exit */
   1.324 +#ifdef DUAL_MODE
   1.325 +        if (running != wanted) {
   1.326 +          /* Find out where the JRE is that we will be using. */
   1.327 +          if (!GetJREPath(jrepath, so_jrepath, ((wanted==64)?LIBARCH64NAME:LIBARCH32NAME), JNI_TRUE)) {
   1.328 +            goto EndDataModelSpeculate;
   1.329 +          }
   1.330 +
   1.331 +          /*
   1.332 +           * Read in jvm.cfg for target data model and process vm
   1.333 +           * selection options.
   1.334 +           */
   1.335 +          if (ReadKnownVMs(jrepath, ((wanted==64)?LIBARCH64NAME:LIBARCH32NAME), JNI_TRUE) < 1) {
   1.336 +            goto EndDataModelSpeculate;
   1.337 +          }
   1.338 +          jvmpath[0] = '\0';
   1.339 +          jvmtype = CheckJvmType(_argcp, _argvp, JNI_TRUE);
   1.340 +          /* exec child can do error checking on the existence of the path */
   1.341 +          jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath,
   1.342 +                                     ((wanted==64)?LIBARCH64NAME:LIBARCH32NAME));
   1.343 +
   1.344 +        }
   1.345 +      EndDataModelSpeculate: /* give up and let other code report error message */
   1.346 +        ;
   1.347 +#else
   1.348 +        fprintf(stderr, "Running a %d-bit JVM is not supported on this platform.\n", wanted);
   1.349 +        exit(1);
   1.350 +#endif
   1.351 +      }
   1.352 +
   1.353 +      /*
   1.354 +       * We will set the LD_LIBRARY_PATH as follows:
   1.355 +       *
   1.356 +       *     o          $JVMPATH (directory portion only)
   1.357 +       *     o          $JRE/lib/$LIBARCHNAME
   1.358 +       *     o          $JRE/../lib/$LIBARCHNAME
   1.359 +       *
   1.360 +       * followed by the user's previous effective LD_LIBRARY_PATH, if
   1.361 +       * any.
   1.362 +       */
   1.363 +
   1.364 +#ifdef __sun
   1.365 +      /*
   1.366 +       * Starting in Solaris 7, ld.so.1 supports three LD_LIBRARY_PATH
   1.367 +       * variables:
   1.368 +       *
   1.369 +       * 1. LD_LIBRARY_PATH -- used for 32 and 64 bit searches if
   1.370 +       * data-model specific variables are not set.
   1.371 +       *
   1.372 +       * 2. LD_LIBRARY_PATH_64 -- overrides and replaces LD_LIBRARY_PATH
   1.373 +       * for 64-bit binaries.
   1.374 +       *
   1.375 +       * 3. LD_LIBRARY_PATH_32 -- overrides and replaces LD_LIBRARY_PATH
   1.376 +       * for 32-bit binaries.
   1.377 +       *
   1.378 +       * The vm uses LD_LIBRARY_PATH to set the java.library.path system
   1.379 +       * property.  To shield the vm from the complication of multiple
   1.380 +       * LD_LIBRARY_PATH variables, if the appropriate data model
   1.381 +       * specific variable is set, we will act as if LD_LIBRARY_PATH had
   1.382 +       * the value of the data model specific variant and the data model
   1.383 +       * specific variant will be unset.  Note that the variable for the
   1.384 +       * *wanted* data model must be used (if it is set), not simply the
   1.385 +       * current running data model.
   1.386 +       */
   1.387 +
   1.388 +      switch(wanted) {
   1.389 +      case 0:
   1.390 +        if(running == 32) {
   1.391 +          dmpath = getenv("LD_LIBRARY_PATH_32");
   1.392 +          wanted = 32;
   1.393 +        }
   1.394 +        else {
   1.395 +          dmpath = getenv("LD_LIBRARY_PATH_64");
   1.396 +          wanted = 64;
   1.397 +        }
   1.398 +        break;
   1.399 +
   1.400 +      case 32:
   1.401 +        dmpath = getenv("LD_LIBRARY_PATH_32");
   1.402 +        break;
   1.403 +
   1.404 +      case 64:
   1.405 +        dmpath = getenv("LD_LIBRARY_PATH_64");
   1.406 +        break;
   1.407 +
   1.408 +      default:
   1.409 +        fprintf(stderr, "Improper value at line %d.", __LINE__);
   1.410 +        exit(1); /* unknown value in wanted */
   1.411 +        break;
   1.412 +      }
   1.413 +
   1.414 +      /*
   1.415 +       * If dmpath is NULL, the relevant data model specific variable is
   1.416 +       * not set and normal LD_LIBRARY_PATH should be used.
   1.417 +       */
   1.418 +      if( dmpath == NULL) {
   1.419 +        runpath = getenv("LD_LIBRARY_PATH");
   1.420 +      }
   1.421 +      else {
   1.422 +        runpath = dmpath;
   1.423 +      }
   1.424 +#else
   1.425 +      /*
   1.426 +       * If not on Solaris, assume only a single LD_LIBRARY_PATH
   1.427 +       * variable.
   1.428 +       */
   1.429 +      runpath = getenv("LD_LIBRARY_PATH");
   1.430 +#endif /* __sun */
   1.431 +
   1.432 +#ifdef __linux
   1.433 +      /*
   1.434 +       * On linux, if a binary is running as sgid or suid, glibc sets
   1.435 +       * LD_LIBRARY_PATH to the empty string for security purposes.  (In
   1.436 +       * contrast, on Solaris the LD_LIBRARY_PATH variable for a
   1.437 +       * privileged binary does not lose its settings; but the dynamic
   1.438 +       * linker does apply more scrutiny to the path.) The launcher uses
   1.439 +       * the value of LD_LIBRARY_PATH to prevent an exec loop.
   1.440 +       * Therefore, if we are running sgid or suid, this function's
   1.441 +       * setting of LD_LIBRARY_PATH will be ineffective and we should
   1.442 +       * return from the function now.  Getting the right libraries to
   1.443 +       * be found must be handled through other mechanisms.
   1.444 +       */
   1.445 +      if((getgid() != getegid()) || (getuid() != geteuid()) ) {
   1.446 +        return;
   1.447 +      }
   1.448 +#endif
   1.449 +
   1.450 +      /* runpath contains current effective LD_LIBRARY_PATH setting */
   1.451 +
   1.452 +      jvmpath = JLI_StringDup(jvmpath);
   1.453 +      new_runpath = JLI_MemAlloc( ((runpath!=NULL)?strlen(runpath):0) +
   1.454 +                              2*strlen(jrepath) + 2*strlen(arch) +
   1.455 +                              strlen(jvmpath) + 52);
   1.456 +      newpath = new_runpath + strlen("LD_LIBRARY_PATH=");
   1.457 +
   1.458 +
   1.459 +      /*
   1.460 +       * Create desired LD_LIBRARY_PATH value for target data model.
   1.461 +       */
   1.462 +      {
   1.463 +        /* remove the name of the .so from the JVM path */
   1.464 +        lastslash = strrchr(jvmpath, '/');
   1.465 +        if (lastslash)
   1.466 +          *lastslash = '\0';
   1.467 +
   1.468 +
   1.469 +        /* jvmpath, ((running != wanted)?((wanted==64)?"/"LIBARCH64NAME:"/.."):""), */
   1.470 +
   1.471 +        sprintf(new_runpath, "LD_LIBRARY_PATH="
   1.472 +                "%s:"
   1.473 +                "%s/lib/%s:"
   1.474 +                "%s/../lib/%s",
   1.475 +                jvmpath,
   1.476 +#ifdef DUAL_MODE
   1.477 +                jrepath, ((wanted==64)?LIBARCH64NAME:LIBARCH32NAME),
   1.478 +                jrepath, ((wanted==64)?LIBARCH64NAME:LIBARCH32NAME)
   1.479 +#else
   1.480 +                jrepath, arch,
   1.481 +                jrepath, arch
   1.482 +#endif
   1.483 +                );
   1.484 +
   1.485 +
   1.486 +        /*
   1.487 +         * Check to make sure that the prefix of the current path is the
   1.488 +         * desired environment variable setting.
   1.489 +         */
   1.490 +        if (runpath != NULL &&
   1.491 +            strncmp(newpath, runpath, strlen(newpath))==0 &&
   1.492 +            (runpath[strlen(newpath)] == 0 || runpath[strlen(newpath)] == ':') &&
   1.493 +            (running == wanted) /* data model does not have to be changed */
   1.494 +#ifdef __sun
   1.495 +            && (dmpath == NULL)    /* data model specific variables not set  */
   1.496 +#endif
   1.497 +            ) {
   1.498 +
   1.499 +          return;
   1.500 +
   1.501 +        }
   1.502 +      }
   1.503 +
   1.504 +      /*
   1.505 +       * Place the desired environment setting onto the prefix of
   1.506 +       * LD_LIBRARY_PATH.  Note that this prevents any possible infinite
   1.507 +       * loop of execv() because we test for the prefix, above.
   1.508 +       */
   1.509 +      if (runpath != 0) {
   1.510 +        strcat(new_runpath, ":");
   1.511 +        strcat(new_runpath, runpath);
   1.512 +      }
   1.513 +
   1.514 +      if( putenv(new_runpath) != 0) {
   1.515 +        exit(1); /* problem allocating memory; LD_LIBRARY_PATH not set
   1.516 +                    properly */
   1.517 +      }
   1.518 +
   1.519 +      /*
   1.520 +       * Unix systems document that they look at LD_LIBRARY_PATH only
   1.521 +       * once at startup, so we have to re-exec the current executable
   1.522 +       * to get the changed environment variable to have an effect.
   1.523 +       */
   1.524 +
   1.525 +#ifdef __sun
   1.526 +      /*
   1.527 +       * If dmpath is not NULL, remove the data model specific string
   1.528 +       * in the environment for the exec'ed child.
   1.529 +       */
   1.530 +
   1.531 +      if( dmpath != NULL)
   1.532 +        (void)UnsetEnv((wanted==32)?"LD_LIBRARY_PATH_32":"LD_LIBRARY_PATH_64");
   1.533 +#endif
   1.534 +
   1.535 +      newenvp = environ;
   1.536 +
   1.537 +      {
   1.538 +        char *newexec = execname;
   1.539 +#ifdef DUAL_MODE
   1.540 +        /*
   1.541 +         * If the data model is being changed, the path to the
   1.542 +         * executable must be updated accordingly; the executable name
   1.543 +         * and directory the executable resides in are separate.  In the
   1.544 +         * case of 32 => 64, the new bits are assumed to reside in, e.g.
   1.545 +         * "olddir/LIBARCH64NAME/execname"; in the case of 64 => 32,
   1.546 +         * the bits are assumed to be in "olddir/../execname".  For example,
   1.547 +         *
   1.548 +         * olddir/sparcv9/execname
   1.549 +         * olddir/amd64/execname
   1.550 +         *
   1.551 +         * for Solaris SPARC and Linux amd64, respectively.
   1.552 +         */
   1.553 +
   1.554 +        if (running != wanted) {
   1.555 +          char *oldexec = strcpy(JLI_MemAlloc(strlen(execname) + 1), execname);
   1.556 +          char *olddir = oldexec;
   1.557 +          char *oldbase = strrchr(oldexec, '/');
   1.558 +
   1.559 +
   1.560 +          newexec = JLI_MemAlloc(strlen(execname) + 20);
   1.561 +          *oldbase++ = 0;
   1.562 +          sprintf(newexec, "%s/%s/%s", olddir,
   1.563 +                  ((wanted==64) ? LIBARCH64NAME : ".."), oldbase);
   1.564 +          argv[0] = newexec;
   1.565 +        }
   1.566 +#endif
   1.567 +
   1.568 +        (void)fflush(stdout);
   1.569 +        (void)fflush(stderr);
   1.570 +        execve(newexec, argv, newenvp);
   1.571 +        perror("execve()");
   1.572 +
   1.573 +        fprintf(stderr, "Error trying to exec %s.\n", newexec);
   1.574 +        fprintf(stderr, "Check if file exists and permissions are set correctly.\n");
   1.575 +
   1.576 +#ifdef DUAL_MODE
   1.577 +        if (running != wanted) {
   1.578 +          fprintf(stderr, "Failed to start a %d-bit JVM process from a %d-bit JVM.\n",
   1.579 +                  wanted, running);
   1.580 +#  ifdef __sun
   1.581 +
   1.582 +#    ifdef __sparc
   1.583 +          fprintf(stderr, "Verify all necessary J2SE components have been installed.\n" );
   1.584 +          fprintf(stderr,
   1.585 +                  "(Solaris SPARC 64-bit components must be installed after 32-bit components.)\n" );
   1.586 +#    else
   1.587 +          fprintf(stderr, "Either 64-bit processes are not supported by this platform\n");
   1.588 +          fprintf(stderr, "or the 64-bit components have not been installed.\n");
   1.589 +#    endif
   1.590 +        }
   1.591 +#  endif
   1.592 +#endif
   1.593 +
   1.594 +      }
   1.595 +
   1.596 +      exit(1);
   1.597 +    }
   1.598 +
   1.599 +#else  /* ifndef GAMMA */
   1.600 +
   1.601 +  /*
   1.602 +   * gamma launcher is simpler in that it doesn't handle VM flavors, data
   1.603 +   * model, LD_LIBRARY_PATH, etc. Assuming everything is set-up correctly
   1.604 +   * all we need to do here is to return correct path names. See also
   1.605 +   * GetJVMPath() and GetApplicationHome().
   1.606 +   */
   1.607 +
   1.608 +  { char *arch = (char *) ARCH; /* like sparc or sparcv9 */
   1.609 +    char *p;
   1.610 +
   1.611 +    if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) {
   1.612 +      fprintf(stderr, "Error: could not find Java 2 Runtime Environment.\n");
   1.613 +      exit(2);
   1.614 +    }
   1.615 +
   1.616 +    if (!GetJVMPath(jrepath, NULL, jvmpath, so_jvmpath, arch )) {
   1.617 +      fprintf(stderr, "Error: no JVM at `%s'.\n", jvmpath);
   1.618 +      exit(4);
   1.619 +    }
   1.620 +  }
   1.621 +
   1.622 +#endif  /* ifndef GAMMA */
   1.623 +}
   1.624 +
   1.625 +
   1.626 +/*
   1.627 + * On Solaris VM choosing is done by the launcher (java.c).
   1.628 + */
   1.629 +static jboolean
   1.630 +GetJVMPath(const char *jrepath, const char *jvmtype,
   1.631 +           char *jvmpath, jint jvmpathsize, char * arch)
   1.632 +{
   1.633 +    struct stat s;
   1.634 +
   1.635 +#ifndef GAMMA
   1.636 +    if (strchr(jvmtype, '/')) {
   1.637 +        sprintf(jvmpath, "%s/" JVM_DLL, jvmtype);
   1.638 +    } else {
   1.639 +        sprintf(jvmpath, "%s/lib/%s/%s/" JVM_DLL, jrepath, arch, jvmtype);
   1.640 +    }
   1.641 +#else
   1.642 +    /*
   1.643 +     * For gamma launcher, JVM is either built-in or in the same directory.
   1.644 +     * Either way we return "<exe_path>/libjvm.so" where <exe_path> is the
   1.645 +     * directory where gamma launcher is located.
   1.646 +     */
   1.647 +
   1.648 +    char *p;
   1.649 +
   1.650 +    snprintf(jvmpath, jvmpathsize, "%s", GetExecname());
   1.651 +    p = strrchr(jvmpath, '/');
   1.652 +    if (p) {
   1.653 +       /* replace executable name with libjvm.so */
   1.654 +       snprintf(p + 1, jvmpathsize - (p + 1 - jvmpath), "%s", JVM_DLL);
   1.655 +    } else {
   1.656 +       /* this case shouldn't happen */
   1.657 +       snprintf(jvmpath, jvmpathsize, "%s", JVM_DLL);
   1.658 +    }
   1.659 +#endif /* ifndef GAMMA */
   1.660 +
   1.661 +    if (_launcher_debug)
   1.662 +      printf("Does `%s' exist ... ", jvmpath);
   1.663 +
   1.664 +    if (stat(jvmpath, &s) == 0) {
   1.665 +        if (_launcher_debug)
   1.666 +          printf("yes.\n");
   1.667 +        return JNI_TRUE;
   1.668 +    } else {
   1.669 +        if (_launcher_debug)
   1.670 +          printf("no.\n");
   1.671 +        return JNI_FALSE;
   1.672 +    }
   1.673 +}
   1.674 +
   1.675 +/*
   1.676 + * Find path to JRE based on .exe's location or registry settings.
   1.677 + */
   1.678 +static jboolean
   1.679 +GetJREPath(char *path, jint pathsize, char * arch, jboolean speculative)
   1.680 +{
   1.681 +    char libjava[MAXPATHLEN];
   1.682 +
   1.683 +    if (GetApplicationHome(path, pathsize)) {
   1.684 +        /* Is JRE co-located with the application? */
   1.685 +        sprintf(libjava, "%s/lib/%s/" JAVA_DLL, path, arch);
   1.686 +        if (access(libjava, F_OK) == 0) {
   1.687 +            goto found;
   1.688 +        }
   1.689 +
   1.690 +        /* Does the app ship a private JRE in <apphome>/jre directory? */
   1.691 +        sprintf(libjava, "%s/jre/lib/%s/" JAVA_DLL, path, arch);
   1.692 +        if (access(libjava, F_OK) == 0) {
   1.693 +            strcat(path, "/jre");
   1.694 +            goto found;
   1.695 +        }
   1.696 +    }
   1.697 +
   1.698 +    if (!speculative)
   1.699 +      fprintf(stderr, "Error: could not find " JAVA_DLL "\n");
   1.700 +    return JNI_FALSE;
   1.701 +
   1.702 + found:
   1.703 +    if (_launcher_debug)
   1.704 +      printf("JRE path is %s\n", path);
   1.705 +    return JNI_TRUE;
   1.706 +}
   1.707 +
   1.708 +jboolean
   1.709 +LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
   1.710 +{
   1.711 +#ifdef GAMMA
   1.712 +    /* JVM is directly linked with gamma launcher; no dlopen() */
   1.713 +    ifn->CreateJavaVM = JNI_CreateJavaVM;
   1.714 +    ifn->GetDefaultJavaVMInitArgs = JNI_GetDefaultJavaVMInitArgs;
   1.715 +    return JNI_TRUE;
   1.716 +#else
   1.717 +   Dl_info dlinfo;
   1.718 +    void *libjvm;
   1.719 +
   1.720 +    if (_launcher_debug) {
   1.721 +        printf("JVM path is %s\n", jvmpath);
   1.722 +    }
   1.723 +
   1.724 +    libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
   1.725 +    if (libjvm == NULL) {
   1.726 +#if defined(__sparc) && !defined(_LP64) /* i.e. 32-bit sparc */
   1.727 +      FILE * fp;
   1.728 +      Elf32_Ehdr elf_head;
   1.729 +      int count;
   1.730 +      int location;
   1.731 +
   1.732 +      fp = fopen(jvmpath, "r");
   1.733 +      if(fp == NULL)
   1.734 +        goto error;
   1.735 +
   1.736 +      /* read in elf header */
   1.737 +      count = fread((void*)(&elf_head), sizeof(Elf32_Ehdr), 1, fp);
   1.738 +      fclose(fp);
   1.739 +      if(count < 1)
   1.740 +        goto error;
   1.741 +
   1.742 +      /*
   1.743 +       * Check for running a server vm (compiled with -xarch=v8plus)
   1.744 +       * on a stock v8 processor.  In this case, the machine type in
   1.745 +       * the elf header would not be included the architecture list
   1.746 +       * provided by the isalist command, which is turn is gotten from
   1.747 +       * sysinfo.  This case cannot occur on 64-bit hardware and thus
   1.748 +       * does not have to be checked for in binaries with an LP64 data
   1.749 +       * model.
   1.750 +       */
   1.751 +      if(elf_head.e_machine == EM_SPARC32PLUS) {
   1.752 +        char buf[257];  /* recommended buffer size from sysinfo man
   1.753 +                           page */
   1.754 +        long length;
   1.755 +        char* location;
   1.756 +
   1.757 +        length = sysinfo(SI_ISALIST, buf, 257);
   1.758 +        if(length > 0) {
   1.759 +          location = strstr(buf, "sparcv8plus ");
   1.760 +          if(location == NULL) {
   1.761 +            fprintf(stderr, "SPARC V8 processor detected; Server compiler requires V9 or better.\n");
   1.762 +            fprintf(stderr, "Use Client compiler on V8 processors.\n");
   1.763 +            fprintf(stderr, "Could not create the Java virtual machine.\n");
   1.764 +            return JNI_FALSE;
   1.765 +          }
   1.766 +        }
   1.767 +      }
   1.768 +#endif
   1.769 +      fprintf(stderr, "dl failure on line %d", __LINE__);
   1.770 +      goto error;
   1.771 +    }
   1.772 +
   1.773 +    ifn->CreateJavaVM = (CreateJavaVM_t)
   1.774 +      dlsym(libjvm, "JNI_CreateJavaVM");
   1.775 +    if (ifn->CreateJavaVM == NULL)
   1.776 +        goto error;
   1.777 +
   1.778 +    ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
   1.779 +        dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
   1.780 +    if (ifn->GetDefaultJavaVMInitArgs == NULL)
   1.781 +      goto error;
   1.782 +
   1.783 +    return JNI_TRUE;
   1.784 +
   1.785 +error:
   1.786 +    fprintf(stderr, "Error: failed %s, because %s\n", jvmpath, dlerror());
   1.787 +    return JNI_FALSE;
   1.788 +#endif /* ifndef GAMMA */
   1.789 +}
   1.790 +
   1.791 +/*
   1.792 + * If app is "/foo/bin/javac", or "/foo/bin/sparcv9/javac" then put
   1.793 + * "/foo" into buf.
   1.794 + */
   1.795 +jboolean
   1.796 +GetApplicationHome(char *buf, jint bufsize)
   1.797 +{
   1.798 +#ifdef __linux__
   1.799 +    char *execname = GetExecname();
   1.800 +    if (execname) {
   1.801 +        strncpy(buf, execname, bufsize-1);
   1.802 +        buf[bufsize-1] = '\0';
   1.803 +    } else {
   1.804 +        return JNI_FALSE;
   1.805 +    }
   1.806 +#else
   1.807 +    Dl_info dlinfo;
   1.808 +
   1.809 +    dladdr((void *)GetApplicationHome, &dlinfo);
   1.810 +    if (realpath(dlinfo.dli_fname, buf) == NULL) {
   1.811 +        fprintf(stderr, "Error: realpath(`%s') failed.\n", dlinfo.dli_fname);
   1.812 +        return JNI_FALSE;
   1.813 +    }
   1.814 +#endif
   1.815 +
   1.816 +#ifdef GAMMA
   1.817 +    {
   1.818 +       /* gamma launcher uses JAVA_HOME or ALT_JAVA_HOME environment variable to find JDK/JRE */
   1.819 +       char* java_home_var = getenv("ALT_JAVA_HOME");
   1.820 +       if (java_home_var == NULL) {
   1.821 +          java_home_var = getenv("JAVA_HOME");
   1.822 +       }
   1.823 +       if (java_home_var == NULL) {
   1.824 +          printf("JAVA_HOME or ALT_JAVA_HOME must point to a valid JDK/JRE to run gamma\n");
   1.825 +          return JNI_FALSE;
   1.826 +       }
   1.827 +       snprintf(buf, bufsize, "%s", java_home_var);
   1.828 +    }
   1.829 +#else
   1.830 +    if (strrchr(buf, '/') == 0) {
   1.831 +        buf[0] = '\0';
   1.832 +        return JNI_FALSE;
   1.833 +    }
   1.834 +    *(strrchr(buf, '/')) = '\0';        /* executable file      */
   1.835 +    if (strlen(buf) < 4 || strrchr(buf, '/') == 0) {
   1.836 +        buf[0] = '\0';
   1.837 +        return JNI_FALSE;
   1.838 +    }
   1.839 +    if (strcmp("/bin", buf + strlen(buf) - 4) != 0)
   1.840 +        *(strrchr(buf, '/')) = '\0';    /* sparcv9 or amd64     */
   1.841 +    if (strlen(buf) < 4 || strcmp("/bin", buf + strlen(buf) - 4) != 0) {
   1.842 +        buf[0] = '\0';
   1.843 +        return JNI_FALSE;
   1.844 +    }
   1.845 +    *(strrchr(buf, '/')) = '\0';        /* bin                  */
   1.846 +#endif /* ifndef GAMMA */
   1.847 +
   1.848 +    return JNI_TRUE;
   1.849 +}
   1.850 +
   1.851 +
   1.852 +/*
   1.853 + * Return true if the named program exists
   1.854 + */
   1.855 +static int
   1.856 +ProgramExists(char *name)
   1.857 +{
   1.858 +    struct stat sb;
   1.859 +    if (stat(name, &sb) != 0) return 0;
   1.860 +    if (S_ISDIR(sb.st_mode)) return 0;
   1.861 +    return (sb.st_mode & S_IEXEC) != 0;
   1.862 +}
   1.863 +
   1.864 +
   1.865 +/*
   1.866 + * Find a command in a directory, returning the path.
   1.867 + */
   1.868 +static char *
   1.869 +Resolve(char *indir, char *cmd)
   1.870 +{
   1.871 +    char name[PATH_MAX + 2], *real;
   1.872 +
   1.873 +    if ((strlen(indir) + strlen(cmd) + 1)  > PATH_MAX) return 0;
   1.874 +    sprintf(name, "%s%c%s", indir, FILE_SEPARATOR, cmd);
   1.875 +    if (!ProgramExists(name)) return 0;
   1.876 +    real = JLI_MemAlloc(PATH_MAX + 2);
   1.877 +    if (!realpath(name, real))
   1.878 +        strcpy(real, name);
   1.879 +    return real;
   1.880 +}
   1.881 +
   1.882 +
   1.883 +/*
   1.884 + * Find a path for the executable
   1.885 + */
   1.886 +static char *
   1.887 +FindExecName(char *program)
   1.888 +{
   1.889 +    char cwdbuf[PATH_MAX+2];
   1.890 +    char *path;
   1.891 +    char *tmp_path;
   1.892 +    char *f;
   1.893 +    char *result = NULL;
   1.894 +
   1.895 +    /* absolute path? */
   1.896 +    if (*program == FILE_SEPARATOR ||
   1.897 +        (FILE_SEPARATOR=='\\' && strrchr(program, ':')))
   1.898 +        return Resolve("", program+1);
   1.899 +
   1.900 +    /* relative path? */
   1.901 +    if (strrchr(program, FILE_SEPARATOR) != 0) {
   1.902 +        char buf[PATH_MAX+2];
   1.903 +        return Resolve(getcwd(cwdbuf, sizeof(cwdbuf)), program);
   1.904 +    }
   1.905 +
   1.906 +    /* from search path? */
   1.907 +    path = getenv("PATH");
   1.908 +    if (!path || !*path) path = ".";
   1.909 +    tmp_path = JLI_MemAlloc(strlen(path) + 2);
   1.910 +    strcpy(tmp_path, path);
   1.911 +
   1.912 +    for (f=tmp_path; *f && result==0; ) {
   1.913 +        char *s = f;
   1.914 +        while (*f && (*f != PATH_SEPARATOR)) ++f;
   1.915 +        if (*f) *f++ = 0;
   1.916 +        if (*s == FILE_SEPARATOR)
   1.917 +            result = Resolve(s, program);
   1.918 +        else {
   1.919 +            /* relative path element */
   1.920 +            char dir[2*PATH_MAX];
   1.921 +            sprintf(dir, "%s%c%s", getcwd(cwdbuf, sizeof(cwdbuf)),
   1.922 +                    FILE_SEPARATOR, s);
   1.923 +            result = Resolve(dir, program);
   1.924 +        }
   1.925 +        if (result != 0) break;
   1.926 +    }
   1.927 +
   1.928 +    JLI_MemFree(tmp_path);
   1.929 +    return result;
   1.930 +}
   1.931 +
   1.932 +
   1.933 +/* Store the name of the executable once computed */
   1.934 +static char *execname = NULL;
   1.935 +
   1.936 +/*
   1.937 + * Compute the name of the executable
   1.938 + *
   1.939 + * In order to re-exec securely we need the absolute path of the
   1.940 + * executable. On Solaris getexecname(3c) may not return an absolute
   1.941 + * path so we use dladdr to get the filename of the executable and
   1.942 + * then use realpath to derive an absolute path. From Solaris 9
   1.943 + * onwards the filename returned in DL_info structure from dladdr is
   1.944 + * an absolute pathname so technically realpath isn't required.
   1.945 + * On Linux we read the executable name from /proc/self/exe.
   1.946 + * As a fallback, and for platforms other than Solaris and Linux,
   1.947 + * we use FindExecName to compute the executable name.
   1.948 + */
   1.949 +static char *
   1.950 +SetExecname(char **argv)
   1.951 +{
   1.952 +    char* exec_path = NULL;
   1.953 +
   1.954 +    if (execname != NULL)       /* Already determined */
   1.955 +        return (execname);
   1.956 +
   1.957 +#if defined(__sun)
   1.958 +    {
   1.959 +        Dl_info dlinfo;
   1.960 +        if (dladdr((void*)&SetExecname, &dlinfo)) {
   1.961 +            char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1);
   1.962 +            if (resolved != NULL) {
   1.963 +                exec_path = realpath(dlinfo.dli_fname, resolved);
   1.964 +                if (exec_path == NULL) {
   1.965 +                    JLI_MemFree(resolved);
   1.966 +                }
   1.967 +            }
   1.968 +        }
   1.969 +    }
   1.970 +#elif defined(__linux__)
   1.971 +    {
   1.972 +        const char* self = "/proc/self/exe";
   1.973 +        char buf[PATH_MAX+1];
   1.974 +        int len = readlink(self, buf, PATH_MAX);
   1.975 +        if (len >= 0) {
   1.976 +            buf[len] = '\0';            /* readlink doesn't nul terminate */
   1.977 +            exec_path = JLI_StringDup(buf);
   1.978 +        }
   1.979 +    }
   1.980 +#else /* !__sun && !__linux */
   1.981 +    {
   1.982 +        /* Not implemented */
   1.983 +    }
   1.984 +#endif
   1.985 +
   1.986 +    if (exec_path == NULL) {
   1.987 +        exec_path = FindExecName(argv[0]);
   1.988 +    }
   1.989 +    execname = exec_path;
   1.990 +    return exec_path;
   1.991 +}
   1.992 +
   1.993 +/*
   1.994 + * Return the name of the executable.  Used in java_md.c to find the JRE area.
   1.995 + */
   1.996 +static char *
   1.997 +GetExecname() {
   1.998 +  return execname;
   1.999 +}
  1.1000 +
  1.1001 +void ReportErrorMessage(char * message, jboolean always) {
  1.1002 +  if (always) {
  1.1003 +    fprintf(stderr, "%s\n", message);
  1.1004 +  }
  1.1005 +}
  1.1006 +
  1.1007 +void ReportErrorMessage2(char * format, char * string, jboolean always) {
  1.1008 +  if (always) {
  1.1009 +    fprintf(stderr, format, string);
  1.1010 +    fprintf(stderr, "\n");
  1.1011 +  }
  1.1012 +}
  1.1013 +
  1.1014 +void  ReportExceptionDescription(JNIEnv * env) {
  1.1015 +  (*env)->ExceptionDescribe(env);
  1.1016 +}
  1.1017 +
  1.1018 +/*
  1.1019 + * Return JNI_TRUE for an option string that has no effect but should
  1.1020 + * _not_ be passed on to the vm; return JNI_FALSE otherwise.  On
  1.1021 + * Solaris SPARC, this screening needs to be done if:
  1.1022 + * 1) LD_LIBRARY_PATH does _not_ need to be reset and
  1.1023 + * 2) -d32 or -d64 is passed to a binary with a matching data model
  1.1024 + *    (the exec in SetLibraryPath removes -d<n> options and points the
  1.1025 + *    exec to the proper binary).  When this exec is not done, these options
  1.1026 + *    would end up getting passed onto the vm.
  1.1027 + */
  1.1028 +jboolean RemovableMachineDependentOption(char * option) {
  1.1029 +  /*
  1.1030 +   * Unconditionally remove both -d32 and -d64 options since only
  1.1031 +   * the last such options has an effect; e.g.
  1.1032 +   * java -d32 -d64 -d32 -version
  1.1033 +   * is equivalent to
  1.1034 +   * java -d32 -version
  1.1035 +   */
  1.1036 +
  1.1037 +  if( (strcmp(option, "-d32")  == 0 ) ||
  1.1038 +      (strcmp(option, "-d64")  == 0 ))
  1.1039 +    return JNI_TRUE;
  1.1040 +  else
  1.1041 +    return JNI_FALSE;
  1.1042 +}
  1.1043 +
  1.1044 +void PrintMachineDependentOptions() {
  1.1045 +      fprintf(stdout,
  1.1046 +        "    -d32          use a 32-bit data model if available\n"
  1.1047 +        "\n"
  1.1048 +        "    -d64          use a 64-bit data model if available\n");
  1.1049 +      return;
  1.1050 +}
  1.1051 +
  1.1052 +#ifndef GAMMA
  1.1053 +/*
  1.1054 + * The following methods (down to ServerClassMachine()) answer
  1.1055 + * the question about whether a machine is a "server-class"
  1.1056 + * machine.  A server-class machine is loosely defined as one
  1.1057 + * with 2 or more processors and 2 gigabytes or more physical
  1.1058 + * memory.  The definition of a processor is a physical package,
  1.1059 + * not a hyperthreaded chip masquerading as a multi-processor.
  1.1060 + * The definition of memory is also somewhat fuzzy, since x86
  1.1061 + * machines seem not to report all the memory in their DIMMs, we
  1.1062 + * think because of memory mapping of graphics cards, etc.
  1.1063 + *
  1.1064 + * This code is somewhat more confused with #ifdef's than we'd
  1.1065 + * like because this file is used by both Solaris and Linux
  1.1066 + * platforms, and so needs to be parameterized for SPARC and
  1.1067 + * i586 hardware.  The other Linux platforms (amd64 and ia64)
  1.1068 + * don't even ask this question, because they only come with
  1.1069 + * server JVMs.  */
  1.1070 +
  1.1071 +# define KB (1024UL)
  1.1072 +# define MB (1024UL * KB)
  1.1073 +# define GB (1024UL * MB)
  1.1074 +
  1.1075 +/* Compute physical memory by asking the OS */
  1.1076 +uint64_t
  1.1077 +physical_memory(void) {
  1.1078 +  const uint64_t pages     = (uint64_t) sysconf(_SC_PHYS_PAGES);
  1.1079 +  const uint64_t page_size = (uint64_t) sysconf(_SC_PAGESIZE);
  1.1080 +  const uint64_t result    = pages * page_size;
  1.1081 +# define UINT64_FORMAT "%" PRIu64
  1.1082 +
  1.1083 +  if (_launcher_debug) {
  1.1084 +    printf("pages: " UINT64_FORMAT
  1.1085 +           "  page_size: " UINT64_FORMAT
  1.1086 +           "  physical memory: " UINT64_FORMAT " (%.3fGB)\n",
  1.1087 +           pages, page_size, result, result / (double) GB);
  1.1088 +  }
  1.1089 +  return result;
  1.1090 +}
  1.1091 +
  1.1092 +#if defined(__sun) && defined(__sparc)
  1.1093 +
  1.1094 +/* Methods for solaris-sparc: these are easy. */
  1.1095 +
  1.1096 +/* Ask the OS how many processors there are. */
  1.1097 +unsigned long
  1.1098 +physical_processors(void) {
  1.1099 +  const unsigned long sys_processors = sysconf(_SC_NPROCESSORS_CONF);
  1.1100 +
  1.1101 +  if (_launcher_debug) {
  1.1102 +    printf("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors);
  1.1103 +  }
  1.1104 +  return sys_processors;
  1.1105 +}
  1.1106 +
  1.1107 +/* The solaris-sparc version of the "server-class" predicate. */
  1.1108 +jboolean
  1.1109 +solaris_sparc_ServerClassMachine(void) {
  1.1110 +  jboolean            result            = JNI_FALSE;
  1.1111 +  /* How big is a server class machine? */
  1.1112 +  const unsigned long server_processors = 2UL;
  1.1113 +  const uint64_t      server_memory     = 2UL * GB;
  1.1114 +  const uint64_t      actual_memory     = physical_memory();
  1.1115 +
  1.1116 +  /* Is this a server class machine? */
  1.1117 +  if (actual_memory >= server_memory) {
  1.1118 +    const unsigned long actual_processors = physical_processors();
  1.1119 +    if (actual_processors >= server_processors) {
  1.1120 +      result = JNI_TRUE;
  1.1121 +    }
  1.1122 +  }
  1.1123 +  if (_launcher_debug) {
  1.1124 +    printf("solaris_" LIBARCHNAME "_ServerClassMachine: %s\n",
  1.1125 +           (result == JNI_TRUE ? "JNI_TRUE" : "JNI_FALSE"));
  1.1126 +  }
  1.1127 +  return result;
  1.1128 +}
  1.1129 +
  1.1130 +#endif /* __sun && __sparc */
  1.1131 +
  1.1132 +#if defined(__sun) && defined(i586)
  1.1133 +
  1.1134 +/*
  1.1135 + * A utility method for asking the CPU about itself.
  1.1136 + * There's a corresponding version of linux-i586
  1.1137 + * because the compilers are different.
  1.1138 + */
  1.1139 +void
  1.1140 +get_cpuid(uint32_t arg,
  1.1141 +          uint32_t* eaxp,
  1.1142 +          uint32_t* ebxp,
  1.1143 +          uint32_t* ecxp,
  1.1144 +          uint32_t* edxp) {
  1.1145 +#ifdef _LP64
  1.1146 +  asm(
  1.1147 +  /* rbx is a callee-saved register */
  1.1148 +      " movq    %rbx, %r11  \n"
  1.1149 +  /* rdx and rcx are 3rd and 4th argument registers */
  1.1150 +      " movq    %rdx, %r10  \n"
  1.1151 +      " movq    %rcx, %r9   \n"
  1.1152 +      " movl    %edi, %eax  \n"
  1.1153 +      " cpuid               \n"
  1.1154 +      " movl    %eax, (%rsi)\n"
  1.1155 +      " movl    %ebx, (%r10)\n"
  1.1156 +      " movl    %ecx, (%r9) \n"
  1.1157 +      " movl    %edx, (%r8) \n"
  1.1158 +  /* Restore rbx */
  1.1159 +      " movq    %r11, %rbx");
  1.1160 +#else
  1.1161 +  /* EBX is a callee-saved register */
  1.1162 +  asm(" pushl   %ebx");
  1.1163 +  /* Need ESI for storing through arguments */
  1.1164 +  asm(" pushl   %esi");
  1.1165 +  asm(" movl    8(%ebp), %eax   \n"
  1.1166 +      " cpuid                   \n"
  1.1167 +      " movl    12(%ebp), %esi  \n"
  1.1168 +      " movl    %eax, (%esi)    \n"
  1.1169 +      " movl    16(%ebp), %esi  \n"
  1.1170 +      " movl    %ebx, (%esi)    \n"
  1.1171 +      " movl    20(%ebp), %esi  \n"
  1.1172 +      " movl    %ecx, (%esi)    \n"
  1.1173 +      " movl    24(%ebp), %esi  \n"
  1.1174 +      " movl    %edx, (%esi)      ");
  1.1175 +  /* Restore ESI and EBX */
  1.1176 +  asm(" popl    %esi");
  1.1177 +  /* Restore EBX */
  1.1178 +  asm(" popl    %ebx");
  1.1179 +#endif
  1.1180 +}
  1.1181 +
  1.1182 +#endif /* __sun && i586 */
  1.1183 +
  1.1184 +#if defined(__linux__) && defined(i586)
  1.1185 +
  1.1186 +/*
  1.1187 + * A utility method for asking the CPU about itself.
  1.1188 + * There's a corresponding version of solaris-i586
  1.1189 + * because the compilers are different.
  1.1190 + */
  1.1191 +void
  1.1192 +get_cpuid(uint32_t arg,
  1.1193 +          uint32_t* eaxp,
  1.1194 +          uint32_t* ebxp,
  1.1195 +          uint32_t* ecxp,
  1.1196 +          uint32_t* edxp) {
  1.1197 +#ifdef _LP64
  1.1198 +  __asm__ volatile (/* Instructions */
  1.1199 +                    "   movl    %4, %%eax  \n"
  1.1200 +                    "   cpuid              \n"
  1.1201 +                    "   movl    %%eax, (%0)\n"
  1.1202 +                    "   movl    %%ebx, (%1)\n"
  1.1203 +                    "   movl    %%ecx, (%2)\n"
  1.1204 +                    "   movl    %%edx, (%3)\n"
  1.1205 +                    : /* Outputs */
  1.1206 +                    : /* Inputs */
  1.1207 +                    "r" (eaxp),
  1.1208 +                    "r" (ebxp),
  1.1209 +                    "r" (ecxp),
  1.1210 +                    "r" (edxp),
  1.1211 +                    "r" (arg)
  1.1212 +                    : /* Clobbers */
  1.1213 +                    "%rax", "%rbx", "%rcx", "%rdx", "memory"
  1.1214 +                    );
  1.1215 +#else
  1.1216 +  uint32_t value_of_eax = 0;
  1.1217 +  uint32_t value_of_ebx = 0;
  1.1218 +  uint32_t value_of_ecx = 0;
  1.1219 +  uint32_t value_of_edx = 0;
  1.1220 +  __asm__ volatile (/* Instructions */
  1.1221 +                        /* ebx is callee-save, so push it */
  1.1222 +                    "   pushl   %%ebx      \n"
  1.1223 +                    "   movl    %4, %%eax  \n"
  1.1224 +                    "   cpuid              \n"
  1.1225 +                    "   movl    %%eax, %0  \n"
  1.1226 +                    "   movl    %%ebx, %1  \n"
  1.1227 +                    "   movl    %%ecx, %2  \n"
  1.1228 +                    "   movl    %%edx, %3  \n"
  1.1229 +                        /* restore ebx */
  1.1230 +                    "   popl    %%ebx      \n"
  1.1231 +
  1.1232 +                    : /* Outputs */
  1.1233 +                    "=m" (value_of_eax),
  1.1234 +                    "=m" (value_of_ebx),
  1.1235 +                    "=m" (value_of_ecx),
  1.1236 +                    "=m" (value_of_edx)
  1.1237 +                    : /* Inputs */
  1.1238 +                    "m" (arg)
  1.1239 +                    : /* Clobbers */
  1.1240 +                    "%eax", "%ecx", "%edx"
  1.1241 +                    );
  1.1242 +  *eaxp = value_of_eax;
  1.1243 +  *ebxp = value_of_ebx;
  1.1244 +  *ecxp = value_of_ecx;
  1.1245 +  *edxp = value_of_edx;
  1.1246 +#endif
  1.1247 +}
  1.1248 +
  1.1249 +#endif /* __linux__ && i586 */
  1.1250 +
  1.1251 +#ifdef i586
  1.1252 +/*
  1.1253 + * Routines shared by solaris-i586 and linux-i586.
  1.1254 + */
  1.1255 +
  1.1256 +enum HyperThreadingSupport_enum {
  1.1257 +  hts_supported        =  1,
  1.1258 +  hts_too_soon_to_tell =  0,
  1.1259 +  hts_not_supported    = -1,
  1.1260 +  hts_not_pentium4     = -2,
  1.1261 +  hts_not_intel        = -3
  1.1262 +};
  1.1263 +typedef enum HyperThreadingSupport_enum HyperThreadingSupport;
  1.1264 +
  1.1265 +/* Determine if hyperthreading is supported */
  1.1266 +HyperThreadingSupport
  1.1267 +hyperthreading_support(void) {
  1.1268 +  HyperThreadingSupport result = hts_too_soon_to_tell;
  1.1269 +  /* Bits 11 through 8 is family processor id */
  1.1270 +# define FAMILY_ID_SHIFT 8
  1.1271 +# define FAMILY_ID_MASK 0xf
  1.1272 +  /* Bits 23 through 20 is extended family processor id */
  1.1273 +# define EXT_FAMILY_ID_SHIFT 20
  1.1274 +# define EXT_FAMILY_ID_MASK 0xf
  1.1275 +  /* Pentium 4 family processor id */
  1.1276 +# define PENTIUM4_FAMILY_ID 0xf
  1.1277 +  /* Bit 28 indicates Hyper-Threading Technology support */
  1.1278 +# define HT_BIT_SHIFT 28
  1.1279 +# define HT_BIT_MASK 1
  1.1280 +  uint32_t vendor_id[3] = { 0U, 0U, 0U };
  1.1281 +  uint32_t value_of_eax = 0U;
  1.1282 +  uint32_t value_of_edx = 0U;
  1.1283 +  uint32_t dummy        = 0U;
  1.1284 +
  1.1285 +  /* Yes, this is supposed to be [0], [2], [1] */
  1.1286 +  get_cpuid(0, &dummy, &vendor_id[0], &vendor_id[2], &vendor_id[1]);
  1.1287 +  if (_launcher_debug) {
  1.1288 +    printf("vendor: %c %c %c %c %c %c %c %c %c %c %c %c \n",
  1.1289 +           ((vendor_id[0] >>  0) & 0xff),
  1.1290 +           ((vendor_id[0] >>  8) & 0xff),
  1.1291 +           ((vendor_id[0] >> 16) & 0xff),
  1.1292 +           ((vendor_id[0] >> 24) & 0xff),
  1.1293 +           ((vendor_id[1] >>  0) & 0xff),
  1.1294 +           ((vendor_id[1] >>  8) & 0xff),
  1.1295 +           ((vendor_id[1] >> 16) & 0xff),
  1.1296 +           ((vendor_id[1] >> 24) & 0xff),
  1.1297 +           ((vendor_id[2] >>  0) & 0xff),
  1.1298 +           ((vendor_id[2] >>  8) & 0xff),
  1.1299 +           ((vendor_id[2] >> 16) & 0xff),
  1.1300 +           ((vendor_id[2] >> 24) & 0xff));
  1.1301 +  }
  1.1302 +  get_cpuid(1, &value_of_eax, &dummy, &dummy, &value_of_edx);
  1.1303 +  if (_launcher_debug) {
  1.1304 +    printf("value_of_eax: 0x%x  value_of_edx: 0x%x\n",
  1.1305 +           value_of_eax, value_of_edx);
  1.1306 +  }
  1.1307 +  if ((((value_of_eax >> FAMILY_ID_SHIFT) & FAMILY_ID_MASK) == PENTIUM4_FAMILY_ID) ||
  1.1308 +      (((value_of_eax >> EXT_FAMILY_ID_SHIFT) & EXT_FAMILY_ID_MASK) != 0)) {
  1.1309 +    if ((((vendor_id[0] >>  0) & 0xff) == 'G') &&
  1.1310 +        (((vendor_id[0] >>  8) & 0xff) == 'e') &&
  1.1311 +        (((vendor_id[0] >> 16) & 0xff) == 'n') &&
  1.1312 +        (((vendor_id[0] >> 24) & 0xff) == 'u') &&
  1.1313 +        (((vendor_id[1] >>  0) & 0xff) == 'i') &&
  1.1314 +        (((vendor_id[1] >>  8) & 0xff) == 'n') &&
  1.1315 +        (((vendor_id[1] >> 16) & 0xff) == 'e') &&
  1.1316 +        (((vendor_id[1] >> 24) & 0xff) == 'I') &&
  1.1317 +        (((vendor_id[2] >>  0) & 0xff) == 'n') &&
  1.1318 +        (((vendor_id[2] >>  8) & 0xff) == 't') &&
  1.1319 +        (((vendor_id[2] >> 16) & 0xff) == 'e') &&
  1.1320 +        (((vendor_id[2] >> 24) & 0xff) == 'l')) {
  1.1321 +      if (((value_of_edx >> HT_BIT_SHIFT) & HT_BIT_MASK) == HT_BIT_MASK) {
  1.1322 +        if (_launcher_debug) {
  1.1323 +          printf("Hyperthreading supported\n");
  1.1324 +        }
  1.1325 +        result = hts_supported;
  1.1326 +      } else {
  1.1327 +        if (_launcher_debug) {
  1.1328 +          printf("Hyperthreading not supported\n");
  1.1329 +        }
  1.1330 +        result = hts_not_supported;
  1.1331 +      }
  1.1332 +    } else {
  1.1333 +      if (_launcher_debug) {
  1.1334 +        printf("Not GenuineIntel\n");
  1.1335 +      }
  1.1336 +      result = hts_not_intel;
  1.1337 +    }
  1.1338 +  } else {
  1.1339 +    if (_launcher_debug) {
  1.1340 +      printf("not Pentium 4 or extended\n");
  1.1341 +    }
  1.1342 +    result = hts_not_pentium4;
  1.1343 +  }
  1.1344 +  return result;
  1.1345 +}
  1.1346 +
  1.1347 +/* Determine how many logical processors there are per CPU */
  1.1348 +unsigned int
  1.1349 +logical_processors_per_package(void) {
  1.1350 +  /*
  1.1351 +   * After CPUID with EAX==1, register EBX bits 23 through 16
  1.1352 +   * indicate the number of logical processors per package
  1.1353 +   */
  1.1354 +# define NUM_LOGICAL_SHIFT 16
  1.1355 +# define NUM_LOGICAL_MASK 0xff
  1.1356 +  unsigned int result                        = 1U;
  1.1357 +  const HyperThreadingSupport hyperthreading = hyperthreading_support();
  1.1358 +
  1.1359 +  if (hyperthreading == hts_supported) {
  1.1360 +    uint32_t value_of_ebx = 0U;
  1.1361 +    uint32_t dummy        = 0U;
  1.1362 +
  1.1363 +    get_cpuid(1, &dummy, &value_of_ebx, &dummy, &dummy);
  1.1364 +    result = (value_of_ebx >> NUM_LOGICAL_SHIFT) & NUM_LOGICAL_MASK;
  1.1365 +    if (_launcher_debug) {
  1.1366 +      printf("logical processors per package: %u\n", result);
  1.1367 +    }
  1.1368 +  }
  1.1369 +  return result;
  1.1370 +}
  1.1371 +
  1.1372 +/* Compute the number of physical processors, not logical processors */
  1.1373 +unsigned long
  1.1374 +physical_processors(void) {
  1.1375 +  const long sys_processors = sysconf(_SC_NPROCESSORS_CONF);
  1.1376 +  unsigned long result      = sys_processors;
  1.1377 +
  1.1378 +  if (_launcher_debug) {
  1.1379 +    printf("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors);
  1.1380 +  }
  1.1381 +  if (sys_processors > 1) {
  1.1382 +    unsigned int logical_processors = logical_processors_per_package();
  1.1383 +    if (logical_processors > 1) {
  1.1384 +      result = (unsigned long) sys_processors / logical_processors;
  1.1385 +    }
  1.1386 +  }
  1.1387 +  if (_launcher_debug) {
  1.1388 +    printf("physical processors: %lu\n", result);
  1.1389 +  }
  1.1390 +  return result;
  1.1391 +}
  1.1392 +
  1.1393 +#endif /* i586 */
  1.1394 +
  1.1395 +#if defined(__sun) && defined(i586)
  1.1396 +
  1.1397 +/* The definition of a server-class machine for solaris-i586/amd64 */
  1.1398 +jboolean
  1.1399 +solaris_i586_ServerClassMachine(void) {
  1.1400 +  jboolean            result            = JNI_FALSE;
  1.1401 +  /* How big is a server class machine? */
  1.1402 +  const unsigned long server_processors = 2UL;
  1.1403 +  const uint64_t      server_memory     = 2UL * GB;
  1.1404 +  /*
  1.1405 +   * We seem not to get our full complement of memory.
  1.1406 +   *     We allow some part (1/8?) of the memory to be "missing",
  1.1407 +   *     based on the sizes of DIMMs, and maybe graphics cards.
  1.1408 +   */
  1.1409 +  const uint64_t      missing_memory    = 256UL * MB;
  1.1410 +  const uint64_t      actual_memory     = physical_memory();
  1.1411 +
  1.1412 +  /* Is this a server class machine? */
  1.1413 +  if (actual_memory >= (server_memory - missing_memory)) {
  1.1414 +    const unsigned long actual_processors = physical_processors();
  1.1415 +    if (actual_processors >= server_processors) {
  1.1416 +      result = JNI_TRUE;
  1.1417 +    }
  1.1418 +  }
  1.1419 +  if (_launcher_debug) {
  1.1420 +    printf("solaris_" LIBARCHNAME "_ServerClassMachine: %s\n",
  1.1421 +           (result == JNI_TRUE ? "true" : "false"));
  1.1422 +  }
  1.1423 +  return result;
  1.1424 +}
  1.1425 +
  1.1426 +#endif /* __sun && i586 */
  1.1427 +
  1.1428 +#if defined(__linux__) && defined(i586)
  1.1429 +
  1.1430 +/* The definition of a server-class machine for linux-i586 */
  1.1431 +jboolean
  1.1432 +linux_i586_ServerClassMachine(void) {
  1.1433 +  jboolean            result            = JNI_FALSE;
  1.1434 +  /* How big is a server class machine? */
  1.1435 +  const unsigned long server_processors = 2UL;
  1.1436 +  const uint64_t      server_memory     = 2UL * GB;
  1.1437 +  /*
  1.1438 +   * We seem not to get our full complement of memory.
  1.1439 +   *     We allow some part (1/8?) of the memory to be "missing",
  1.1440 +   *     based on the sizes of DIMMs, and maybe graphics cards.
  1.1441 +   */
  1.1442 +  const uint64_t      missing_memory    = 256UL * MB;
  1.1443 +  const uint64_t      actual_memory     = physical_memory();
  1.1444 +
  1.1445 +  /* Is this a server class machine? */
  1.1446 +  if (actual_memory >= (server_memory - missing_memory)) {
  1.1447 +    const unsigned long actual_processors = physical_processors();
  1.1448 +    if (actual_processors >= server_processors) {
  1.1449 +      result = JNI_TRUE;
  1.1450 +    }
  1.1451 +  }
  1.1452 +  if (_launcher_debug) {
  1.1453 +    printf("linux_" LIBARCHNAME "_ServerClassMachine: %s\n",
  1.1454 +           (result == JNI_TRUE ? "true" : "false"));
  1.1455 +  }
  1.1456 +  return result;
  1.1457 +}
  1.1458 +
  1.1459 +#endif /* __linux__ && i586 */
  1.1460 +
  1.1461 +/* Dispatch to the platform-specific definition of "server-class" */
  1.1462 +jboolean
  1.1463 +ServerClassMachine(void) {
  1.1464 +  jboolean result = JNI_FALSE;
  1.1465 +#if   defined(NEVER_ACT_AS_SERVER_CLASS_MACHINE)
  1.1466 +  result = JNI_FALSE;
  1.1467 +#elif defined(ALWAYS_ACT_AS_SERVER_CLASS_MACHINE)
  1.1468 +  result = JNI_TRUE;
  1.1469 +#elif defined(__sun) && defined(__sparc)
  1.1470 +  result = solaris_sparc_ServerClassMachine();
  1.1471 +#elif defined(__sun) && defined(i586)
  1.1472 +  result = solaris_i586_ServerClassMachine();
  1.1473 +#elif defined(__linux__) && defined(i586)
  1.1474 +  result = linux_i586_ServerClassMachine();
  1.1475 +#else
  1.1476 +  if (_launcher_debug) {
  1.1477 +    printf("ServerClassMachine: returns default value of %s\n",
  1.1478 +           (result == JNI_TRUE ? "true" : "false"));
  1.1479 +  }
  1.1480 +#endif
  1.1481 +  return result;
  1.1482 +}
  1.1483 +
  1.1484 +/*
  1.1485 + *      Since using the file system as a registry is a bit risky, perform
  1.1486 + *      additional sanity checks on the identified directory to validate
  1.1487 + *      it as a valid jre/sdk.
  1.1488 + *
  1.1489 + *      Return 0 if the tests fail; otherwise return non-zero (true).
  1.1490 + *
  1.1491 + *      Note that checking for anything more than the existence of an
  1.1492 + *      executable object at bin/java relative to the path being checked
  1.1493 + *      will break the regression tests.
  1.1494 + */
  1.1495 +static int
  1.1496 +CheckSanity(char *path, char *dir)
  1.1497 +{
  1.1498 +    char    buffer[PATH_MAX];
  1.1499 +
  1.1500 +    if (strlen(path) + strlen(dir) + 11 > PATH_MAX)
  1.1501 +        return (0);     /* Silently reject "impossibly" long paths */
  1.1502 +
  1.1503 +    (void)strcat(strcat(strcat(strcpy(buffer, path), "/"), dir), "/bin/java");
  1.1504 +    return ((access(buffer, X_OK) == 0) ? 1 : 0);
  1.1505 +}
  1.1506 +
  1.1507 +/*
  1.1508 + *      Determine if there is an acceptable JRE in the directory dirname.
  1.1509 + *      Upon locating the "best" one, return a fully qualified path to
  1.1510 + *      it. "Best" is defined as the most advanced JRE meeting the
  1.1511 + *      constraints contained in the manifest_info. If no JRE in this
  1.1512 + *      directory meets the constraints, return NULL.
  1.1513 + *
  1.1514 + *      Note that we don't check for errors in reading the directory
  1.1515 + *      (which would be done by checking errno).  This is because it
  1.1516 + *      doesn't matter if we get an error reading the directory, or
  1.1517 + *      we just don't find anything interesting in the directory.  We
  1.1518 + *      just return NULL in either case.
  1.1519 + *
  1.1520 + *      The historical names of j2sdk and j2re were changed to jdk and
  1.1521 + *      jre respecively as part of the 1.5 rebranding effort.  Since the
  1.1522 + *      former names are legacy on Linux, they must be recognized for
  1.1523 + *      all time.  Fortunately, this is a minor cost.
  1.1524 + */
  1.1525 +static char
  1.1526 +*ProcessDir(manifest_info *info, char *dirname)
  1.1527 +{
  1.1528 +    DIR     *dirp;
  1.1529 +    struct dirent *dp;
  1.1530 +    char    *best = NULL;
  1.1531 +    int     offset;
  1.1532 +    int     best_offset = 0;
  1.1533 +    char    *ret_str = NULL;
  1.1534 +    char    buffer[PATH_MAX];
  1.1535 +
  1.1536 +    if ((dirp = opendir(dirname)) == NULL)
  1.1537 +        return (NULL);
  1.1538 +
  1.1539 +    do {
  1.1540 +        if ((dp = readdir(dirp)) != NULL) {
  1.1541 +            offset = 0;
  1.1542 +            if ((strncmp(dp->d_name, "jre", 3) == 0) ||
  1.1543 +                (strncmp(dp->d_name, "jdk", 3) == 0))
  1.1544 +                offset = 3;
  1.1545 +            else if (strncmp(dp->d_name, "j2re", 4) == 0)
  1.1546 +                offset = 4;
  1.1547 +            else if (strncmp(dp->d_name, "j2sdk", 5) == 0)
  1.1548 +                offset = 5;
  1.1549 +            if (offset > 0) {
  1.1550 +                if ((JLI_AcceptableRelease(dp->d_name + offset,
  1.1551 +                    info->jre_version)) && CheckSanity(dirname, dp->d_name))
  1.1552 +                    if ((best == NULL) || (JLI_ExactVersionId(
  1.1553 +                      dp->d_name + offset, best + best_offset) > 0)) {
  1.1554 +                        if (best != NULL)
  1.1555 +                            JLI_MemFree(best);
  1.1556 +                        best = JLI_StringDup(dp->d_name);
  1.1557 +                        best_offset = offset;
  1.1558 +                    }
  1.1559 +            }
  1.1560 +        }
  1.1561 +    } while (dp != NULL);
  1.1562 +    (void) closedir(dirp);
  1.1563 +    if (best == NULL)
  1.1564 +        return (NULL);
  1.1565 +    else {
  1.1566 +        ret_str = JLI_MemAlloc(strlen(dirname) + strlen(best) + 2);
  1.1567 +        ret_str = strcat(strcat(strcpy(ret_str, dirname), "/"), best);
  1.1568 +        JLI_MemFree(best);
  1.1569 +        return (ret_str);
  1.1570 +    }
  1.1571 +}
  1.1572 +
  1.1573 +/*
  1.1574 + *      This is the global entry point. It examines the host for the optimal
  1.1575 + *      JRE to be used by scanning a set of directories.  The set of directories
  1.1576 + *      is platform dependent and can be overridden by the environment
  1.1577 + *      variable JAVA_VERSION_PATH.
  1.1578 + *
  1.1579 + *      This routine itself simply determines the set of appropriate
  1.1580 + *      directories before passing control onto ProcessDir().
  1.1581 + */
  1.1582 +char*
  1.1583 +LocateJRE(manifest_info* info)
  1.1584 +{
  1.1585 +    char        *path;
  1.1586 +    char        *home;
  1.1587 +    char        *target = NULL;
  1.1588 +    char        *dp;
  1.1589 +    char        *cp;
  1.1590 +
  1.1591 +    /*
  1.1592 +     * Start by getting JAVA_VERSION_PATH
  1.1593 +     */
  1.1594 +    if (info->jre_restrict_search)
  1.1595 +        path = JLI_StringDup(system_dir);
  1.1596 +    else if ((path = getenv("JAVA_VERSION_PATH")) != NULL)
  1.1597 +        path = JLI_StringDup(path);
  1.1598 +    else
  1.1599 +        if ((home = getenv("HOME")) != NULL) {
  1.1600 +            path = (char *)JLI_MemAlloc(strlen(home) + strlen(system_dir) +
  1.1601 +                strlen(user_dir) + 2);
  1.1602 +            path = strcat(strcat(strcat(strcpy(path, home),
  1.1603 +                user_dir), ":"), system_dir);
  1.1604 +        } else
  1.1605 +            path = JLI_StringDup(system_dir);
  1.1606 +
  1.1607 +    /*
  1.1608 +     * Step through each directory on the path. Terminate the scan with
  1.1609 +     * the first directory with an acceptable JRE.
  1.1610 +     */
  1.1611 +    cp = dp = path;
  1.1612 +    while (dp != NULL) {
  1.1613 +        cp = strchr(dp, (int)':');
  1.1614 +        if (cp != NULL)
  1.1615 +            *cp = (char)NULL;
  1.1616 +        if ((target = ProcessDir(info, dp)) != NULL)
  1.1617 +            break;
  1.1618 +        dp = cp;
  1.1619 +        if (dp != NULL)
  1.1620 +            dp++;
  1.1621 +    }
  1.1622 +    JLI_MemFree(path);
  1.1623 +    return (target);
  1.1624 +}
  1.1625 +
  1.1626 +/*
  1.1627 + * Given a path to a jre to execute, this routine checks if this process
  1.1628 + * is indeed that jre.  If not, it exec's that jre.
  1.1629 + *
  1.1630 + * We want to actually check the paths rather than just the version string
  1.1631 + * built into the executable, so that given version specification (and
  1.1632 + * JAVA_VERSION_PATH) will yield the exact same Java environment, regardless
  1.1633 + * of the version of the arbitrary launcher we start with.
  1.1634 + */
  1.1635 +void
  1.1636 +ExecJRE(char *jre, char **argv)
  1.1637 +{
  1.1638 +    char    wanted[PATH_MAX];
  1.1639 +    char    *execname;
  1.1640 +    char    *progname;
  1.1641 +
  1.1642 +    /*
  1.1643 +     * Resolve the real path to the directory containing the selected JRE.
  1.1644 +     */
  1.1645 +    if (realpath(jre, wanted) == NULL) {
  1.1646 +        fprintf(stderr, "Unable to resolve %s\n", jre);
  1.1647 +        exit(1);
  1.1648 +    }
  1.1649 +
  1.1650 +    /*
  1.1651 +     * Resolve the real path to the currently running launcher.
  1.1652 +     */
  1.1653 +    execname = SetExecname(argv);
  1.1654 +    if (execname == NULL) {
  1.1655 +        fprintf(stderr, "Unable to resolve current executable\n");
  1.1656 +        exit(1);
  1.1657 +    }
  1.1658 +
  1.1659 +    /*
  1.1660 +     * If the path to the selected JRE directory is a match to the initial
  1.1661 +     * portion of the path to the currently executing JRE, we have a winner!
  1.1662 +     * If so, just return.
  1.1663 +     */
  1.1664 +    if (strncmp(wanted, execname, strlen(wanted)) == 0)
  1.1665 +        return;                 /* I am the droid you were looking for */
  1.1666 +
  1.1667 +    /*
  1.1668 +     * If this isn't the selected version, exec the selected version.
  1.1669 +     */
  1.1670 +#ifdef JAVA_ARGS  /* javac, jar and friends. */
  1.1671 +    progname = "java";
  1.1672 +#else             /* java, oldjava, javaw and friends */
  1.1673 +#ifdef PROGNAME
  1.1674 +    progname = PROGNAME;
  1.1675 +#else
  1.1676 +    progname = *argv;
  1.1677 +    if ((s = strrchr(progname, FILE_SEPARATOR)) != 0) {
  1.1678 +        progname = s + 1;
  1.1679 +    }
  1.1680 +#endif /* PROGNAME */
  1.1681 +#endif /* JAVA_ARGS */
  1.1682 +
  1.1683 +    /*
  1.1684 +     * This should never happen (because of the selection code in SelectJRE),
  1.1685 +     * but check for "impossibly" long path names just because buffer overruns
  1.1686 +     * can be so deadly.
  1.1687 +     */
  1.1688 +    if (strlen(wanted) + strlen(progname) + 6 > PATH_MAX) {
  1.1689 +        fprintf(stderr, "Path length exceeds maximum length (PATH_MAX)\n");
  1.1690 +        exit(1);
  1.1691 +    }
  1.1692 +
  1.1693 +    /*
  1.1694 +     * Construct the path and exec it.
  1.1695 +     */
  1.1696 +    (void)strcat(strcat(wanted, "/bin/"), progname);
  1.1697 +    argv[0] = progname;
  1.1698 +    if (_launcher_debug) {
  1.1699 +        int i;
  1.1700 +        printf("ReExec Command: %s (%s)\n", wanted, argv[0]);
  1.1701 +        printf("ReExec Args:");
  1.1702 +        for (i = 1; argv[i] != NULL; i++)
  1.1703 +            printf(" %s", argv[i]);
  1.1704 +        printf("\n");
  1.1705 +    }
  1.1706 +    (void)fflush(stdout);
  1.1707 +    (void)fflush(stderr);
  1.1708 +    execv(wanted, argv);
  1.1709 +    perror("execv()");
  1.1710 +    fprintf(stderr, "Exec of %s failed\n", wanted);
  1.1711 +    exit(1);
  1.1712 +}
  1.1713 +#endif /* ifndef GAMMA */
  1.1714 +
  1.1715 +/*
  1.1716 + * "Borrowed" from Solaris 10 where the unsetenv() function is being added
  1.1717 + * to libc thanks to SUSv3 (Standard Unix Specification, version 3). As
  1.1718 + * such, in the fullness of time this will appear in libc on all relevant
  1.1719 + * Solaris/Linux platforms and maybe even the Windows platform.  At that
  1.1720 + * time, this stub can be removed.
  1.1721 + *
  1.1722 + * This implementation removes the environment locking for multithreaded
  1.1723 + * applications.  (We don't have access to these mutexes within libc and
  1.1724 + * the launcher isn't multithreaded.)  Note that what remains is platform
  1.1725 + * independent, because it only relies on attributes that a POSIX environment
  1.1726 + * defines.
  1.1727 + *
  1.1728 + * Returns 0 on success, -1 on failure.
  1.1729 + *
  1.1730 + * Also removed was the setting of errno.  The only value of errno set
  1.1731 + * was EINVAL ("Invalid Argument").
  1.1732 + */
  1.1733 +
  1.1734 +/*
  1.1735 + * s1(environ) is name=value
  1.1736 + * s2(name) is name(not the form of name=value).
  1.1737 + * if names match, return value of 1, else return 0
  1.1738 + */
  1.1739 +static int
  1.1740 +match_noeq(const char *s1, const char *s2)
  1.1741 +{
  1.1742 +        while (*s1 == *s2++) {
  1.1743 +                if (*s1++ == '=')
  1.1744 +                        return (1);
  1.1745 +        }
  1.1746 +        if (*s1 == '=' && s2[-1] == '\0')
  1.1747 +                return (1);
  1.1748 +        return (0);
  1.1749 +}
  1.1750 +
  1.1751 +/*
  1.1752 + * added for SUSv3 standard
  1.1753 + *
  1.1754 + * Delete entry from environ.
  1.1755 + * Do not free() memory!  Other threads may be using it.
  1.1756 + * Keep it around forever.
  1.1757 + */
  1.1758 +static int
  1.1759 +borrowed_unsetenv(const char *name)
  1.1760 +{
  1.1761 +        long    idx;            /* index into environ */
  1.1762 +
  1.1763 +        if (name == NULL || *name == '\0' ||
  1.1764 +            strchr(name, '=') != NULL) {
  1.1765 +                return (-1);
  1.1766 +        }
  1.1767 +
  1.1768 +        for (idx = 0; environ[idx] != NULL; idx++) {
  1.1769 +                if (match_noeq(environ[idx], name))
  1.1770 +                        break;
  1.1771 +        }
  1.1772 +        if (environ[idx] == NULL) {
  1.1773 +                /* name not found but still a success */
  1.1774 +                return (0);
  1.1775 +        }
  1.1776 +        /* squeeze up one entry */
  1.1777 +        do {
  1.1778 +                environ[idx] = environ[idx+1];
  1.1779 +        } while (environ[++idx] != NULL);
  1.1780 +
  1.1781 +        return (0);
  1.1782 +}
  1.1783 +/* --- End of "borrowed" code --- */
  1.1784 +
  1.1785 +/*
  1.1786 + * Wrapper for unsetenv() function.
  1.1787 + */
  1.1788 +int
  1.1789 +UnsetEnv(char *name)
  1.1790 +{
  1.1791 +    return(borrowed_unsetenv(name));
  1.1792 +}
  1.1793 +
  1.1794 +/* --- Splash Screen shared library support --- */
  1.1795 +
  1.1796 +static const char* SPLASHSCREEN_SO = "libsplashscreen.so";
  1.1797 +
  1.1798 +static void* hSplashLib = NULL;
  1.1799 +
  1.1800 +void* SplashProcAddress(const char* name) {
  1.1801 +    if (!hSplashLib) {
  1.1802 +        hSplashLib = dlopen(SPLASHSCREEN_SO, RTLD_LAZY | RTLD_GLOBAL);
  1.1803 +    }
  1.1804 +    if (hSplashLib) {
  1.1805 +        void* sym = dlsym(hSplashLib, name);
  1.1806 +        return sym;
  1.1807 +    } else {
  1.1808 +        return NULL;
  1.1809 +    }
  1.1810 +}
  1.1811 +
  1.1812 +void SplashFreeLibrary() {
  1.1813 +    if (hSplashLib) {
  1.1814 +        dlclose(hSplashLib);
  1.1815 +        hSplashLib = NULL;
  1.1816 +    }
  1.1817 +}
  1.1818 +
  1.1819 +const char *
  1.1820 +jlong_format_specifier() {
  1.1821 +    return "%lld";
  1.1822 +}
  1.1823 +
  1.1824 +/*
  1.1825 + * Block current thread and continue execution in a new thread
  1.1826 + */
  1.1827 +int
  1.1828 +ContinueInNewThread(int (JNICALL *continuation)(void *), jlong stack_size, void * args) {
  1.1829 +    int rslt;
  1.1830 +#ifdef __linux__
  1.1831 +    pthread_t tid;
  1.1832 +    pthread_attr_t attr;
  1.1833 +    pthread_attr_init(&attr);
  1.1834 +    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  1.1835 +
  1.1836 +    if (stack_size > 0) {
  1.1837 +      pthread_attr_setstacksize(&attr, stack_size);
  1.1838 +    }
  1.1839 +
  1.1840 +    if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) {
  1.1841 +      void * tmp;
  1.1842 +      pthread_join(tid, &tmp);
  1.1843 +      rslt = (int)tmp;
  1.1844 +    } else {
  1.1845 +     /*
  1.1846 +      * Continue execution in current thread if for some reason (e.g. out of
  1.1847 +      * memory/LWP)  a new thread can't be created. This will likely fail
  1.1848 +      * later in continuation as JNI_CreateJavaVM needs to create quite a
  1.1849 +      * few new threads, anyway, just give it a try..
  1.1850 +      */
  1.1851 +      rslt = continuation(args);
  1.1852 +    }
  1.1853 +
  1.1854 +    pthread_attr_destroy(&attr);
  1.1855 +#else
  1.1856 +    thread_t tid;
  1.1857 +    long flags = 0;
  1.1858 +    if (thr_create(NULL, stack_size, (void *(*)(void *))continuation, args, flags, &tid) == 0) {
  1.1859 +      void * tmp;
  1.1860 +      thr_join(tid, NULL, &tmp);
  1.1861 +      rslt = (int)tmp;
  1.1862 +    } else {
  1.1863 +      /* See above. Continue in current thread if thr_create() failed */
  1.1864 +      rslt = continuation(args);
  1.1865 +    }
  1.1866 +#endif
  1.1867 +    return rslt;
  1.1868 +}
  1.1869 +
  1.1870 +/* Coarse estimation of number of digits assuming the worst case is a 64-bit pid. */
  1.1871 +#define MAX_PID_STR_SZ   20
  1.1872 +
  1.1873 +void SetJavaLauncherPlatformProps() {
  1.1874 +   /* Linux only */
  1.1875 +#ifdef __linux__
  1.1876 +    const char *substr = "-Dsun.java.launcher.pid=";
  1.1877 +    char *pid_prop_str = (char *)JLI_MemAlloc(strlen(substr) + MAX_PID_STR_SZ + 1);
  1.1878 +    sprintf(pid_prop_str, "%s%d", substr, getpid());
  1.1879 +    AddOption(pid_prop_str, NULL);
  1.1880 +#endif
  1.1881 +}

mercurial