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