Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/unix/native/libjli/java_md.c
41119 views
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
#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
/*
55
* Flowchart of launcher execs and options processing on unix
56
*
57
* The selection of the proper vm shared library to open depends on
58
* several classes of command line options, including vm "flavor"
59
* options (-client, -server).
60
* The vm selection options are not passed to the running
61
* virtual machine; they must be screened out by the launcher.
62
*
63
* The version specification (if any) is processed first by the
64
* platform independent routine SelectVersion. This may result in
65
* the exec of the specified launcher version.
66
*
67
* Previously the launcher modified the LD_LIBRARY_PATH appropriately for the
68
* desired data model path, regardless if data models matched or not. The
69
* launcher subsequently exec'ed the desired executable, in order to make the
70
* LD_LIBRARY_PATH path available, for the runtime linker.
71
*
72
* Now, in most cases,the launcher will dlopen the target libjvm.so. All
73
* required libraries are loaded by the runtime linker, using the
74
* $RPATH/$ORIGIN baked into the shared libraries at compile time. Therefore,
75
* in most cases, the launcher will only exec, if the data models are
76
* mismatched, and will not set any environment variables, regardless of the
77
* data models.
78
*
79
* However, if the environment contains a LD_LIBRARY_PATH, this will cause the
80
* launcher to inspect the LD_LIBRARY_PATH. The launcher will check
81
* a. if the LD_LIBRARY_PATH's first component is the path to the desired
82
* libjvm.so
83
* b. if any other libjvm.so is found in any of the paths.
84
* If case b is true, then the launcher will set the LD_LIBRARY_PATH to the
85
* desired JRE and reexec, in order to propagate the environment.
86
*
87
* Main
88
* (incoming argv)
89
* |
90
* \|/
91
* CreateExecutionEnvironment
92
* (determines desired data model)
93
* |
94
* |
95
* \|/
96
* Have Desired Model ? --> NO --> Exit(with error)
97
* |
98
* |
99
* \|/
100
* YES
101
* |
102
* |
103
* \|/
104
* CheckJvmType
105
* (removes -client, -server, etc.)
106
* |
107
* |
108
* \|/
109
* TranslateDashJArgs...
110
* (Prepare to pass args to vm)
111
* |
112
* |
113
* \|/
114
* ParseArguments
115
* |
116
* |
117
* \|/
118
* RequiresSetenv
119
* Is LD_LIBRARY_PATH
120
* and friends set ? --> NO --> Continue
121
* YES
122
* |
123
* |
124
* \|/
125
* Path is desired JRE ? YES --> Continue
126
* NO
127
* |
128
* |
129
* \|/
130
* Paths have well known
131
* jvm paths ? --> NO --> Error/Exit
132
* YES
133
* |
134
* |
135
* \|/
136
* Does libjvm.so exist
137
* in any of them ? --> NO --> Continue
138
* YES
139
* |
140
* |
141
* \|/
142
* Set the LD_LIBRARY_PATH
143
* |
144
* |
145
* \|/
146
* Re-exec
147
* |
148
* |
149
* \|/
150
* Main
151
*/
152
153
/* Store the name of the executable once computed */
154
static char *execname = NULL;
155
156
/*
157
* execname accessor from other parts of platform dependent logic
158
*/
159
const char *
160
GetExecName() {
161
return execname;
162
}
163
164
#ifdef SETENV_REQUIRED
165
static jboolean
166
JvmExists(const char *path) {
167
char tmp[PATH_MAX + 1];
168
struct stat statbuf;
169
JLI_Snprintf(tmp, PATH_MAX, "%s/%s", path, JVM_DLL);
170
if (stat(tmp, &statbuf) == 0) {
171
return JNI_TRUE;
172
}
173
return JNI_FALSE;
174
}
175
/*
176
* contains a lib/{server,client}/libjvm.so ?
177
*/
178
static jboolean
179
ContainsLibJVM(const char *env) {
180
/* the usual suspects */
181
char clientPattern[] = "lib/client";
182
char serverPattern[] = "lib/server";
183
char *envpath;
184
char *path;
185
char* save_ptr = NULL;
186
jboolean clientPatternFound;
187
jboolean serverPatternFound;
188
189
/* fastest path */
190
if (env == NULL) {
191
return JNI_FALSE;
192
}
193
194
/* to optimize for time, test if any of our usual suspects are present. */
195
clientPatternFound = JLI_StrStr(env, clientPattern) != NULL;
196
serverPatternFound = JLI_StrStr(env, serverPattern) != NULL;
197
if (clientPatternFound == JNI_FALSE && serverPatternFound == JNI_FALSE) {
198
return JNI_FALSE;
199
}
200
201
/*
202
* we have a suspicious path component, check if it contains a libjvm.so
203
*/
204
envpath = JLI_StringDup(env);
205
for (path = strtok_r(envpath, ":", &save_ptr); path != NULL; path = strtok_r(NULL, ":", &save_ptr)) {
206
if (clientPatternFound && JLI_StrStr(path, clientPattern) != NULL) {
207
if (JvmExists(path)) {
208
JLI_MemFree(envpath);
209
return JNI_TRUE;
210
}
211
}
212
if (serverPatternFound && JLI_StrStr(path, serverPattern) != NULL) {
213
if (JvmExists(path)) {
214
JLI_MemFree(envpath);
215
return JNI_TRUE;
216
}
217
}
218
}
219
JLI_MemFree(envpath);
220
return JNI_FALSE;
221
}
222
223
/*
224
* Test whether the environment variable needs to be set, see flowchart.
225
*/
226
static jboolean
227
RequiresSetenv(const char *jvmpath) {
228
char jpath[PATH_MAX + 1];
229
char *llp;
230
char *dmllp = NULL;
231
char *p; /* a utility pointer */
232
233
#ifdef MUSL_LIBC
234
/*
235
* The musl library loader requires LD_LIBRARY_PATH to be set in order
236
* to correctly resolve the dependency libjava.so has on libjvm.so.
237
*/
238
return JNI_TRUE;
239
#endif
240
241
#ifdef AIX
242
/* We always have to set the LIBPATH on AIX because ld doesn't support $ORIGIN. */
243
return JNI_TRUE;
244
#endif
245
246
llp = getenv("LD_LIBRARY_PATH");
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
294
void
295
CreateExecutionEnvironment(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
char *runpath = NULL; /* existing effective LD_LIBRARY_PATH setting */
307
char* new_runpath = NULL; /* desired new LD_LIBRARY_PATH string */
308
char* newpath = NULL; /* path on new LD_LIBRARY_PATH */
309
char* lastslash = NULL;
310
char** newenvp = NULL; /* current environment */
311
size_t new_runpath_size;
312
#endif /* SETENV_REQUIRED */
313
314
/* Compute/set the name of the executable */
315
SetExecname(*pargv);
316
317
/* Check to see if the jvmpath exists */
318
/* Find out where the JRE is that we will be using. */
319
if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE)) {
320
JLI_ReportErrorMessage(JRE_ERROR1);
321
exit(2);
322
}
323
JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%sjvm.cfg",
324
jrepath, FILESEP, FILESEP);
325
/* Find the specified JVM type */
326
if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {
327
JLI_ReportErrorMessage(CFG_ERROR7);
328
exit(1);
329
}
330
331
jvmpath[0] = '\0';
332
jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE);
333
if (JLI_StrCmp(jvmtype, "ERROR") == 0) {
334
JLI_ReportErrorMessage(CFG_ERROR9);
335
exit(4);
336
}
337
338
if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) {
339
JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
340
exit(4);
341
}
342
/*
343
* we seem to have everything we need, so without further ado
344
* we return back, otherwise proceed to set the environment.
345
*/
346
#ifdef SETENV_REQUIRED
347
mustsetenv = RequiresSetenv(jvmpath);
348
JLI_TraceLauncher("mustsetenv: %s\n", mustsetenv ? "TRUE" : "FALSE");
349
350
if (mustsetenv == JNI_FALSE) {
351
return;
352
}
353
#else
354
return;
355
#endif /* SETENV_REQUIRED */
356
357
#ifdef SETENV_REQUIRED
358
if (mustsetenv) {
359
/*
360
* We will set the LD_LIBRARY_PATH as follows:
361
*
362
* o $JVMPATH (directory portion only)
363
* o $JRE/lib
364
* o $JRE/../lib
365
*
366
* followed by the user's previous effective LD_LIBRARY_PATH, if
367
* any.
368
*/
369
370
runpath = getenv(LD_LIBRARY_PATH);
371
372
/* runpath contains current effective LD_LIBRARY_PATH setting */
373
{ /* New scope to declare local variable */
374
char *new_jvmpath = JLI_StringDup(jvmpath);
375
new_runpath_size = ((runpath != NULL) ? JLI_StrLen(runpath) : 0) +
376
2 * JLI_StrLen(jrepath) +
377
JLI_StrLen(new_jvmpath) + 52;
378
new_runpath = JLI_MemAlloc(new_runpath_size);
379
newpath = new_runpath + JLI_StrLen(LD_LIBRARY_PATH "=");
380
381
382
/*
383
* Create desired LD_LIBRARY_PATH value for target data model.
384
*/
385
{
386
/* remove the name of the .so from the JVM path */
387
lastslash = JLI_StrRChr(new_jvmpath, '/');
388
if (lastslash)
389
*lastslash = '\0';
390
391
sprintf(new_runpath, LD_LIBRARY_PATH "="
392
"%s:"
393
"%s/lib:"
394
"%s/../lib",
395
new_jvmpath,
396
jrepath,
397
jrepath
398
);
399
400
JLI_MemFree(new_jvmpath);
401
402
/*
403
* Check to make sure that the prefix of the current path is the
404
* desired environment variable setting, though the RequiresSetenv
405
* checks if the desired runpath exists, this logic does a more
406
* comprehensive check.
407
*/
408
if (runpath != NULL &&
409
JLI_StrNCmp(newpath, runpath, JLI_StrLen(newpath)) == 0 &&
410
(runpath[JLI_StrLen(newpath)] == 0 ||
411
runpath[JLI_StrLen(newpath)] == ':')) {
412
JLI_MemFree(new_runpath);
413
return;
414
}
415
}
416
}
417
418
/*
419
* Place the desired environment setting onto the prefix of
420
* LD_LIBRARY_PATH. Note that this prevents any possible infinite
421
* loop of execv() because we test for the prefix, above.
422
*/
423
if (runpath != 0) {
424
/* ensure storage for runpath + colon + NULL */
425
if ((JLI_StrLen(runpath) + 1 + 1) > new_runpath_size) {
426
JLI_ReportErrorMessageSys(JRE_ERROR11);
427
exit(1);
428
}
429
JLI_StrCat(new_runpath, ":");
430
JLI_StrCat(new_runpath, runpath);
431
}
432
433
if (putenv(new_runpath) != 0) {
434
/* problem allocating memory; LD_LIBRARY_PATH not set properly */
435
exit(1);
436
}
437
438
/*
439
* Unix systems document that they look at LD_LIBRARY_PATH only
440
* once at startup, so we have to re-exec the current executable
441
* to get the changed environment variable to have an effect.
442
*/
443
444
newenvp = environ;
445
}
446
#endif /* SETENV_REQUIRED */
447
{
448
char *newexec = execname;
449
JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n");
450
(void) fflush(stdout);
451
(void) fflush(stderr);
452
#ifdef SETENV_REQUIRED
453
if (mustsetenv) {
454
execve(newexec, argv, newenvp);
455
} else {
456
execv(newexec, argv);
457
}
458
#else /* !SETENV_REQUIRED */
459
execv(newexec, argv);
460
#endif /* SETENV_REQUIRED */
461
JLI_ReportErrorMessageSys(JRE_ERROR4, newexec);
462
}
463
exit(1);
464
}
465
466
467
static jboolean
468
GetJVMPath(const char *jrepath, const char *jvmtype,
469
char *jvmpath, jint jvmpathsize)
470
{
471
struct stat s;
472
473
if (JLI_StrChr(jvmtype, '/')) {
474
JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);
475
} else {
476
JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtype);
477
}
478
479
JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
480
481
if (stat(jvmpath, &s) == 0) {
482
JLI_TraceLauncher("yes.\n");
483
return JNI_TRUE;
484
} else {
485
JLI_TraceLauncher("no.\n");
486
return JNI_FALSE;
487
}
488
}
489
490
/*
491
* Find path to JRE based on .exe's location or registry settings.
492
*/
493
static jboolean
494
GetJREPath(char *path, jint pathsize, jboolean speculative)
495
{
496
char libjava[MAXPATHLEN];
497
struct stat s;
498
499
if (GetApplicationHome(path, pathsize)) {
500
/* Is JRE co-located with the application? */
501
JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
502
if (access(libjava, F_OK) == 0) {
503
JLI_TraceLauncher("JRE path is %s\n", path);
504
return JNI_TRUE;
505
}
506
/* ensure storage for path + /jre + NULL */
507
if ((JLI_StrLen(path) + 4 + 1) > (size_t) pathsize) {
508
JLI_TraceLauncher("Insufficient space to store JRE path\n");
509
return JNI_FALSE;
510
}
511
/* Does the app ship a private JRE in <apphome>/jre directory? */
512
JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);
513
if (access(libjava, F_OK) == 0) {
514
JLI_StrCat(path, "/jre");
515
JLI_TraceLauncher("JRE path is %s\n", path);
516
return JNI_TRUE;
517
}
518
}
519
520
if (GetApplicationHomeFromDll(path, pathsize)) {
521
JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
522
if (stat(libjava, &s) == 0) {
523
JLI_TraceLauncher("JRE path is %s\n", path);
524
return JNI_TRUE;
525
}
526
}
527
528
if (!speculative)
529
JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);
530
return JNI_FALSE;
531
}
532
533
jboolean
534
LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
535
{
536
void *libjvm;
537
538
JLI_TraceLauncher("JVM path is %s\n", jvmpath);
539
540
libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
541
if (libjvm == NULL) {
542
JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);
543
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
544
return JNI_FALSE;
545
}
546
547
ifn->CreateJavaVM = (CreateJavaVM_t)
548
dlsym(libjvm, "JNI_CreateJavaVM");
549
if (ifn->CreateJavaVM == NULL) {
550
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
551
return JNI_FALSE;
552
}
553
554
ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
555
dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
556
if (ifn->GetDefaultJavaVMInitArgs == NULL) {
557
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
558
return JNI_FALSE;
559
}
560
561
ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)
562
dlsym(libjvm, "JNI_GetCreatedJavaVMs");
563
if (ifn->GetCreatedJavaVMs == NULL) {
564
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
565
return JNI_FALSE;
566
}
567
568
return JNI_TRUE;
569
}
570
571
/*
572
* Compute the name of the executable
573
*
574
* In order to re-exec securely we need the absolute path of the
575
* executable. On Solaris getexecname(3c) may not return an absolute
576
* path so we use dladdr to get the filename of the executable and
577
* then use realpath to derive an absolute path. From Solaris 9
578
* onwards the filename returned in DL_info structure from dladdr is
579
* an absolute pathname so technically realpath isn't required.
580
* On Linux we read the executable name from /proc/self/exe.
581
* As a fallback, and for platforms other than Solaris and Linux,
582
* we use FindExecName to compute the executable name.
583
*/
584
const char*
585
SetExecname(char **argv)
586
{
587
char* exec_path = NULL;
588
#if defined(__ANDROID__) //Since both __ANDROID__ and __linux__ are defined, we must let the preprocessor preprocess the __ANDRIOD__ part first
589
char *__java_home = getenv("JAVA_HOME");
590
// From http://hg.openjdk.java.net/mobile/jdk9/jdk/file/17bb8a98d5e3/src/java.base/unix/native/libjli/java_md_solinux.c#l844
591
/* For Android, 'self' would point to /system/bin/app_process
592
* since we are really executing a Dalvik program at this point.
593
* argv[0] points to the Dalvik application name and we set the
594
* path to __java_home.
595
*/
596
char buf[PATH_MAX+1];
597
char *p = NULL;
598
if ((p = JLI_StrRChr(argv[0], '/')) != 0) {
599
/* may be running from command line */
600
p++;
601
if ((JLI_StrLen(p) == 4) && JLI_StrCmp(p, "java") == 0) {
602
/* started as 'java'. Must be command line */
603
JLI_TraceLauncher("SetExecName maybe command line = %s\n", argv[0]);
604
if (*argv[0] != '/') {
605
char *curdir = NULL;
606
/* get absolute path */
607
getcwd(buf, PATH_MAX);
608
curdir = JLI_StringDup(buf);
609
JLI_Snprintf(buf, PATH_MAX, "%s/%s", curdir, argv[0]);
610
JLI_MemFree(curdir);
611
} else {
612
JLI_Snprintf(buf, PATH_MAX, "%s", argv[0]);
613
}
614
} else {
615
/* Not command line, see if __java_home set */
616
if (__java_home != NULL) {
617
JLI_TraceLauncher("SetExecName not java = %s\n", __java_home);
618
JLI_Snprintf(buf, PATH_MAX, "%s/bin/java", __java_home);
619
} else {
620
/* Fake it as best we can or should we punt? */
621
JLI_TraceLauncher("SetExecName fake it = %s\n", argv[0]);
622
JLI_Snprintf(buf, PATH_MAX, "/data/data/%s/storage/jvm/bin/java",
623
argv[0]);
624
}
625
}
626
} else {
627
/* Not started as 'java', see if __java_home set */
628
if (__java_home != NULL) {
629
JLI_TraceLauncher("SetExecName not command line = %s\n", __java_home);
630
JLI_Snprintf(buf, PATH_MAX, "%s/bin/java", __java_home);
631
} else {
632
/* Fake it as best we can or should we punt? */
633
JLI_TraceLauncher("SetExecName fake it 2 = %s\n", argv[0]);
634
JLI_Snprintf(buf, PATH_MAX, "/data/data/%s/storage/jvm/bin/java",
635
argv[0]);
636
}
637
}
638
exec_path = JLI_StringDup(buf);
639
#elif defined(__linux__)
640
{
641
const char* self = "/proc/self/exe";
642
char buf[PATH_MAX+1];
643
int len = readlink(self, buf, PATH_MAX);
644
if (len >= 0) {
645
buf[len] = '\0'; /* readlink(2) doesn't NUL terminate */
646
exec_path = JLI_StringDup(buf);
647
}
648
}
649
#endif
650
651
if (exec_path == NULL) {
652
exec_path = FindExecName(argv[0]);
653
}
654
execname = exec_path;
655
return exec_path;
656
}
657
658
/* --- Splash Screen shared library support --- */
659
static const char* SPLASHSCREEN_SO = JNI_LIB_NAME("splashscreen");
660
static void* hSplashLib = NULL;
661
662
void* SplashProcAddress(const char* name) {
663
if (!hSplashLib) {
664
int ret;
665
char jrePath[MAXPATHLEN];
666
char splashPath[MAXPATHLEN];
667
668
if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) {
669
JLI_ReportErrorMessage(JRE_ERROR1);
670
return NULL;
671
}
672
ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s",
673
jrePath, SPLASHSCREEN_SO);
674
675
if (ret >= (int) sizeof(splashPath)) {
676
JLI_ReportErrorMessage(JRE_ERROR11);
677
return NULL;
678
}
679
if (ret < 0) {
680
JLI_ReportErrorMessage(JRE_ERROR13);
681
return NULL;
682
}
683
hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL);
684
JLI_TraceLauncher("Info: loaded %s\n", splashPath);
685
}
686
if (hSplashLib) {
687
void* sym = dlsym(hSplashLib, name);
688
return sym;
689
} else {
690
return NULL;
691
}
692
}
693
694
/*
695
* Signature adapter for pthread_create() or thr_create().
696
*/
697
static void* ThreadJavaMain(void* args) {
698
return (void*)(intptr_t)JavaMain(args);
699
}
700
701
/*
702
* Block current thread and continue execution in a new thread.
703
*/
704
int
705
CallJavaMainInNewThread(jlong stack_size, void* args) {
706
int rslt;
707
pthread_t tid;
708
pthread_attr_t attr;
709
pthread_attr_init(&attr);
710
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
711
712
if (stack_size > 0) {
713
pthread_attr_setstacksize(&attr, stack_size);
714
}
715
pthread_attr_setguardsize(&attr, 0); // no pthread guard page on java threads
716
717
if (pthread_create(&tid, &attr, ThreadJavaMain, args) == 0) {
718
void* tmp;
719
pthread_join(tid, &tmp);
720
rslt = (int)(intptr_t)tmp;
721
} else {
722
/*
723
* Continue execution in current thread if for some reason (e.g. out of
724
* memory/LWP) a new thread can't be created. This will likely fail
725
* later in JavaMain as JNI_CreateJavaVM needs to create quite a
726
* few new threads, anyway, just give it a try..
727
*/
728
rslt = JavaMain(args);
729
}
730
731
pthread_attr_destroy(&attr);
732
return rslt;
733
}
734
735
/* Coarse estimation of number of digits assuming the worst case is a 64-bit pid. */
736
#define MAX_PID_STR_SZ 20
737
738
int
739
JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
740
int argc, char **argv,
741
int mode, char *what, int ret)
742
{
743
ShowSplashScreen();
744
return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
745
}
746
747
void
748
PostJVMInit(JNIEnv *env, jclass mainClass, JavaVM *vm)
749
{
750
// stubbed out for windows and *nixes.
751
}
752
753
void
754
RegisterThread()
755
{
756
// stubbed out for windows and *nixes.
757
}
758
759
/*
760
* on unix, we return a false to indicate this option is not applicable
761
*/
762
jboolean
763
ProcessPlatformOption(const char *arg)
764
{
765
return JNI_FALSE;
766
}
767
768