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