File: | jdk/src/java.base/unix/native/libjli/java_md.c |
Warning: | line 301, column 9 Value stored to 'argc' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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" "libjvm.so" |
42 | #define JAVA_DLL"libjava.so" "libjava.so" |
43 | #ifdef AIX |
44 | #define LD_LIBRARY_PATH"LD_LIBRARY_PATH" "LIBPATH" |
45 | #else |
46 | #define LD_LIBRARY_PATH"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((void*)0); |
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_MAX4096 + 1]; |
168 | struct stat statbuf; |
169 | JLI_Snprintf(tmp, PATH_MAX, "%s/%s", path, JVM_DLL)__builtin___snprintf_chk (tmp, 4096, 2 - 1, __builtin_object_size (tmp, 2 > 1), "%s/%s", path, "libjvm.so"); |
170 | if (stat(tmp, &statbuf) == 0) { |
171 | return JNI_TRUE1; |
172 | } |
173 | return JNI_FALSE0; |
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((void*)0); |
186 | jboolean clientPatternFound; |
187 | jboolean serverPatternFound; |
188 | |
189 | /* fastest path */ |
190 | if (env == NULL((void*)0)) { |
191 | return JNI_FALSE0; |
192 | } |
193 | |
194 | /* to optimize for time, test if any of our usual suspects are present. */ |
195 | clientPatternFound = JLI_StrStr(env, clientPattern)strstr((env), (clientPattern)) != NULL((void*)0); |
196 | serverPatternFound = JLI_StrStr(env, serverPattern)strstr((env), (serverPattern)) != NULL((void*)0); |
197 | if (clientPatternFound == JNI_FALSE0 && serverPatternFound == JNI_FALSE0) { |
198 | return JNI_FALSE0; |
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((void*)0); path = strtok_r(NULL((void*)0), ":", &save_ptr)) { |
206 | if (clientPatternFound && JLI_StrStr(path, clientPattern)strstr((path), (clientPattern)) != NULL((void*)0)) { |
207 | if (JvmExists(path)) { |
208 | JLI_MemFree(envpath); |
209 | return JNI_TRUE1; |
210 | } |
211 | } |
212 | if (serverPatternFound && JLI_StrStr(path, serverPattern)strstr((path), (serverPattern)) != NULL((void*)0)) { |
213 | if (JvmExists(path)) { |
214 | JLI_MemFree(envpath); |
215 | return JNI_TRUE1; |
216 | } |
217 | } |
218 | } |
219 | JLI_MemFree(envpath); |
220 | return JNI_FALSE0; |
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_MAX4096 + 1]; |
229 | char *llp; |
230 | char *dmllp = NULL((void*)0); |
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_TRUE1; |
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_TRUE1; |
244 | #endif |
245 | |
246 | llp = getenv("LD_LIBRARY_PATH"); |
247 | /* no environment variable is a good environment variable */ |
248 | if (llp == NULL((void*)0) && dmllp == NULL((void*)0)) { |
249 | return JNI_FALSE0; |
250 | } |
251 | #ifdef __linux1 |
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_FALSE0; |
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)strncpy((jpath), (jvmpath), (4096)); |
277 | p = JLI_StrRChr(jpath, '/')strrchr((jpath), ('/')); |
278 | *p = '\0'; |
279 | if (llp != NULL((void*)0) && JLI_StrNCmp(llp, jpath, JLI_StrLen(jpath))strncmp((llp), (jpath), (strlen((jpath)))) == 0) { |
280 | return JNI_FALSE0; |
281 | } |
282 | |
283 | /* scrutinize all the paths further */ |
284 | if (llp != NULL((void*)0) && ContainsLibJVM(llp)) { |
285 | return JNI_TRUE1; |
286 | } |
287 | if (dmllp != NULL((void*)0) && ContainsLibJVM(dmllp)) { |
288 | return JNI_TRUE1; |
289 | } |
290 | return JNI_FALSE0; |
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((void*)0); |
301 | int argc = *pargc; |
Value stored to 'argc' during its initialization is never read | |
302 | char **argv = *pargv; |
303 | |
304 | #ifdef SETENV_REQUIRED |
305 | jboolean mustsetenv = JNI_FALSE0; |
306 | char *runpath = NULL((void*)0); /* existing effective LD_LIBRARY_PATH setting */ |
307 | char* new_runpath = NULL((void*)0); /* desired new LD_LIBRARY_PATH string */ |
308 | char* newpath = NULL((void*)0); /* path on new LD_LIBRARY_PATH */ |
309 | char* lastslash = NULL((void*)0); |
310 | char** newenvp = NULL((void*)0); /* 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_FALSE0)) { |
320 | JLI_ReportErrorMessage(JRE_ERROR1"Error: Could not find Java SE Runtime Environment."); |
321 | exit(2); |
322 | } |
323 | JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%sjvm.cfg",__builtin___snprintf_chk (jvmcfg, so_jvmcfg, 2 - 1, __builtin_object_size (jvmcfg, 2 > 1), "%s%slib%sjvm.cfg", jrepath, "/", "/") |
324 | jrepath, FILESEP, FILESEP)__builtin___snprintf_chk (jvmcfg, so_jvmcfg, 2 - 1, __builtin_object_size (jvmcfg, 2 > 1), "%s%slib%sjvm.cfg", jrepath, "/", "/"); |
325 | /* Find the specified JVM type */ |
326 | if (ReadKnownVMs(jvmcfg, JNI_FALSE0) < 1) { |
327 | JLI_ReportErrorMessage(CFG_ERROR7"Error: no known VMs. (check for corrupt jvm.cfg file)"); |
328 | exit(1); |
329 | } |
330 | |
331 | jvmpath[0] = '\0'; |
332 | jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE0); |
333 | if (JLI_StrCmp(jvmtype, "ERROR")strcmp((jvmtype), ("ERROR")) == 0) { |
334 | JLI_ReportErrorMessage(CFG_ERROR9"Error: could not determine JVM type."); |
335 | exit(4); |
336 | } |
337 | |
338 | if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) { |
339 | JLI_ReportErrorMessage(CFG_ERROR8"Error: missing `%s' JVM at `%s'.\nPlease install or use the JRE or JDK that contains these missing components.", 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_FALSE0) { |
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"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((void*)0)) ? JLI_StrLen(runpath)strlen((runpath)) : 0) + |
376 | 2 * JLI_StrLen(jrepath)strlen((jrepath)) + |
377 | JLI_StrLen(new_jvmpath)strlen((new_jvmpath)) + 52; |
378 | new_runpath = JLI_MemAlloc(new_runpath_size); |
379 | newpath = new_runpath + JLI_StrLen(LD_LIBRARY_PATH "=")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, '/')strrchr((new_jvmpath), ('/')); |
388 | if (lastslash) |
389 | *lastslash = '\0'; |
390 | |
391 | sprintf(new_runpath, LD_LIBRARY_PATH "="__builtin___sprintf_chk (new_runpath, 2 - 1, __builtin_object_size (new_runpath, 2 > 1), "LD_LIBRARY_PATH" "=" "%s:" "%s/lib:" "%s/../lib", new_jvmpath, jrepath, jrepath) |
392 | "%s:"__builtin___sprintf_chk (new_runpath, 2 - 1, __builtin_object_size (new_runpath, 2 > 1), "LD_LIBRARY_PATH" "=" "%s:" "%s/lib:" "%s/../lib", new_jvmpath, jrepath, jrepath) |
393 | "%s/lib:"__builtin___sprintf_chk (new_runpath, 2 - 1, __builtin_object_size (new_runpath, 2 > 1), "LD_LIBRARY_PATH" "=" "%s:" "%s/lib:" "%s/../lib", new_jvmpath, jrepath, jrepath) |
394 | "%s/../lib",__builtin___sprintf_chk (new_runpath, 2 - 1, __builtin_object_size (new_runpath, 2 > 1), "LD_LIBRARY_PATH" "=" "%s:" "%s/lib:" "%s/../lib", new_jvmpath, jrepath, jrepath) |
395 | new_jvmpath,__builtin___sprintf_chk (new_runpath, 2 - 1, __builtin_object_size (new_runpath, 2 > 1), "LD_LIBRARY_PATH" "=" "%s:" "%s/lib:" "%s/../lib", new_jvmpath, jrepath, jrepath) |
396 | jrepath,__builtin___sprintf_chk (new_runpath, 2 - 1, __builtin_object_size (new_runpath, 2 > 1), "LD_LIBRARY_PATH" "=" "%s:" "%s/lib:" "%s/../lib", new_jvmpath, jrepath, jrepath) |
397 | jrepath__builtin___sprintf_chk (new_runpath, 2 - 1, __builtin_object_size (new_runpath, 2 > 1), "LD_LIBRARY_PATH" "=" "%s:" "%s/lib:" "%s/../lib", new_jvmpath, jrepath, jrepath) |
398 | )__builtin___sprintf_chk (new_runpath, 2 - 1, __builtin_object_size (new_runpath, 2 > 1), "LD_LIBRARY_PATH" "=" "%s:" "%s/lib:" "%s/../lib", new_jvmpath, jrepath, jrepath); |
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((void*)0) && |
409 | JLI_StrNCmp(newpath, runpath, JLI_StrLen(newpath))strncmp((newpath), (runpath), (strlen((newpath)))) == 0 && |
410 | (runpath[JLI_StrLen(newpath)strlen((newpath))] == 0 || |
411 | runpath[JLI_StrLen(newpath)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)strlen((runpath)) + 1 + 1) > new_runpath_size) { |
426 | JLI_ReportErrorMessageSys(JRE_ERROR11"Error: Path length exceeds maximum length (PATH_MAX)"); |
427 | exit(1); |
428 | } |
429 | JLI_StrCat(new_runpath, ":")strcat((new_runpath), (":")); |
430 | JLI_StrCat(new_runpath, runpath)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(stdoutstdout); |
451 | (void) fflush(stderrstderr); |
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"Error: trying to exec %s.\nCheck if file exists and permissions are set correctly.", 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, '/')strchr((jvmtype), ('/'))) { |
474 | JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype)__builtin___snprintf_chk (jvmpath, jvmpathsize, 2 - 1, __builtin_object_size (jvmpath, 2 > 1), "%s/" "libjvm.so", jvmtype); |
475 | } else { |
476 | JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtype)__builtin___snprintf_chk (jvmpath, jvmpathsize, 2 - 1, __builtin_object_size (jvmpath, 2 > 1), "%s/lib/%s/" "libjvm.so", 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_TRUE1; |
484 | } else { |
485 | JLI_TraceLauncher("no.\n"); |
486 | return JNI_FALSE0; |
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[MAXPATHLEN4096]; |
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)__builtin___snprintf_chk (libjava, sizeof(libjava), 2 - 1, __builtin_object_size (libjava, 2 > 1), "%s/lib/" "libjava.so", path); |
502 | if (access(libjava, F_OK0) == 0) { |
503 | JLI_TraceLauncher("JRE path is %s\n", path); |
504 | return JNI_TRUE1; |
505 | } |
506 | /* ensure storage for path + /jre + NULL */ |
507 | if ((JLI_StrLen(path)strlen((path)) + 4 + 1) > (size_t) pathsize) { |
508 | JLI_TraceLauncher("Insufficient space to store JRE path\n"); |
509 | return JNI_FALSE0; |
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)__builtin___snprintf_chk (libjava, sizeof(libjava), 2 - 1, __builtin_object_size (libjava, 2 > 1), "%s/jre/lib/" "libjava.so", path); |
513 | if (access(libjava, F_OK0) == 0) { |
514 | JLI_StrCat(path, "/jre")strcat((path), ("/jre")); |
515 | JLI_TraceLauncher("JRE path is %s\n", path); |
516 | return JNI_TRUE1; |
517 | } |
518 | } |
519 | |
520 | if (GetApplicationHomeFromDll(path, pathsize)) { |
521 | JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path)__builtin___snprintf_chk (libjava, sizeof(libjava), 2 - 1, __builtin_object_size (libjava, 2 > 1), "%s/lib/" "libjava.so", path); |
522 | if (stat(libjava, &s) == 0) { |
523 | JLI_TraceLauncher("JRE path is %s\n", path); |
524 | return JNI_TRUE1; |
525 | } |
526 | } |
527 | |
528 | if (!speculative) |
529 | JLI_ReportErrorMessage(JRE_ERROR8"Error: could not find " JAVA_DLL"libjava.so"); |
530 | return JNI_FALSE0; |
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_NOW0x00002 + RTLD_GLOBAL0x00100); |
541 | if (libjvm == NULL((void*)0)) { |
542 | JLI_ReportErrorMessage(DLL_ERROR1"Error: dl failure on line %d", __LINE__542); |
543 | JLI_ReportErrorMessage(DLL_ERROR2"Error: failed %s, because %s", jvmpath, dlerror()); |
544 | return JNI_FALSE0; |
545 | } |
546 | |
547 | ifn->CreateJavaVM = (CreateJavaVM_t) |
548 | dlsym(libjvm, "JNI_CreateJavaVM"); |
549 | if (ifn->CreateJavaVM == NULL((void*)0)) { |
550 | JLI_ReportErrorMessage(DLL_ERROR2"Error: failed %s, because %s", jvmpath, dlerror()); |
551 | return JNI_FALSE0; |
552 | } |
553 | |
554 | ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t) |
555 | dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs"); |
556 | if (ifn->GetDefaultJavaVMInitArgs == NULL((void*)0)) { |
557 | JLI_ReportErrorMessage(DLL_ERROR2"Error: failed %s, because %s", jvmpath, dlerror()); |
558 | return JNI_FALSE0; |
559 | } |
560 | |
561 | ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t) |
562 | dlsym(libjvm, "JNI_GetCreatedJavaVMs"); |
563 | if (ifn->GetCreatedJavaVMs == NULL((void*)0)) { |
564 | JLI_ReportErrorMessage(DLL_ERROR2"Error: failed %s, because %s", jvmpath, dlerror()); |
565 | return JNI_FALSE0; |
566 | } |
567 | |
568 | return JNI_TRUE1; |
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((void*)0); |
588 | #if defined(__linux__1) |
589 | { |
590 | const char* self = "/proc/self/exe"; |
591 | char buf[PATH_MAX4096+1]; |
592 | int len = readlink(self, buf, PATH_MAX4096); |
593 | if (len >= 0) { |
594 | buf[len] = '\0'; /* readlink(2) doesn't NUL terminate */ |
595 | exec_path = JLI_StringDup(buf); |
596 | } |
597 | } |
598 | #else /* !__linux__ */ |
599 | { |
600 | /* Not implemented */ |
601 | } |
602 | #endif |
603 | |
604 | if (exec_path == NULL((void*)0)) { |
605 | exec_path = FindExecName(argv[0]); |
606 | } |
607 | execname = exec_path; |
608 | return exec_path; |
609 | } |
610 | |
611 | /* --- Splash Screen shared library support --- */ |
612 | static const char* SPLASHSCREEN_SO = JNI_LIB_NAME("splashscreen")"lib" "splashscreen" ".so"; |
613 | static void* hSplashLib = NULL((void*)0); |
614 | |
615 | void* SplashProcAddress(const char* name) { |
616 | if (!hSplashLib) { |
617 | int ret; |
618 | char jrePath[MAXPATHLEN4096]; |
619 | char splashPath[MAXPATHLEN4096]; |
620 | |
621 | if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE0)) { |
622 | JLI_ReportErrorMessage(JRE_ERROR1"Error: Could not find Java SE Runtime Environment."); |
623 | return NULL((void*)0); |
624 | } |
625 | ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s",__builtin___snprintf_chk (splashPath, sizeof(splashPath), 2 - 1, __builtin_object_size (splashPath, 2 > 1), "%s/lib/%s" , jrePath, SPLASHSCREEN_SO) |
626 | jrePath, SPLASHSCREEN_SO)__builtin___snprintf_chk (splashPath, sizeof(splashPath), 2 - 1, __builtin_object_size (splashPath, 2 > 1), "%s/lib/%s" , jrePath, SPLASHSCREEN_SO); |
627 | |
628 | if (ret >= (int) sizeof(splashPath)) { |
629 | JLI_ReportErrorMessage(JRE_ERROR11"Error: Path length exceeds maximum length (PATH_MAX)"); |
630 | return NULL((void*)0); |
631 | } |
632 | if (ret < 0) { |
633 | JLI_ReportErrorMessage(JRE_ERROR13"Error: String processing operation failed"); |
634 | return NULL((void*)0); |
635 | } |
636 | hSplashLib = dlopen(splashPath, RTLD_LAZY0x00001 | RTLD_GLOBAL0x00100); |
637 | JLI_TraceLauncher("Info: loaded %s\n", splashPath); |
638 | } |
639 | if (hSplashLib) { |
640 | void* sym = dlsym(hSplashLib, name); |
641 | return sym; |
642 | } else { |
643 | return NULL((void*)0); |
644 | } |
645 | } |
646 | |
647 | /* |
648 | * Signature adapter for pthread_create() or thr_create(). |
649 | */ |
650 | static void* ThreadJavaMain(void* args) { |
651 | return (void*)(intptr_t)JavaMain(args); |
652 | } |
653 | |
654 | /* |
655 | * Block current thread and continue execution in a new thread. |
656 | */ |
657 | int |
658 | CallJavaMainInNewThread(jlong stack_size, void* args) { |
659 | int rslt; |
660 | pthread_t tid; |
661 | pthread_attr_t attr; |
662 | pthread_attr_init(&attr); |
663 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLEPTHREAD_CREATE_JOINABLE); |
664 | |
665 | if (stack_size > 0) { |
666 | pthread_attr_setstacksize(&attr, stack_size); |
667 | } |
668 | pthread_attr_setguardsize(&attr, 0); // no pthread guard page on java threads |
669 | |
670 | if (pthread_create(&tid, &attr, ThreadJavaMain, args) == 0) { |
671 | void* tmp; |
672 | pthread_join(tid, &tmp); |
673 | rslt = (int)(intptr_t)tmp; |
674 | } else { |
675 | /* |
676 | * Continue execution in current thread if for some reason (e.g. out of |
677 | * memory/LWP) a new thread can't be created. This will likely fail |
678 | * later in JavaMain as JNI_CreateJavaVM needs to create quite a |
679 | * few new threads, anyway, just give it a try.. |
680 | */ |
681 | rslt = JavaMain(args); |
682 | } |
683 | |
684 | pthread_attr_destroy(&attr); |
685 | return rslt; |
686 | } |
687 | |
688 | /* Coarse estimation of number of digits assuming the worst case is a 64-bit pid. */ |
689 | #define MAX_PID_STR_SZ20 20 |
690 | |
691 | int |
692 | JVMInit(InvocationFunctions* ifn, jlong threadStackSize, |
693 | int argc, char **argv, |
694 | int mode, char *what, int ret) |
695 | { |
696 | ShowSplashScreen(); |
697 | return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret); |
698 | } |
699 | |
700 | void |
701 | PostJVMInit(JNIEnv *env, jclass mainClass, JavaVM *vm) |
702 | { |
703 | // stubbed out for windows and *nixes. |
704 | } |
705 | |
706 | void |
707 | RegisterThread() |
708 | { |
709 | // stubbed out for windows and *nixes. |
710 | } |
711 | |
712 | /* |
713 | * on unix, we return a false to indicate this option is not applicable |
714 | */ |
715 | jboolean |
716 | ProcessPlatformOption(const char *arg) |
717 | { |
718 | return JNI_FALSE0; |
719 | } |