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