1 /*
   2  * Copyright (c) 1998, 2015, 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 #ifdef __solaris__
 344       char*  dmpath     = NULL;  /* data model specific LD_LIBRARY_PATH,
 345                                     Solaris only */
 346 #endif /* __solaris__ */
 347 #endif  /* SETENV_REQUIRED */
 348 
 349       char** newargv    = NULL;
 350       int    newargc    = 0;
 351 
 352       /*
 353        * Starting in 1.5, all unix platforms accept the -d32 and -d64
 354        * options.  On platforms where only one data-model is supported
 355        * (e.g. ia-64 Linux), using the flag for the other data model is
 356        * an error and will terminate the program.
 357        */
 358 
 359       { /* open new scope to declare local variables */
 360         int i;
 361 
 362         newargv = (char **)JLI_MemAlloc((argc+1) * sizeof(char*));
 363         newargv[newargc++] = argv[0];
 364 
 365         /* scan for data model arguments and remove from argument list;
 366            last occurrence determines desired data model */
 367         for (i=1; i < argc; i++) {
 368 
 369           if (JLI_StrCmp(argv[i], "-J-d64") == 0 || JLI_StrCmp(argv[i], "-d64") == 0) {
 370             wanted = 64;
 371             continue;
 372           }
 373           if (JLI_StrCmp(argv[i], "-J-d32") == 0 || JLI_StrCmp(argv[i], "-d32") == 0) {
 374             wanted = 32;
 375             continue;
 376           }
 377           newargv[newargc++] = argv[i];
 378 
 379           if (IsJavaArgs()) {
 380             if (argv[i][0] != '-') continue;
 381           } else {
 382             if (JLI_StrCmp(argv[i], "-classpath") == 0 || JLI_StrCmp(argv[i], "-cp") == 0) {
 383               i++;
 384               if (i >= argc) break;
 385               newargv[newargc++] = argv[i];
 386               continue;
 387             }
 388             if (argv[i][0] != '-') { i++; break; }
 389           }
 390         }
 391 
 392         /* copy rest of args [i .. argc) */
 393         while (i < argc) {
 394           newargv[newargc++] = argv[i++];
 395         }
 396         newargv[newargc] = NULL;
 397 
 398         /*
 399          * newargv has all proper arguments here
 400          */
 401 
 402         argc = newargc;
 403         argv = newargv;
 404       }
 405 
 406       /* If the data model is not changing, it is an error if the
 407          jvmpath does not exist */
 408       if (wanted == running) {
 409         /* Find out where the JRE is that we will be using. */
 410         if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) {
 411           JLI_ReportErrorMessage(JRE_ERROR1);
 412           exit(2);
 413         }
 414         JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg",
 415                      jrepath, FILESEP, FILESEP,  arch, FILESEP);
 416         /* Find the specified JVM type */
 417         if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {
 418           JLI_ReportErrorMessage(CFG_ERROR7);
 419           exit(1);
 420         }
 421 
 422         jvmpath[0] = '\0';
 423         jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE);
 424         if (JLI_StrCmp(jvmtype, "ERROR") == 0) {
 425             JLI_ReportErrorMessage(CFG_ERROR9);
 426             exit(4);
 427         }
 428 
 429         if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, 0 )) {
 430           JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
 431           exit(4);
 432         }
 433         /*
 434          * we seem to have everything we need, so without further ado
 435          * we return back, otherwise proceed to set the environment.
 436          */
 437 #ifdef SETENV_REQUIRED
 438         mustsetenv = RequiresSetenv(jvmpath);
 439         JLI_TraceLauncher("mustsetenv: %s\n", mustsetenv ? "TRUE" : "FALSE");
 440 
 441         if (mustsetenv == JNI_FALSE) {
 442             JLI_MemFree(newargv);
 443             return;
 444         }
 445 #else
 446             JLI_MemFree(newargv);
 447             return;
 448 #endif /* SETENV_REQUIRED */
 449     } else {  /* do the same speculatively or exit */
 450         JLI_ReportErrorMessage(JRE_ERROR2, wanted);
 451         exit(1);
 452     }
 453 #ifdef SETENV_REQUIRED
 454         if (mustsetenv) {
 455             /*
 456              * We will set the LD_LIBRARY_PATH as follows:
 457              *
 458              *     o          $JVMPATH (directory portion only)
 459              *     o          $JRE/lib/$LIBARCHNAME
 460              *     o          $JRE/../lib/$LIBARCHNAME
 461              *
 462              * followed by the user's previous effective LD_LIBRARY_PATH, if
 463              * any.
 464              */
 465 
 466 #ifdef __solaris__
 467             /*
 468              * Starting in Solaris 7, ld.so.1 supports three LD_LIBRARY_PATH
 469              * variables:
 470              *
 471              * 1. LD_LIBRARY_PATH -- used for 32 and 64 bit searches if
 472              * data-model specific variables are not set.
 473              *
 474              * 2. LD_LIBRARY_PATH_64 -- overrides and replaces LD_LIBRARY_PATH
 475              * for 64-bit binaries.
 476              * The vm uses LD_LIBRARY_PATH to set the java.library.path system
 477              * property.  To shield the vm from the complication of multiple
 478              * LD_LIBRARY_PATH variables, if the appropriate data model
 479              * specific variable is set, we will act as if LD_LIBRARY_PATH had
 480              * the value of the data model specific variant and the data model
 481              * specific variant will be unset.  Note that the variable for the
 482              * *wanted* data model must be used (if it is set), not simply the
 483              * current running data model.
 484              */
 485 
 486             switch (wanted) {
 487                 case 0:
 488                 case 64:
 489                     dmpath = getenv("LD_LIBRARY_PATH_64");
 490                     wanted = 64;
 491                     break;
 492 
 493                 default:
 494                     JLI_ReportErrorMessage(JRE_ERROR3, __LINE__);
 495                     exit(1); /* unknown value in wanted */
 496                     break;
 497             }
 498 
 499             /*
 500              * If dmpath is NULL, the relevant data model specific variable is
 501              * not set and normal LD_LIBRARY_PATH should be used.
 502              */
 503             if (dmpath == NULL) {
 504                 runpath = getenv("LD_LIBRARY_PATH");
 505             } else {
 506                 runpath = dmpath;
 507             }
 508 #else /* ! __solaris__ */
 509             /*
 510              * If not on Solaris, assume only a single LD_LIBRARY_PATH
 511              * variable.
 512              */
 513             runpath = getenv(LD_LIBRARY_PATH);
 514 #endif /* __solaris__ */
 515 
 516             /* runpath contains current effective LD_LIBRARY_PATH setting */
 517 
 518             jvmpath = JLI_StringDup(jvmpath);
 519             new_runpath = JLI_MemAlloc(((runpath != NULL) ? JLI_StrLen(runpath) : 0) +
 520                     2 * JLI_StrLen(jrepath) + 2 * JLI_StrLen(arch) +
 521 #ifdef AIX
 522                     /* On AIX we additionally need 'jli' in the path because ld doesn't support $ORIGIN. */
 523                     JLI_StrLen(jrepath) + JLI_StrLen(arch) + JLI_StrLen("/lib//jli:") +
 524 #endif
 525                     JLI_StrLen(jvmpath) + 52);
 526             newpath = new_runpath + JLI_StrLen(LD_LIBRARY_PATH "=");
 527 
 528 
 529             /*
 530              * Create desired LD_LIBRARY_PATH value for target data model.
 531              */
 532             {
 533                 /* remove the name of the .so from the JVM path */
 534                 lastslash = JLI_StrRChr(jvmpath, '/');
 535                 if (lastslash)
 536                     *lastslash = '\0';
 537 
 538                 sprintf(new_runpath, LD_LIBRARY_PATH "="
 539                         "%s:"
 540                         "%s/lib/%s:"
 541 #ifdef AIX
 542                         "%s/lib/%s/jli:" /* Needed on AIX because ld doesn't support $ORIGIN. */
 543 #endif
 544                         "%s/../lib/%s",
 545                         jvmpath,
 546                         jrepath, arch,
 547 #ifdef AIX
 548                         jrepath, arch,
 549 #endif
 550                         jrepath, arch
 551                         );
 552 
 553 
 554                 /*
 555                  * Check to make sure that the prefix of the current path is the
 556                  * desired environment variable setting, though the RequiresSetenv
 557                  * checks if the desired runpath exists, this logic does a more
 558                  * comprehensive check.
 559                  */
 560                 if (runpath != NULL &&
 561                         JLI_StrNCmp(newpath, runpath, JLI_StrLen(newpath)) == 0 &&
 562                         (runpath[JLI_StrLen(newpath)] == 0 || runpath[JLI_StrLen(newpath)] == ':') &&
 563                         (running == wanted) /* data model does not have to be changed */
 564 #ifdef __solaris__
 565                         && (dmpath == NULL) /* data model specific variables not set  */
 566 #endif /* __solaris__ */
 567                         ) {
 568                     JLI_MemFree(newargv);
 569                     JLI_MemFree(new_runpath);
 570                     return;
 571                 }
 572             }
 573 
 574             /*
 575              * Place the desired environment setting onto the prefix of
 576              * LD_LIBRARY_PATH.  Note that this prevents any possible infinite
 577              * loop of execv() because we test for the prefix, above.
 578              */
 579             if (runpath != 0) {
 580                 JLI_StrCat(new_runpath, ":");
 581                 JLI_StrCat(new_runpath, runpath);
 582             }
 583 
 584             if (putenv(new_runpath) != 0) {
 585                 exit(1); /* problem allocating memory; LD_LIBRARY_PATH not set
 586                     properly */
 587             }
 588 
 589             /*
 590              * Unix systems document that they look at LD_LIBRARY_PATH only
 591              * once at startup, so we have to re-exec the current executable
 592              * to get the changed environment variable to have an effect.
 593              */
 594 
 595 #ifdef __solaris__
 596             /*
 597              * If dmpath is not NULL, remove the data model specific string
 598              * in the environment for the exec'ed child.
 599              */
 600             if (dmpath != NULL)
 601                 (void)UnsetEnv("LD_LIBRARY_PATH_64");
 602 #endif /* __solaris */
 603 
 604             newenvp = environ;
 605         }
 606 #endif /* SETENV_REQUIRED */
 607         {
 608             char *newexec = execname;
 609             JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n");
 610             (void) fflush(stdout);
 611             (void) fflush(stderr);
 612 #ifdef SETENV_REQUIRED
 613             if (mustsetenv) {
 614                 execve(newexec, argv, newenvp);
 615             } else {
 616                 execv(newexec, argv);
 617             }
 618 #else /* !SETENV_REQUIRED */
 619             execv(newexec, argv);
 620 #endif /* SETENV_REQUIRED */
 621             JLI_ReportErrorMessageSys(JRE_ERROR4, newexec);
 622         }
 623         exit(1);
 624     }
 625 }
 626 
 627 /*
 628  * On Solaris VM choosing is done by the launcher (java.c),
 629  * bitsWanted is used by MacOSX,  on Solaris and Linux this.
 630  * parameter is unused.
 631  */
 632 static jboolean
 633 GetJVMPath(const char *jrepath, const char *jvmtype,
 634            char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)
 635 {
 636     struct stat s;
 637 
 638     if (JLI_StrChr(jvmtype, '/')) {
 639         JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);
 640     } else {
 641         JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/%s/" JVM_DLL, jrepath, arch, jvmtype);
 642     }
 643 
 644     JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
 645 
 646     if (stat(jvmpath, &s) == 0) {
 647         JLI_TraceLauncher("yes.\n");
 648         return JNI_TRUE;
 649     } else {
 650         JLI_TraceLauncher("no.\n");
 651         return JNI_FALSE;
 652     }
 653 }
 654 
 655 /*
 656  * Find path to JRE based on .exe's location or registry settings.
 657  */
 658 static jboolean
 659 GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)
 660 {
 661     char libjava[MAXPATHLEN];
 662 
 663     if (GetApplicationHome(path, pathsize)) {
 664         /* Is JRE co-located with the application? */
 665         JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/%s/" JAVA_DLL, path, arch);
 666         if (access(libjava, F_OK) == 0) {
 667             JLI_TraceLauncher("JRE path is %s\n", path);
 668             return JNI_TRUE;
 669         }
 670 
 671         /* Does the app ship a private JRE in <apphome>/jre directory? */
 672         JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/%s/" JAVA_DLL, path, arch);
 673         if (access(libjava, F_OK) == 0) {
 674             JLI_StrCat(path, "/jre");
 675             JLI_TraceLauncher("JRE path is %s\n", path);
 676             return JNI_TRUE;
 677         }
 678     }
 679 
 680     if (!speculative)
 681       JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);
 682     return JNI_FALSE;
 683 }
 684 
 685 jboolean
 686 LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
 687 {
 688     void *libjvm;
 689 
 690     JLI_TraceLauncher("JVM path is %s\n", jvmpath);
 691 
 692     libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
 693     if (libjvm == NULL) {
 694 #if defined(__solaris__) && defined(__sparc) && !defined(_LP64) /* i.e. 32-bit sparc */
 695       FILE * fp;
 696       Elf32_Ehdr elf_head;
 697       int count;
 698       int location;
 699 
 700       fp = fopen(jvmpath, "r");
 701       if (fp == NULL) {
 702         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 703         return JNI_FALSE;
 704       }
 705 
 706       /* read in elf header */
 707       count = fread((void*)(&elf_head), sizeof(Elf32_Ehdr), 1, fp);
 708       fclose(fp);
 709       if (count < 1) {
 710         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 711         return JNI_FALSE;
 712       }
 713 
 714       /*
 715        * Check for running a server vm (compiled with -xarch=v8plus)
 716        * on a stock v8 processor.  In this case, the machine type in
 717        * the elf header would not be included the architecture list
 718        * provided by the isalist command, which is turn is gotten from
 719        * sysinfo.  This case cannot occur on 64-bit hardware and thus
 720        * does not have to be checked for in binaries with an LP64 data
 721        * model.
 722        */
 723       if (elf_head.e_machine == EM_SPARC32PLUS) {
 724         char buf[257];  /* recommended buffer size from sysinfo man
 725                            page */
 726         long length;
 727         char* location;
 728 
 729         length = sysinfo(SI_ISALIST, buf, 257);
 730         if (length > 0) {
 731             location = JLI_StrStr(buf, "sparcv8plus ");
 732           if (location == NULL) {
 733             JLI_ReportErrorMessage(JVM_ERROR3);
 734             return JNI_FALSE;
 735           }
 736         }
 737       }
 738 #endif
 739         JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);
 740         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 741         return JNI_FALSE;
 742     }
 743 
 744     ifn->CreateJavaVM = (CreateJavaVM_t)
 745         dlsym(libjvm, "JNI_CreateJavaVM");
 746     if (ifn->CreateJavaVM == NULL) {
 747         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 748         return JNI_FALSE;
 749     }
 750 
 751     ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
 752         dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
 753     if (ifn->GetDefaultJavaVMInitArgs == NULL) {
 754         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 755         return JNI_FALSE;
 756     }
 757 
 758     ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)
 759         dlsym(libjvm, "JNI_GetCreatedJavaVMs");
 760     if (ifn->GetCreatedJavaVMs == NULL) {
 761         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
 762         return JNI_FALSE;
 763     }
 764 
 765     return JNI_TRUE;
 766 }
 767 
 768 /*
 769  * Compute the name of the executable
 770  *
 771  * In order to re-exec securely we need the absolute path of the
 772  * executable. On Solaris getexecname(3c) may not return an absolute
 773  * path so we use dladdr to get the filename of the executable and
 774  * then use realpath to derive an absolute path. From Solaris 9
 775  * onwards the filename returned in DL_info structure from dladdr is
 776  * an absolute pathname so technically realpath isn't required.
 777  * On Linux we read the executable name from /proc/self/exe.
 778  * As a fallback, and for platforms other than Solaris and Linux,
 779  * we use FindExecName to compute the executable name.
 780  */
 781 const char*
 782 SetExecname(char **argv)
 783 {
 784     char* exec_path = NULL;
 785 #if defined(__solaris__)
 786     {
 787         Dl_info dlinfo;
 788         int (*fptr)();
 789 
 790         fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
 791         if (fptr == NULL) {
 792             JLI_ReportErrorMessage(DLL_ERROR3, dlerror());
 793             return JNI_FALSE;
 794         }
 795 
 796         if (dladdr((void*)fptr, &dlinfo)) {
 797             char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1);
 798             if (resolved != NULL) {
 799                 exec_path = realpath(dlinfo.dli_fname, resolved);
 800                 if (exec_path == NULL) {
 801                     JLI_MemFree(resolved);
 802                 }
 803             }
 804         }
 805     }
 806 #elif defined(__linux__)
 807     {
 808         const char* self = "/proc/self/exe";
 809         char buf[PATH_MAX+1];
 810         int len = readlink(self, buf, PATH_MAX);
 811         if (len >= 0) {
 812             buf[len] = '\0';            /* readlink(2) doesn't NUL terminate */
 813             exec_path = JLI_StringDup(buf);
 814         }
 815     }
 816 #else /* !__solaris__ && !__linux__ */
 817     {
 818         /* Not implemented */
 819     }
 820 #endif
 821 
 822     if (exec_path == NULL) {
 823         exec_path = FindExecName(argv[0]);
 824     }
 825     execname = exec_path;
 826     return exec_path;
 827 }
 828 
 829 /* --- Splash Screen shared library support --- */
 830 static const char* SPLASHSCREEN_SO = JNI_LIB_NAME("splashscreen");
 831 static void* hSplashLib = NULL;
 832 
 833 void* SplashProcAddress(const char* name) {
 834     if (!hSplashLib) {
 835         int ret;
 836         char jrePath[MAXPATHLEN];
 837         char splashPath[MAXPATHLEN];
 838 
 839         if (!GetJREPath(jrePath, sizeof(jrePath), LIBARCHNAME, JNI_FALSE)) {
 840             JLI_ReportErrorMessage(JRE_ERROR1);
 841             return NULL;
 842         }
 843         ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s/%s",
 844                      jrePath, LIBARCHNAME, SPLASHSCREEN_SO);
 845 
 846         if (ret >= (int) sizeof(splashPath)) {
 847             JLI_ReportErrorMessage(JRE_ERROR11);
 848             return NULL;
 849         }
 850         if (ret < 0) {
 851             JLI_ReportErrorMessage(JRE_ERROR13);
 852             return NULL;
 853         }
 854         hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL);
 855         JLI_TraceLauncher("Info: loaded %s\n", splashPath);
 856     }
 857     if (hSplashLib) {
 858         void* sym = dlsym(hSplashLib, name);
 859         return sym;
 860     } else {
 861         return NULL;
 862     }
 863 }
 864 
 865 void SplashFreeLibrary() {
 866     if (hSplashLib) {
 867         dlclose(hSplashLib);
 868         hSplashLib = NULL;
 869     }
 870 }
 871 
 872 /*
 873  * Block current thread and continue execution in a new thread
 874  */
 875 int
 876 ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) {
 877     int rslt;
 878 #ifndef __solaris__
 879     pthread_t tid;
 880     pthread_attr_t attr;
 881     pthread_attr_init(&attr);
 882     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 883 
 884     if (stack_size > 0) {
 885       pthread_attr_setstacksize(&attr, stack_size);
 886     }
 887 
 888     if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) {
 889       void * tmp;
 890       pthread_join(tid, &tmp);
 891       rslt = (int)(intptr_t)tmp;
 892     } else {
 893      /*
 894       * Continue execution in current thread if for some reason (e.g. out of
 895       * memory/LWP)  a new thread can't be created. This will likely fail
 896       * later in continuation as JNI_CreateJavaVM needs to create quite a
 897       * few new threads, anyway, just give it a try..
 898       */
 899       rslt = continuation(args);
 900     }
 901 
 902     pthread_attr_destroy(&attr);
 903 #else /* __solaris__ */
 904     thread_t tid;
 905     long flags = 0;
 906     if (thr_create(NULL, stack_size, (void *(*)(void *))continuation, args, flags, &tid) == 0) {
 907       void * tmp;
 908       thr_join(tid, NULL, &tmp);
 909       rslt = (int)(intptr_t)tmp;
 910     } else {
 911       /* See above. Continue in current thread if thr_create() failed */
 912       rslt = continuation(args);
 913     }
 914 #endif /* !__solaris__ */
 915     return rslt;
 916 }
 917 
 918 /* Coarse estimation of number of digits assuming the worst case is a 64-bit pid. */
 919 #define MAX_PID_STR_SZ   20
 920 
 921 void SetJavaLauncherPlatformProps() {
 922    /* Linux only */
 923 #ifdef __linux__
 924     const char *substr = "-Dsun.java.launcher.pid=";
 925     char *pid_prop_str = (char *)JLI_MemAlloc(JLI_StrLen(substr) + MAX_PID_STR_SZ + 1);
 926     sprintf(pid_prop_str, "%s%d", substr, getpid());
 927     AddOption(pid_prop_str, NULL);
 928 #endif /* __linux__ */
 929 }
 930 
 931 int
 932 JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
 933         int argc, char **argv,
 934         int mode, char *what, int ret)
 935 {
 936     ShowSplashScreen();
 937     return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
 938 }
 939 
 940 void
 941 PostJVMInit(JNIEnv *env, jclass mainClass, JavaVM *vm)
 942 {
 943     // stubbed out for windows and *nixes.
 944 }
 945 
 946 void
 947 RegisterThread()
 948 {
 949     // stubbed out for windows and *nixes.
 950 }
 951 
 952 /*
 953  * on unix, we return a false to indicate this option is not applicable
 954  */
 955 jboolean
 956 ProcessPlatformOption(const char *arg)
 957 {
 958     return JNI_FALSE;
 959 }