1 /*
   2  * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "java.h"
  27 #include "jvm_md.h"
  28 #include <dirent.h>
  29 #include <dlfcn.h>
  30 #include <fcntl.h>
  31 #include <inttypes.h>
  32 #include <stdio.h>
  33 #include <string.h>
  34 #include <stdlib.h>
  35 #include <sys/stat.h>
  36 #include <unistd.h>
  37 #include <sys/types.h>
  38 #include "manifest_info.h"
  39 
  40 
  41 #define JVM_DLL "libjvm.so"
  42 #define JAVA_DLL "libjava.so"
  43 #ifdef AIX
  44 #define LD_LIBRARY_PATH "LIBPATH"
  45 #else
  46 #define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
  47 #endif
  48 
  49 /* help jettison the LD_LIBRARY_PATH settings in the future */
  50 #ifndef SETENV_REQUIRED
  51 #define SETENV_REQUIRED
  52 #endif
  53 
  54 #ifdef __solaris__
  55 #  ifndef LIBARCHNAME
  56 #    error "The macro LIBARCHNAME was not defined on the compile line"
  57 #  endif
  58 #  include <sys/systeminfo.h>
  59 #  include <sys/elf.h>
  60 #  include <stdio.h>
  61 #endif
  62 
  63 /*
  64  * Flowchart of launcher execs and options processing on unix
  65  *
  66  * The selection of the proper vm shared library to open depends on
  67  * several classes of command line options, including vm "flavor"
  68  * options (-client, -server) and the data model options, -d32  and
  69  * -d64, as well as a version specification which may have come from
  70  * the command line or from the manifest of an executable jar file.
  71  * The vm selection options are not passed to the running
  72  * virtual machine; they must be screened out by the launcher.
  73  *
  74  * The version specification (if any) is processed first by the
  75  * platform independent routine SelectVersion.  This may result in
  76  * the exec of the specified launcher version.
  77  *
  78  * Previously the launcher modified the LD_LIBRARY_PATH appropriately for the
  79  * desired data model path, regardless if data models matched or not. The
  80  * launcher subsequently exec'ed the desired executable, in order to make the
  81  * LD_LIBRARY_PATH path available, for the runtime linker.
  82  *
  83  * Now, in most cases,the launcher will dlopen the target libjvm.so. All
  84  * required libraries are loaded by the runtime linker, using the
  85  * $RPATH/$ORIGIN baked into the shared libraries at compile time. Therefore,
  86  * in most cases, the launcher will only exec, if the data models are
  87  * mismatched, and will not set any environment variables, regardless of the
  88  * data models.
  89  *
  90  * However, if the environment contains a LD_LIBRARY_PATH, this will cause the
  91  * launcher to inspect the LD_LIBRARY_PATH. The launcher will check
  92  *  a. if the LD_LIBRARY_PATH's first component is the path to the desired
  93  *     libjvm.so
  94  *  b. if any other libjvm.so is found in any of the paths.
  95  * If case b is true, then the launcher will set the LD_LIBRARY_PATH to the
  96  * desired JRE and reexec, in order to propagate the environment.
  97  *
  98  *  Main
  99  *  (incoming argv)
 100  *  |
 101  * \|/
 102  * CreateExecutionEnvironment
 103  * (determines desired data model)
 104  *  |
 105  *  |
 106  * \|/
 107  *  Have Desired Model ? --> NO --> Exit(with error)
 108  *  |
 109  *  |
 110  * \|/
 111  * YES
 112  *  |
 113  *  |
 114  * \|/
 115  * CheckJvmType
 116  * (removes -client, -server, etc.)
 117  *  |
 118  *  |
 119  * \|/
 120  * TranslateDashJArgs...
 121  * (Prepare to pass args to vm)
 122  *  |
 123  *  |
 124  * \|/
 125  * ParseArguments
 126  * (removes -d32 and -d64 if any,
 127  *  processes version options,
 128  *  creates argument list for vm,
 129  *  etc.)
 130  *   |
 131  *   |
 132  *  \|/
 133  * RequiresSetenv
 134  * Is LD_LIBRARY_PATH
 135  * and friends set ? --> NO --> Have Desired Model ? NO --> Error/Exit
 136  *  YES                              YES --> Continue
 137  *   |
 138  *   |
 139  *  \|/
 140  * Path is desired JRE ? YES --> Have Desired Model ? NO --> Error/Exit
 141  *  NO                               YES --> Continue
 142  *   |
 143  *   |
 144  *  \|/
 145  * Paths have well known
 146  * jvm paths ?       --> NO --> Have Desired Model ? NO --> Error/Exit
 147  *  YES                              YES --> Continue
 148  *   |
 149  *   |
 150  *  \|/
 151  *  Does libjvm.so exit
 152  *  in any of them ? --> NO --> Have Desired Model ? NO --> Error/Exit
 153  *   YES                             YES --> Continue
 154  *   |
 155  *   |
 156  *  \|/
 157  *  Set the LD_LIBRARY_PATH
 158  *   |
 159  *   |
 160  *  \|/
 161  * Re-exec
 162  *   |
 163  *   |
 164  *  \|/
 165  * Main
 166  */
 167 
 168 /* Store the name of the executable once computed */
 169 static char *execname = NULL;
 170 
 171 /*
 172  * execname accessor from other parts of platform dependent logic
 173  */
 174 const char *
 175 GetExecName() {
 176     return execname;
 177 }
 178 
 179 #ifdef SETENV_REQUIRED
 180 static jboolean
 181 JvmExists(const char *path) {
 182     char tmp[PATH_MAX + 1];
 183     struct stat statbuf;
 184     JLI_Snprintf(tmp, PATH_MAX, "%s/%s", path, JVM_DLL);
 185     if (stat(tmp, &statbuf) == 0) {
 186         return JNI_TRUE;
 187     }
 188     return JNI_FALSE;
 189 }
 190 /*
 191  * contains a lib/$LIBARCHNAME/{server,client}/libjvm.so ?
 192  */
 193 static jboolean
 194 ContainsLibJVM(const char *env) {
 195     char clientPattern[PATH_MAX + 1];
 196     char serverPattern[PATH_MAX + 1];
 197     char *envpath;
 198     char *path;
 199     jboolean clientPatternFound;
 200     jboolean serverPatternFound;
 201 
 202     /* fastest path */
 203     if (env == NULL) {
 204         return JNI_FALSE;
 205     }
 206 
 207     /* the usual suspects */
 208     JLI_Snprintf(clientPattern, PATH_MAX, "lib/%s/client", LIBARCHNAME);
 209     JLI_Snprintf(serverPattern, PATH_MAX, "lib/%s/server", LIBARCHNAME);
 210 
 211     /* to optimize for time, test if any of our usual suspects are present. */
 212     clientPatternFound = JLI_StrStr(env, clientPattern) != NULL;
 213     serverPatternFound = JLI_StrStr(env, serverPattern) != NULL;
 214     if (clientPatternFound == JNI_FALSE && serverPatternFound == JNI_FALSE) {
 215         return JNI_FALSE;
 216     }
 217 
 218     /*
 219      * we have a suspicious path component, check if it contains a libjvm.so
 220      */
 221     envpath = JLI_StringDup(env);
 222     for (path = JLI_StrTok(envpath, ":"); path != NULL; path = JLI_StrTok(NULL, ":")) {
 223         if (clientPatternFound && JLI_StrStr(path, clientPattern) != NULL) {
 224             if (JvmExists(path)) {
 225                 JLI_MemFree(envpath);
 226                 return JNI_TRUE;
 227             }
 228         }
 229         if (serverPatternFound && JLI_StrStr(path, serverPattern)  != NULL) {
 230             if (JvmExists(path)) {
 231                 JLI_MemFree(envpath);
 232                 return JNI_TRUE;
 233             }
 234         }
 235     }
 236     JLI_MemFree(envpath);
 237     return JNI_FALSE;
 238 }
 239 
 240 /*
 241  * Test whether the environment variable needs to be set, see flowchart.
 242  */
 243 static jboolean
 244 RequiresSetenv(const char *jvmpath) {
 245     char jpath[PATH_MAX + 1];
 246     char *llp;
 247     char *dmllp = NULL;
 248     char *p; /* a utility pointer */
 249 
 250 #ifdef AIX
 251     /* We always have to set the LIBPATH on AIX because ld doesn't support $ORIGIN. */
 252     return JNI_TRUE;
 253 #endif
 254 
 255     llp = getenv("LD_LIBRARY_PATH");
 256 #ifdef __solaris__
 257     dmllp = getenv("LD_LIBRARY_PATH_64");
 258 #endif /* __solaris__ */
 259     /* no environment variable is a good environment variable */
 260     if (llp == NULL && dmllp == NULL) {
 261         return JNI_FALSE;
 262     }
 263 #ifdef __linux
 264     /*
 265      * On linux, if a binary is running as sgid or suid, glibc sets
 266      * LD_LIBRARY_PATH to the empty string for security purposes. (In contrast,
 267      * on Solaris the LD_LIBRARY_PATH variable for a privileged binary does not
 268      * lose its settings; but the dynamic linker does apply more scrutiny to the
 269      * path.) The launcher uses the value of LD_LIBRARY_PATH to prevent an exec
 270      * loop, here and further downstream. Therefore, if we are running sgid or
 271      * suid, this function's setting of LD_LIBRARY_PATH will be ineffective and
 272      * we should case a return from the calling function.  Getting the right
 273      * libraries will be handled by the RPATH. In reality, this check is
 274      * redundant, as the previous check for a non-null LD_LIBRARY_PATH will
 275      * return back to the calling function forthwith, it is left here to safe
 276      * guard against any changes, in the glibc's existing security policy.
 277      */
 278     if ((getgid() != getegid()) || (getuid() != geteuid())) {
 279         return JNI_FALSE;
 280     }
 281 #endif /* __linux */
 282 
 283     /*
 284      * Prevent recursions. Since LD_LIBRARY_PATH is the one which will be set by
 285      * previous versions of the JRE, thus it is the only path that matters here.
 286      * So we check to see if the desired JRE is set.
 287      */
 288     JLI_StrNCpy(jpath, jvmpath, PATH_MAX);
 289     p = JLI_StrRChr(jpath, '/');
 290     *p = '\0';
 291     if (llp != NULL && JLI_StrNCmp(llp, jpath, JLI_StrLen(jpath)) == 0) {
 292         return JNI_FALSE;
 293     }
 294 
 295     /* scrutinize all the paths further */
 296     if (llp != NULL &&  ContainsLibJVM(llp)) {
 297         return JNI_TRUE;
 298     }
 299     if (dmllp != NULL && ContainsLibJVM(dmllp)) {
 300         return JNI_TRUE;
 301     }
 302     return JNI_FALSE;
 303 }
 304 #endif /* SETENV_REQUIRED */
 305 
 306 void
 307 CreateExecutionEnvironment(int *pargc, char ***pargv,
 308                            char jrepath[], jint so_jrepath,
 309                            char jvmpath[], jint so_jvmpath,
 310                            char jvmcfg[],  jint so_jvmcfg) {
 311   /*
 312    * First, determine if we are running the desired data model.  If we
 313    * are running the desired data model, all the error messages
 314    * associated with calling GetJREPath, ReadKnownVMs, etc. should be
 315    * output, otherwise we simply exit with an error, as we no longer
 316    * support dual data models.
 317    */
 318     jboolean jvmpathExists;
 319 
 320     /* Compute/set the name of the executable */
 321     SetExecname(*pargv);
 322 
 323     /* Check data model flags, and exec process, if needed */
 324     {
 325       char *arch        = LIBARCHNAME; /* like sparc or sparcv9 */
 326       char * jvmtype    = NULL;
 327       int  argc         = *pargc;
 328       char **argv       = *pargv;
 329       int running       = CURRENT_DATA_MODEL;
 330       /*
 331        * As of jdk9, there is no support for dual mode operations, however
 332        * for legacy error reporting purposes and until -d options are supported
 333        * we need this.
 334        */
 335       int wanted        = running;
 336 #ifdef SETENV_REQUIRED
 337       jboolean mustsetenv = JNI_FALSE;
 338       char *runpath     = NULL; /* existing effective LD_LIBRARY_PATH setting */
 339       char* new_runpath = NULL; /* desired new LD_LIBRARY_PATH string */
 340       char* newpath     = NULL; /* path on new LD_LIBRARY_PATH */
 341       char* lastslash   = NULL;
 342       char** newenvp    = NULL; /* current environment */
 343       size_t new_runpath_size;
 344 #ifdef __solaris__
 345       char*  dmpath     = NULL;  /* data model specific LD_LIBRARY_PATH,
 346                                     Solaris only */
 347 #endif /* __solaris__ */
 348 #endif  /* SETENV_REQUIRED */
 349 
 350       char** newargv    = NULL;
 351       int    newargc    = 0;
 352 
 353       /*
 354        * Starting in 1.5, all unix platforms accept the -d32 and -d64
 355        * options.  On platforms where only one data-model is supported
 356        * (e.g. ia-64 Linux), using the flag for the other data model is
 357        * an error and will terminate the program.
 358        */
 359 
 360       { /* open new scope to declare local variables */
 361         int i;
 362 
 363         newargv = (char **)JLI_MemAlloc((argc+1) * sizeof(char*));
 364         newargv[newargc++] = argv[0];
 365 
 366         /* scan for data model arguments and remove from argument list;
 367            last occurrence determines desired data model */
 368         for (i=1; i < argc; i++) {
 369 
 370           if (JLI_StrCmp(argv[i], "-J-d64") == 0 || JLI_StrCmp(argv[i], "-d64") == 0) {
 371             wanted = 64;
 372             continue;
 373           }
 374           if (JLI_StrCmp(argv[i], "-J-d32") == 0 || JLI_StrCmp(argv[i], "-d32") == 0) {
 375             wanted = 32;
 376             continue;
 377           }
 378           newargv[newargc++] = argv[i];
 379 
 380           if (IsJavaArgs()) {
 381             if (argv[i][0] != '-') continue;
 382           } else {
 383             if (JLI_StrCmp(argv[i], "-classpath") == 0 || JLI_StrCmp(argv[i], "-cp") == 0) {
 384               i++;
 385               if (i >= argc) break;
 386               newargv[newargc++] = argv[i];
 387               continue;
 388             }
 389             if (argv[i][0] != '-') { i++; break; }
 390           }
 391         }
 392 
 393         /* copy rest of args [i .. argc) */
 394         while (i < argc) {
 395           newargv[newargc++] = argv[i++];
 396         }
 397         newargv[newargc] = NULL;
 398 
 399         /*
 400          * newargv has all proper arguments here
 401          */
 402 
 403         argc = newargc;
 404         argv = newargv;
 405       }
 406 
 407       /* If the data model is not changing, it is an error if the
 408          jvmpath does not exist */
 409       if (wanted == running) {
 410         /* Find out where the JRE is that we will be using. */
 411         if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) {
 412           JLI_ReportErrorMessage(JRE_ERROR1);
 413           exit(2);
 414         }
 415         JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg",
 416                      jrepath, FILESEP, FILESEP,  arch, FILESEP);
 417         /* Find the specified JVM type */
 418         if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {
 419           JLI_ReportErrorMessage(CFG_ERROR7);
 420           exit(1);
 421         }
 422 
 423         jvmpath[0] = '\0';
 424         jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE);
 425         if (JLI_StrCmp(jvmtype, "ERROR") == 0) {
 426             JLI_ReportErrorMessage(CFG_ERROR9);
 427             exit(4);
 428         }
 429 
 430         if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, 0 )) {
 431           JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
 432           exit(4);
 433         }
 434         /*
 435          * we seem to have everything we need, so without further ado
 436          * we return back, otherwise proceed to set the environment.
 437          */
 438 #ifdef SETENV_REQUIRED
 439         mustsetenv = RequiresSetenv(jvmpath);
 440         JLI_TraceLauncher("mustsetenv: %s\n", mustsetenv ? "TRUE" : "FALSE");
 441 
 442         if (mustsetenv == JNI_FALSE) {
 443             JLI_MemFree(newargv);
 444             return;
 445         }
 446 #else
 447         JLI_MemFree(newargv);
 448         return;
 449 #endif /* SETENV_REQUIRED */
 450       } else {  /* do the same speculatively or exit */
 451         JLI_ReportErrorMessage(JRE_ERROR2, wanted);
 452         exit(1);
 453       }
 454 #ifdef SETENV_REQUIRED
 455         if (mustsetenv) {
 456             /*
 457              * We will set the LD_LIBRARY_PATH as follows:
 458              *
 459              *     o          $JVMPATH (directory portion only)
 460              *     o          $JRE/lib/$LIBARCHNAME
 461              *     o          $JRE/../lib/$LIBARCHNAME
 462              *
 463              * followed by the user's previous effective LD_LIBRARY_PATH, if
 464              * any.
 465              */
 466 
 467 #ifdef __solaris__
 468             /*
 469              * Starting in Solaris 7, ld.so.1 supports three LD_LIBRARY_PATH
 470              * variables:
 471              *
 472              * 1. LD_LIBRARY_PATH -- used for 32 and 64 bit searches if
 473              * data-model specific variables are not set.
 474              *
 475              * 2. LD_LIBRARY_PATH_64 -- overrides and replaces LD_LIBRARY_PATH
 476              * for 64-bit binaries.
 477              * The vm uses LD_LIBRARY_PATH to set the java.library.path system
 478              * property.  To shield the vm from the complication of multiple
 479              * LD_LIBRARY_PATH variables, if the appropriate data model
 480              * specific variable is set, we will act as if LD_LIBRARY_PATH had
 481              * the value of the data model specific variant and the data model
 482              * specific variant will be unset.  Note that the variable for the
 483              * *wanted* data model must be used (if it is set), not simply the
 484              * current running data model.
 485              */
 486 
 487             switch (wanted) {
 488                 case 0:
 489                 case 64:
 490                     dmpath = getenv("LD_LIBRARY_PATH_64");
 491                     wanted = 64;
 492                     break;
 493 
 494                 default:
 495                     JLI_ReportErrorMessage(JRE_ERROR3, __LINE__);
 496                     exit(1); /* unknown value in wanted */
 497                     break;
 498             }
 499 
 500             /*
 501              * If dmpath is NULL, the relevant data model specific variable is
 502              * not set and normal LD_LIBRARY_PATH should be used.
 503              */
 504             if (dmpath == NULL) {
 505                 runpath = getenv("LD_LIBRARY_PATH");
 506             } else {
 507                 runpath = dmpath;
 508             }
 509 #else /* ! __solaris__ */
 510             /*
 511              * If not on Solaris, assume only a single LD_LIBRARY_PATH
 512              * variable.
 513              */
 514             runpath = getenv(LD_LIBRARY_PATH);
 515 #endif /* __solaris__ */
 516 
 517             /* runpath contains current effective LD_LIBRARY_PATH setting */
 518 
 519             char *new_jvmpath = JLI_StringDup(jvmpath);
 520             new_runpath_size = ((runpath != NULL) ? JLI_StrLen(runpath) : 0) +
 521                     2 * JLI_StrLen(jrepath) + 2 * JLI_StrLen(arch) +
 522 #ifdef AIX
 523                     /* On AIX we additionally need 'jli' in the path because ld doesn't support $ORIGIN. */
 524                     JLI_StrLen(jrepath) + JLI_StrLen(arch) + JLI_StrLen("/lib/jli:") +
 525 #endif
 526                     JLI_StrLen(new_jvmpath) + 52;
 527             new_runpath = JLI_MemAlloc(new_runpath_size);
 528             newpath = new_runpath + JLI_StrLen(LD_LIBRARY_PATH "=");
 529 
 530 
 531             /*
 532              * Create desired LD_LIBRARY_PATH value for target data model.
 533              */
 534             {
 535                 /* remove the name of the .so from the JVM path */
 536                 lastslash = JLI_StrRChr(new_jvmpath, '/');
 537                 if (lastslash)
 538                     *lastslash = '\0';
 539 
 540                 sprintf(new_runpath, LD_LIBRARY_PATH "="
 541                         "%s:"
 542                         "%s/lib/%s:"
 543 #ifdef AIX
 544                         "%s/lib/%s/jli:" /* Needed on AIX because ld doesn't support $ORIGIN. */
 545 #endif
 546                         "%s/../lib/%s",
 547                         new_jvmpath,
 548                         jrepath, arch,
 549 #ifdef AIX
 550                         jrepath, arch,
 551 #endif
 552                         jrepath, arch
 553                         );
 554 
 555                 JLI_MemFree(new_jvmpath);
 556 
 557                 /*
 558                  * Check to make sure that the prefix of the current path is the
 559                  * desired environment variable setting, though the RequiresSetenv
 560                  * checks if the desired runpath exists, this logic does a more
 561                  * comprehensive check.
 562                  */
 563                 if (runpath != NULL &&
 564                         JLI_StrNCmp(newpath, runpath, JLI_StrLen(newpath)) == 0 &&
 565                         (runpath[JLI_StrLen(newpath)] == 0 || runpath[JLI_StrLen(newpath)] == ':') &&
 566                         (running == wanted) /* data model does not have to be changed */
 567 #ifdef __solaris__
 568                         && (dmpath == NULL) /* data model specific variables not set  */
 569 #endif /* __solaris__ */
 570                         ) {
 571                     JLI_MemFree(newargv);
 572                     JLI_MemFree(new_runpath);
 573                     return;
 574                 }
 575             }
 576 
 577             /*
 578              * Place the desired environment setting onto the prefix of
 579              * LD_LIBRARY_PATH.  Note that this prevents any possible infinite
 580              * loop of execv() because we test for the prefix, above.
 581              */
 582             if (runpath != 0) {
 583                 /* ensure storage for runpath + colon + NULL */
 584                 if ((JLI_StrLen(runpath) + 1 + 1) > new_runpath_size) {
 585                     JLI_ReportErrorMessageSys(JRE_ERROR11);
 586                     exit(1);
 587                 }
 588                 JLI_StrCat(new_runpath, ":");
 589                 JLI_StrCat(new_runpath, runpath);
 590             }
 591 
 592             if (putenv(new_runpath) != 0) {
 593                 exit(1); /* problem allocating memory; LD_LIBRARY_PATH not set
 594                     properly */
 595             }
 596 
 597             /*
 598              * Unix systems document that they look at LD_LIBRARY_PATH only
 599              * once at startup, so we have to re-exec the current executable
 600              * to get the changed environment variable to have an effect.
 601              */
 602 
 603 #ifdef __solaris__
 604             /*
 605              * If dmpath is not NULL, remove the data model specific string
 606              * in the environment for the exec'ed child.
 607              */
 608             if (dmpath != NULL)
 609                 (void)UnsetEnv("LD_LIBRARY_PATH_64");
 610 #endif /* __solaris */
 611 
 612             newenvp = environ;
 613         }
 614 #endif /* SETENV_REQUIRED */
 615         {
 616             char *newexec = execname;
 617             JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n");
 618             (void) fflush(stdout);
 619             (void) fflush(stderr);
 620 #ifdef SETENV_REQUIRED
 621             if (mustsetenv) {
 622                 execve(newexec, argv, newenvp);
 623             } else {
 624                 execv(newexec, argv);
 625             }
 626 #else /* !SETENV_REQUIRED */
 627             execv(newexec, argv);
 628 #endif /* SETENV_REQUIRED */
 629             JLI_ReportErrorMessageSys(JRE_ERROR4, newexec);
 630         }
 631         exit(1);
 632     }
 633 }
 634 
 635 /*
 636  * On Solaris VM choosing is done by the launcher (java.c),
 637  * bitsWanted is used by MacOSX,  on Solaris and Linux this.
 638  * parameter is unused.
 639  */
 640 static jboolean
 641 GetJVMPath(const char *jrepath, const char *jvmtype,
 642            char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)
 643 {
 644     struct stat s;
 645 
 646     if (JLI_StrChr(jvmtype, '/')) {
 647         JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);
 648     } else {
 649         JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/%s/" JVM_DLL, jrepath, arch, jvmtype);
 650     }
 651 
 652     JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
 653 
 654     if (stat(jvmpath, &s) == 0) {
 655         JLI_TraceLauncher("yes.\n");
 656         return JNI_TRUE;
 657     } else {
 658         JLI_TraceLauncher("no.\n");
 659         return JNI_FALSE;
 660     }
 661 }
 662 
 663 /*
 664  * Find path to JRE based on .exe's location or registry settings.
 665  */
 666 static jboolean
 667 GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)
 668 {
 669     char libjava[MAXPATHLEN];
 670     struct stat s;
 671 
 672     if (GetApplicationHome(path, pathsize)) {
 673         /* Is JRE co-located with the application? */
 674         JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/%s/" JAVA_DLL, path, arch);
 675         if (access(libjava, F_OK) == 0) {
 676             JLI_TraceLauncher("JRE path is %s\n", path);
 677             return JNI_TRUE;
 678         }
 679         /* ensure storage for path + /jre + NULL */
 680         if ((JLI_StrLen(path) + 4  + 1) > (size_t) pathsize) {
 681             JLI_TraceLauncher("Insufficient space to store JRE path\n");
 682             return JNI_FALSE;
 683         }
 684         /* Does the app ship a private JRE in <apphome>/jre directory? */
 685         JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/%s/" JAVA_DLL, path, arch);
 686         if (access(libjava, F_OK) == 0) {
 687             JLI_StrCat(path, "/jre");
 688             JLI_TraceLauncher("JRE path is %s\n", path);
 689             return JNI_TRUE;
 690         }
 691     }
 692 
 693     if (GetApplicationHomeFromDll(path, pathsize)) {
 694         JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/%s/" JAVA_DLL, path, arch);
 695         if (stat(libjava, &s) == 0) {
 696             JLI_TraceLauncher("JRE path is %s\n", path);
 697             return JNI_TRUE;
 698         }
 699     }
 700 
 701     if (!speculative)
 702       JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);
 703     return JNI_FALSE;
 704 }
 705 
 706 jboolean
 707 LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
 708 {
 709     void *libjvm;
 710 
 711     JLI_TraceLauncher("JVM path is %s\n", jvmpath);
 712 
 713     libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
 714     if (libjvm == NULL) {
 715 #if defined(__solaris__) && defined(__sparc) && !defined(_LP64) /* i.e. 32-bit sparc */
 716       FILE * fp;
 717       Elf32_Ehdr elf_head;
 718       int count;
 719       int location;
 720 
 721       fp = fopen(jvmpath, "r");
 722       if (fp == NULL) {
 723         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 724         return JNI_FALSE;
 725       }
 726 
 727       /* read in elf header */
 728       count = fread((void*)(&elf_head), sizeof(Elf32_Ehdr), 1, fp);
 729       fclose(fp);
 730       if (count < 1) {
 731         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 732         return JNI_FALSE;
 733       }
 734 
 735       /*
 736        * Check for running a server vm (compiled with -xarch=v8plus)
 737        * on a stock v8 processor.  In this case, the machine type in
 738        * the elf header would not be included the architecture list
 739        * provided by the isalist command, which is turn is gotten from
 740        * sysinfo.  This case cannot occur on 64-bit hardware and thus
 741        * does not have to be checked for in binaries with an LP64 data
 742        * model.
 743        */
 744       if (elf_head.e_machine == EM_SPARC32PLUS) {
 745         char buf[257];  /* recommended buffer size from sysinfo man
 746                            page */
 747         long length;
 748         char* location;
 749 
 750         length = sysinfo(SI_ISALIST, buf, 257);
 751         if (length > 0) {
 752             location = JLI_StrStr(buf, "sparcv8plus ");
 753           if (location == NULL) {
 754             JLI_ReportErrorMessage(JVM_ERROR3);
 755             return JNI_FALSE;
 756           }
 757         }
 758       }
 759 #endif
 760         JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);
 761         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 762         return JNI_FALSE;
 763     }
 764 
 765     ifn->CreateJavaVM = (CreateJavaVM_t)
 766         dlsym(libjvm, "JNI_CreateJavaVM");
 767     if (ifn->CreateJavaVM == NULL) {
 768         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 769         return JNI_FALSE;
 770     }
 771 
 772     ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
 773         dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
 774     if (ifn->GetDefaultJavaVMInitArgs == NULL) {
 775         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 776         return JNI_FALSE;
 777     }
 778 
 779     ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)
 780         dlsym(libjvm, "JNI_GetCreatedJavaVMs");
 781     if (ifn->GetCreatedJavaVMs == NULL) {
 782         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 783         return JNI_FALSE;
 784     }
 785 
 786     return JNI_TRUE;
 787 }
 788 
 789 /*
 790  * Compute the name of the executable
 791  *
 792  * In order to re-exec securely we need the absolute path of the
 793  * executable. On Solaris getexecname(3c) may not return an absolute
 794  * path so we use dladdr to get the filename of the executable and
 795  * then use realpath to derive an absolute path. From Solaris 9
 796  * onwards the filename returned in DL_info structure from dladdr is
 797  * an absolute pathname so technically realpath isn't required.
 798  * On Linux we read the executable name from /proc/self/exe.
 799  * As a fallback, and for platforms other than Solaris and Linux,
 800  * we use FindExecName to compute the executable name.
 801  */
 802 const char*
 803 SetExecname(char **argv)
 804 {
 805     char* exec_path = NULL;
 806 #if defined(__solaris__)
 807     {
 808         Dl_info dlinfo;
 809         int (*fptr)();
 810 
 811         fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
 812         if (fptr == NULL) {
 813             JLI_ReportErrorMessage(DLL_ERROR3, dlerror());
 814             return JNI_FALSE;
 815         }
 816 
 817         if (dladdr((void*)fptr, &dlinfo)) {
 818             char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1);
 819             if (resolved != NULL) {
 820                 exec_path = realpath(dlinfo.dli_fname, resolved);
 821                 if (exec_path == NULL) {
 822                     JLI_MemFree(resolved);
 823                 }
 824             }
 825         }
 826     }
 827 #elif defined(__linux__)
 828     {
 829         const char* self = "/proc/self/exe";
 830         char buf[PATH_MAX+1];
 831         int len = readlink(self, buf, PATH_MAX);
 832         if (len >= 0) {
 833             buf[len] = '\0';            /* readlink(2) doesn't NUL terminate */
 834             exec_path = JLI_StringDup(buf);
 835         }
 836     }
 837 #else /* !__solaris__ && !__linux__ */
 838     {
 839         /* Not implemented */
 840     }
 841 #endif
 842 
 843     if (exec_path == NULL) {
 844         exec_path = FindExecName(argv[0]);
 845     }
 846     execname = exec_path;
 847     return exec_path;
 848 }
 849 
 850 /* --- Splash Screen shared library support --- */
 851 static const char* SPLASHSCREEN_SO = JNI_LIB_NAME("splashscreen");
 852 static void* hSplashLib = NULL;
 853 
 854 void* SplashProcAddress(const char* name) {
 855     if (!hSplashLib) {
 856         int ret;
 857         char jrePath[MAXPATHLEN];
 858         char splashPath[MAXPATHLEN];
 859 
 860         if (!GetJREPath(jrePath, sizeof(jrePath), LIBARCHNAME, JNI_FALSE)) {
 861             JLI_ReportErrorMessage(JRE_ERROR1);
 862             return NULL;
 863         }
 864         ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s/%s",
 865                      jrePath, LIBARCHNAME, SPLASHSCREEN_SO);
 866 
 867         if (ret >= (int) sizeof(splashPath)) {
 868             JLI_ReportErrorMessage(JRE_ERROR11);
 869             return NULL;
 870         }
 871         if (ret < 0) {
 872             JLI_ReportErrorMessage(JRE_ERROR13);
 873             return NULL;
 874         }
 875         hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL);
 876         JLI_TraceLauncher("Info: loaded %s\n", splashPath);
 877     }
 878     if (hSplashLib) {
 879         void* sym = dlsym(hSplashLib, name);
 880         return sym;
 881     } else {
 882         return NULL;
 883     }
 884 }
 885 
 886 void SplashFreeLibrary() {
 887     if (hSplashLib) {
 888         dlclose(hSplashLib);
 889         hSplashLib = NULL;
 890     }
 891 }
 892 
 893 /*
 894  * Block current thread and continue execution in a new thread
 895  */
 896 int
 897 ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) {
 898     int rslt;
 899 #ifndef __solaris__
 900     pthread_t tid;
 901     pthread_attr_t attr;
 902     pthread_attr_init(&attr);
 903     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 904 
 905     if (stack_size > 0) {
 906       pthread_attr_setstacksize(&attr, stack_size);
 907     }
 908 
 909     if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) {
 910       void * tmp;
 911       pthread_join(tid, &tmp);
 912       rslt = (int)(intptr_t)tmp;
 913     } else {
 914      /*
 915       * Continue execution in current thread if for some reason (e.g. out of
 916       * memory/LWP)  a new thread can't be created. This will likely fail
 917       * later in continuation as JNI_CreateJavaVM needs to create quite a
 918       * few new threads, anyway, just give it a try..
 919       */
 920       rslt = continuation(args);
 921     }
 922 
 923     pthread_attr_destroy(&attr);
 924 #else /* __solaris__ */
 925     thread_t tid;
 926     long flags = 0;
 927     if (thr_create(NULL, stack_size, (void *(*)(void *))continuation, args, flags, &tid) == 0) {
 928       void * tmp;
 929       thr_join(tid, NULL, &tmp);
 930       rslt = (int)(intptr_t)tmp;
 931     } else {
 932       /* See above. Continue in current thread if thr_create() failed */
 933       rslt = continuation(args);
 934     }
 935 #endif /* !__solaris__ */
 936     return rslt;
 937 }
 938 
 939 /* Coarse estimation of number of digits assuming the worst case is a 64-bit pid. */
 940 #define MAX_PID_STR_SZ   20
 941 
 942 void SetJavaLauncherPlatformProps() {
 943    /* Linux only */
 944 #ifdef __linux__
 945     const char *substr = "-Dsun.java.launcher.pid=";
 946     char *pid_prop_str = (char *)JLI_MemAlloc(JLI_StrLen(substr) + MAX_PID_STR_SZ + 1);
 947     sprintf(pid_prop_str, "%s%d", substr, getpid());
 948     AddOption(pid_prop_str, NULL);
 949 #endif /* __linux__ */
 950 }
 951 
 952 int
 953 JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
 954         int argc, char **argv,
 955         int mode, char *what, int ret)
 956 {
 957     ShowSplashScreen();
 958     return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
 959 }
 960 
 961 void
 962 PostJVMInit(JNIEnv *env, jclass mainClass, JavaVM *vm)
 963 {
 964     // stubbed out for windows and *nixes.
 965 }
 966 
 967 void
 968 RegisterThread()
 969 {
 970     // stubbed out for windows and *nixes.
 971 }
 972 
 973 /*
 974  * on unix, we return a false to indicate this option is not applicable
 975  */
 976 jboolean
 977 ProcessPlatformOption(const char *arg)
 978 {
 979     return JNI_FALSE;
 980 }