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