228 #endif
229 }
230
231 char jvmPath[PATH_MAX];
232 jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), GetArch(), CURRENT_DATA_MODEL);
233 if (!gotJVMPath) {
234 JLI_ReportErrorMessage("Failed to GetJVMPath()");
235 return NULL;
236 }
237
238 InvocationFunctions *fxns = malloc(sizeof(InvocationFunctions));
239 jboolean vmLoaded = LoadJavaVM(jvmPath, fxns);
240 if (!vmLoaded) {
241 JLI_ReportErrorMessage("Failed to LoadJavaVM()");
242 return NULL;
243 }
244
245 return sExportedJNIFunctions = fxns;
246 }
247
248 JNIEXPORT jint JNICALL
249 JNI_GetDefaultJavaVMInitArgs(void *args) {
250 InvocationFunctions *ifn = GetExportedJNIFunctions();
251 if (ifn == NULL) return JNI_ERR;
252 return ifn->GetDefaultJavaVMInitArgs(args);
253 }
254
255 JNIEXPORT jint JNICALL
256 JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args) {
257 InvocationFunctions *ifn = GetExportedJNIFunctions();
258 if (ifn == NULL) return JNI_ERR;
259 return ifn->CreateJavaVM(pvm, penv, args);
260 }
261
262 JNIEXPORT jint JNICALL
263 JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs) {
264 InvocationFunctions *ifn = GetExportedJNIFunctions();
265 if (ifn == NULL) return JNI_ERR;
266 return ifn->GetCreatedJavaVMs(vmBuf, bufLen, nVMs);
267 }
268
269 /*
270 * Allow JLI-aware launchers to specify a client/server preference
271 */
272 JNIEXPORT void JNICALL
273 JLI_SetPreferredJVM(const char *prefJVM) {
274 if (sPreferredJVMType != NULL) {
275 free(sPreferredJVMType);
276 sPreferredJVMType = NULL;
277 }
278
279 if (prefJVM == NULL) return;
280 sPreferredJVMType = strdup(prefJVM);
281 }
282
283 static BOOL awtLoaded = NO;
284 static pthread_mutex_t awtLoaded_mutex = PTHREAD_MUTEX_INITIALIZER;
285 static pthread_cond_t awtLoaded_cv = PTHREAD_COND_INITIALIZER;
286
287 JNIEXPORT void JNICALL
288 JLI_NotifyAWTLoaded()
289 {
290 pthread_mutex_lock(&awtLoaded_mutex);
291 awtLoaded = YES;
292 pthread_cond_signal(&awtLoaded_cv);
293 pthread_mutex_unlock(&awtLoaded_mutex);
294 }
295
296 static int (*main_fptr)(int argc, char **argv) = NULL;
297
298 /*
299 * Unwrap the arguments and re-run main()
300 */
301 static void *apple_main (void *arg)
302 {
303 objc_registerThreadWithCollector();
304
305 if (main_fptr == NULL) {
306 main_fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
307 if (main_fptr == NULL) {
308 JLI_ReportErrorMessageSys("error locating main entrypoint\n");
309 exit(1);
310 }
311 }
312
313 struct NSAppArgs *args = (struct NSAppArgs *) arg;
314 exit(main_fptr(args->argc, args->argv));
315 }
316
317 static void dummyTimer(CFRunLoopTimerRef timer, void *info) {}
318
319 static void ParkEventLoop() {
320 // RunLoop needs at least one source, and 1e20 is pretty far into the future
321 CFRunLoopTimerRef t = CFRunLoopTimerCreate(kCFAllocatorDefault, 1.0e20, 0.0, 0, 0, dummyTimer, NULL);
322 CFRunLoopAddTimer(CFRunLoopGetCurrent(), t, kCFRunLoopDefaultMode);
323 CFRelease(t);
324
325 // Park this thread in the main run loop.
326 int32_t result;
571 */
572 static jboolean
573 GetJVMPath(const char *jrepath, const char *jvmtype,
574 char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)
575 {
576 struct stat s;
577
578 if (JLI_StrChr(jvmtype, '/')) {
579 JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);
580 } else {
581 /*
582 * macosx client library is built thin, i386 only.
583 * 64 bit client requests must load server library
584 */
585 const char *jvmtypeUsed = ((bitsWanted == 64) && (strcmp(jvmtype, "client") == 0)) ? "server" : jvmtype;
586 JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtypeUsed);
587 }
588
589 JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
590
591 if (stat(jvmpath, &s) == 0) {
592 JLI_TraceLauncher("yes.\n");
593 return JNI_TRUE;
594 } else {
595 JLI_TraceLauncher("no.\n");
596 return JNI_FALSE;
597 }
598 }
599
600 /*
601 * Find path to JRE based on .exe's location or registry settings.
602 */
603 static jboolean
604 GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)
605 {
606 char libjava[MAXPATHLEN];
607
608 if (GetApplicationHome(path, pathsize)) {
609 /* Is JRE co-located with the application? */
610 JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
611 if (access(libjava, F_OK) == 0) {
612 return JNI_TRUE;
613 }
614 /* ensure storage for path + /jre + NULL */
615 if ((JLI_StrLen(path) + 4 + 1) > (size_t) pathsize) {
616 JLI_TraceLauncher("Insufficient space to store JRE path\n");
617 return JNI_FALSE;
618 }
619 /* Does the app ship a private JRE in <apphome>/jre directory? */
620 JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);
621 if (access(libjava, F_OK) == 0) {
622 JLI_StrCat(path, "/jre");
623 JLI_TraceLauncher("JRE path is %s\n", path);
624 return JNI_TRUE;
625 }
626 }
627
628 /* try to find ourselves instead */
629 Dl_info selfInfo;
630 dladdr(&GetJREPath, &selfInfo);
631
632 char *realPathToSelf = realpath(selfInfo.dli_fname, path);
633 if (realPathToSelf != path) {
634 return JNI_FALSE;
635 }
636
637 size_t pathLen = strlen(realPathToSelf);
638 if (pathLen == 0) {
639 return JNI_FALSE;
640 }
641
642 const char lastPathComponent[] = "/lib/jli/libjli.dylib";
643 size_t sizeOfLastPathComponent = sizeof(lastPathComponent) - 1;
644 if (pathLen < sizeOfLastPathComponent) {
645 return JNI_FALSE;
646 }
647
648 size_t indexOfLastPathComponent = pathLen - sizeOfLastPathComponent;
649 if (0 == strncmp(realPathToSelf + indexOfLastPathComponent, lastPathComponent, sizeOfLastPathComponent - 1)) {
650 realPathToSelf[indexOfLastPathComponent + 1] = '\0';
651 return JNI_TRUE;
652 }
653
654 if (!speculative)
655 JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);
656 return JNI_FALSE;
657 }
658
659 jboolean
660 LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
661 {
662 Dl_info dlinfo;
663 void *libjvm;
664
665 JLI_TraceLauncher("JVM path is %s\n", jvmpath);
666
667 libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
668 if (libjvm == NULL) {
669 JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);
670 JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
671 return JNI_FALSE;
672 }
673
674 ifn->CreateJavaVM = (CreateJavaVM_t)
675 dlsym(libjvm, "JNI_CreateJavaVM");
676 if (ifn->CreateJavaVM == NULL) {
677 JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
678 return JNI_FALSE;
679 }
680
681 ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
682 dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
683 if (ifn->GetDefaultJavaVMInitArgs == NULL) {
684 JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
685 return JNI_FALSE;
686 }
687
697
698 /*
699 * Compute the name of the executable
700 *
701 * In order to re-exec securely we need the absolute path of the
702 * executable. On Solaris getexecname(3c) may not return an absolute
703 * path so we use dladdr to get the filename of the executable and
704 * then use realpath to derive an absolute path. From Solaris 9
705 * onwards the filename returned in DL_info structure from dladdr is
706 * an absolute pathname so technically realpath isn't required.
707 * On Linux we read the executable name from /proc/self/exe.
708 * As a fallback, and for platforms other than Solaris and Linux,
709 * we use FindExecName to compute the executable name.
710 */
711 const char*
712 SetExecname(char **argv)
713 {
714 char* exec_path = NULL;
715 {
716 Dl_info dlinfo;
717 int (*fptr)();
718
719 fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
720 if (fptr == NULL) {
721 JLI_ReportErrorMessage(DLL_ERROR3, dlerror());
722 return JNI_FALSE;
723 }
724
725 if (dladdr((void*)fptr, &dlinfo)) {
726 char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1);
727 if (resolved != NULL) {
728 exec_path = realpath(dlinfo.dli_fname, resolved);
729 if (exec_path == NULL) {
730 JLI_MemFree(resolved);
731 }
732 }
733 }
734 }
735 if (exec_path == NULL) {
736 exec_path = FindExecName(argv[0]);
737 }
738 execname = exec_path;
739 return exec_path;
|
228 #endif
229 }
230
231 char jvmPath[PATH_MAX];
232 jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), GetArch(), CURRENT_DATA_MODEL);
233 if (!gotJVMPath) {
234 JLI_ReportErrorMessage("Failed to GetJVMPath()");
235 return NULL;
236 }
237
238 InvocationFunctions *fxns = malloc(sizeof(InvocationFunctions));
239 jboolean vmLoaded = LoadJavaVM(jvmPath, fxns);
240 if (!vmLoaded) {
241 JLI_ReportErrorMessage("Failed to LoadJavaVM()");
242 return NULL;
243 }
244
245 return sExportedJNIFunctions = fxns;
246 }
247
248 #ifndef STATIC_BUILD
249
250 JNIEXPORT jint JNICALL
251 JNI_GetDefaultJavaVMInitArgs(void *args) {
252 InvocationFunctions *ifn = GetExportedJNIFunctions();
253 if (ifn == NULL) return JNI_ERR;
254 return ifn->GetDefaultJavaVMInitArgs(args);
255 }
256
257 JNIEXPORT jint JNICALL
258 JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args) {
259 InvocationFunctions *ifn = GetExportedJNIFunctions();
260 if (ifn == NULL) return JNI_ERR;
261 return ifn->CreateJavaVM(pvm, penv, args);
262 }
263
264 JNIEXPORT jint JNICALL
265 JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs) {
266 InvocationFunctions *ifn = GetExportedJNIFunctions();
267 if (ifn == NULL) return JNI_ERR;
268 return ifn->GetCreatedJavaVMs(vmBuf, bufLen, nVMs);
269 }
270 #endif
271
272 /*
273 * Allow JLI-aware launchers to specify a client/server preference
274 */
275 JNIEXPORT void JNICALL
276 JLI_SetPreferredJVM(const char *prefJVM) {
277 if (sPreferredJVMType != NULL) {
278 free(sPreferredJVMType);
279 sPreferredJVMType = NULL;
280 }
281
282 if (prefJVM == NULL) return;
283 sPreferredJVMType = strdup(prefJVM);
284 }
285
286 static BOOL awtLoaded = NO;
287 static pthread_mutex_t awtLoaded_mutex = PTHREAD_MUTEX_INITIALIZER;
288 static pthread_cond_t awtLoaded_cv = PTHREAD_COND_INITIALIZER;
289
290 JNIEXPORT void JNICALL
291 JLI_NotifyAWTLoaded()
292 {
293 pthread_mutex_lock(&awtLoaded_mutex);
294 awtLoaded = YES;
295 pthread_cond_signal(&awtLoaded_cv);
296 pthread_mutex_unlock(&awtLoaded_mutex);
297 }
298
299 static int (*main_fptr)(int argc, char **argv) = NULL;
300
301 /*
302 * Unwrap the arguments and re-run main()
303 */
304 static void *apple_main (void *arg)
305 {
306 objc_registerThreadWithCollector();
307
308 if (main_fptr == NULL) {
309 #ifdef STATIC_BUILD
310 extern int main(int argc, char **argv);
311 main_fptr = &main;
312 #else
313 main_fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
314 #endif
315 if (main_fptr == NULL) {
316 JLI_ReportErrorMessageSys("error locating main entrypoint\n");
317 exit(1);
318 }
319 }
320
321 struct NSAppArgs *args = (struct NSAppArgs *) arg;
322 exit(main_fptr(args->argc, args->argv));
323 }
324
325 static void dummyTimer(CFRunLoopTimerRef timer, void *info) {}
326
327 static void ParkEventLoop() {
328 // RunLoop needs at least one source, and 1e20 is pretty far into the future
329 CFRunLoopTimerRef t = CFRunLoopTimerCreate(kCFAllocatorDefault, 1.0e20, 0.0, 0, 0, dummyTimer, NULL);
330 CFRunLoopAddTimer(CFRunLoopGetCurrent(), t, kCFRunLoopDefaultMode);
331 CFRelease(t);
332
333 // Park this thread in the main run loop.
334 int32_t result;
579 */
580 static jboolean
581 GetJVMPath(const char *jrepath, const char *jvmtype,
582 char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)
583 {
584 struct stat s;
585
586 if (JLI_StrChr(jvmtype, '/')) {
587 JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);
588 } else {
589 /*
590 * macosx client library is built thin, i386 only.
591 * 64 bit client requests must load server library
592 */
593 const char *jvmtypeUsed = ((bitsWanted == 64) && (strcmp(jvmtype, "client") == 0)) ? "server" : jvmtype;
594 JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtypeUsed);
595 }
596
597 JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
598
599 #ifdef STATIC_BUILD
600 return JNI_TRUE;
601 #else
602 if (stat(jvmpath, &s) == 0) {
603 JLI_TraceLauncher("yes.\n");
604 return JNI_TRUE;
605 } else {
606 JLI_TraceLauncher("no.\n");
607 return JNI_FALSE;
608 }
609 #endif
610 }
611
612 /*
613 * Find path to JRE based on .exe's location or registry settings.
614 */
615 static jboolean
616 GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)
617 {
618 char libjava[MAXPATHLEN];
619
620 if (GetApplicationHome(path, pathsize)) {
621 /* Is JRE co-located with the application? */
622 #ifdef STATIC_BUILD
623 char jvm_cfg[MAXPATHLEN];
624 JLI_Snprintf(jvm_cfg, sizeof(jvm_cfg), "%s/lib/jvm.cfg", path);
625 if (access(jvm_cfg, F_OK) == 0) {
626 return JNI_TRUE;
627 }
628 #else
629 JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
630 if (access(libjava, F_OK) == 0) {
631 return JNI_TRUE;
632 }
633 #endif
634 /* ensure storage for path + /jre + NULL */
635 if ((JLI_StrLen(path) + 4 + 1) > (size_t) pathsize) {
636 JLI_TraceLauncher("Insufficient space to store JRE path\n");
637 return JNI_FALSE;
638 }
639 /* Does the app ship a private JRE in <apphome>/jre directory? */
640 JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);
641 if (access(libjava, F_OK) == 0) {
642 JLI_StrCat(path, "/jre");
643 JLI_TraceLauncher("JRE path is %s\n", path);
644 return JNI_TRUE;
645 }
646 }
647
648 /* try to find ourselves instead */
649 Dl_info selfInfo;
650 dladdr(&GetJREPath, &selfInfo);
651
652 #ifdef STATIC_BUILD
653 char jvm_cfg[MAXPATHLEN];
654 char *p = NULL;
655 strncpy(jvm_cfg, selfInfo.dli_fname, MAXPATHLEN);
656 p = strrchr(jvm_cfg, '/'); *p = '\0';
657 p = strrchr(jvm_cfg, '/');
658 if (strcmp(p, "/.") == 0) {
659 *p = '\0';
660 p = strrchr(jvm_cfg, '/'); *p = '\0';
661 }
662 else *p = '\0';
663 strncpy(path, jvm_cfg, pathsize);
664 strncat(jvm_cfg, "/lib/jvm.cfg", MAXPATHLEN);
665 if (access(jvm_cfg, F_OK) == 0) {
666 return JNI_TRUE;
667 }
668 #endif
669
670 char *realPathToSelf = realpath(selfInfo.dli_fname, path);
671 if (realPathToSelf != path) {
672 return JNI_FALSE;
673 }
674
675 size_t pathLen = strlen(realPathToSelf);
676 if (pathLen == 0) {
677 return JNI_FALSE;
678 }
679
680 const char lastPathComponent[] = "/lib/jli/libjli.dylib";
681 size_t sizeOfLastPathComponent = sizeof(lastPathComponent) - 1;
682 if (pathLen < sizeOfLastPathComponent) {
683 return JNI_FALSE;
684 }
685
686 size_t indexOfLastPathComponent = pathLen - sizeOfLastPathComponent;
687 if (0 == strncmp(realPathToSelf + indexOfLastPathComponent, lastPathComponent, sizeOfLastPathComponent - 1)) {
688 realPathToSelf[indexOfLastPathComponent + 1] = '\0';
689 return JNI_TRUE;
690 }
691
692 if (!speculative)
693 JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);
694 return JNI_FALSE;
695 }
696
697 jboolean
698 LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
699 {
700 Dl_info dlinfo;
701 void *libjvm;
702
703 JLI_TraceLauncher("JVM path is %s\n", jvmpath);
704
705 #ifndef STATIC_BUILD
706 libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
707 #else
708 libjvm = dlopen(NULL, RTLD_FIRST);
709 #endif
710 if (libjvm == NULL) {
711 JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);
712 JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
713 return JNI_FALSE;
714 }
715
716 ifn->CreateJavaVM = (CreateJavaVM_t)
717 dlsym(libjvm, "JNI_CreateJavaVM");
718 if (ifn->CreateJavaVM == NULL) {
719 JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
720 return JNI_FALSE;
721 }
722
723 ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
724 dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
725 if (ifn->GetDefaultJavaVMInitArgs == NULL) {
726 JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
727 return JNI_FALSE;
728 }
729
739
740 /*
741 * Compute the name of the executable
742 *
743 * In order to re-exec securely we need the absolute path of the
744 * executable. On Solaris getexecname(3c) may not return an absolute
745 * path so we use dladdr to get the filename of the executable and
746 * then use realpath to derive an absolute path. From Solaris 9
747 * onwards the filename returned in DL_info structure from dladdr is
748 * an absolute pathname so technically realpath isn't required.
749 * On Linux we read the executable name from /proc/self/exe.
750 * As a fallback, and for platforms other than Solaris and Linux,
751 * we use FindExecName to compute the executable name.
752 */
753 const char*
754 SetExecname(char **argv)
755 {
756 char* exec_path = NULL;
757 {
758 Dl_info dlinfo;
759
760 #ifdef STATIC_BUILD
761 void *fptr;
762 fptr = (void *)&SetExecname;
763 #else
764 int (*fptr)();
765 fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
766 #endif
767 if (fptr == NULL) {
768 JLI_ReportErrorMessage(DLL_ERROR3, dlerror());
769 return JNI_FALSE;
770 }
771
772 if (dladdr((void*)fptr, &dlinfo)) {
773 char *resolved = (char*)JLI_MemAlloc(PATH_MAX+1);
774 if (resolved != NULL) {
775 exec_path = realpath(dlinfo.dli_fname, resolved);
776 if (exec_path == NULL) {
777 JLI_MemFree(resolved);
778 }
779 }
780 }
781 }
782 if (exec_path == NULL) {
783 exec_path = FindExecName(argv[0]);
784 }
785 execname = exec_path;
786 return exec_path;
|