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