1 /* 2 * Copyright (c) 2010, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 /* 26 * Gamma (Hotspot internal engineering test) launcher based on 6.0u22-b01 JDK, 27 * search "GAMMA" for gamma specific changes. 28 * 29 * GAMMA: gamma launcher is much simpler than regular java launcher in that 30 * JVM is either statically linked in or it is installed in the 31 * same directory where the launcher exists, so we don't have to 32 * worry about choosing the right JVM based on command line flag, jar 33 * file and/or ergonomics. Intead of removing unused logic from source 34 * they are commented out with #ifndef GAMMA, hopefully it'll be easier 35 * to maintain this file in sync with regular JDK launcher. 36 */ 37 38 /* 39 * Shared source for 'java' command line tool. 40 * 41 * If JAVA_ARGS is defined, then it acts as a launcher for applications. For 42 * instance, the JDK command line tools such as javac and javadoc (see 43 * makefiles for more details) are built with this program. Any arguments 44 * prefixed with '-J' will be passed directly to the 'java' command. 45 */ 46 47 #ifdef GAMMA 48 # ifdef JAVA_ARGS 49 # error Do NOT define JAVA_ARGS when building gamma launcher 50 # endif 51 #endif 52 53 /* 54 * One job of the launcher is to remove command line options which the 55 * vm does not understand and will not process. These options include 56 * options which select which style of vm is run (e.g. -client and 57 * -server) as well as options which select the data model to use. 58 * Additionally, for tools which invoke an underlying vm "-J-foo" 59 * options are turned into "-foo" options to the vm. This option 60 * filtering is handled in a number of places in the launcher, some of 61 * it in machine-dependent code. In this file, the function 62 * CheckJVMType removes vm style options and TranslateApplicationArgs 63 * removes "-J" prefixes. On unix platforms, the 64 * CreateExecutionEnvironment function from the unix java_md.c file 65 * processes and removes -d<n> options. However, in case 66 * CreateExecutionEnvironment does not need to exec because 67 * LD_LIBRARY_PATH is set acceptably and the data model does not need 68 * to be changed, ParseArguments will screen out the redundant -d<n> 69 * options and prevent them from being passed to the vm; this is done 70 * by using the machine-dependent call 71 * RemovableMachineDependentOption. 72 */ 73 74 #include <stdio.h> 75 #include <stdlib.h> 76 #include <string.h> 77 78 #include <jni.h> 79 #include <jvm.h> 80 #include "java.h" 81 82 #ifndef GAMMA 83 #include "manifest_info.h" 84 #include "version_comp.h" 85 #include "wildcard.h" 86 #include "splashscreen.h" 87 #endif 88 89 #ifndef FULL_VERSION 90 #define FULL_VERSION JDK_MAJOR_VERSION "." JDK_MINOR_VERSION 91 #endif 92 93 /* 94 * The following environment variable is used to influence the behavior 95 * of the jre exec'd through the SelectVersion routine. The command line 96 * options which specify the version are not passed to the exec'd version, 97 * because that jre may be an older version which wouldn't recognize them. 98 * This environment variable is known to this (and later) version and serves 99 * to suppress the version selection code. This is not only for efficiency, 100 * but also for correctness, since any command line options have been 101 * removed which would cause any value found in the manifest to be used. 102 * This would be incorrect because the command line options are defined 103 * to take precedence. 104 * 105 * The value associated with this environment variable is the MainClass 106 * name from within the executable jar file (if any). This is strictly a 107 * performance enhancement to avoid re-reading the jar file manifest. 108 * 109 * A NOTE TO DEVELOPERS: For performance reasons it is important that 110 * the program image remain relatively small until after SelectVersion 111 * CreateExecutionEnvironment have finished their possibly recursive 112 * processing. Watch everything, but resist all temptations to use Java 113 * interfaces. 114 */ 115 #define ENV_ENTRY "_JAVA_VERSION_SET" 116 117 #ifndef GAMMA 118 #define SPLASH_FILE_ENV_ENTRY "_JAVA_SPLASH_FILE" 119 #define SPLASH_JAR_ENV_ENTRY "_JAVA_SPLASH_JAR" 120 #endif 121 122 static jboolean printVersion = JNI_FALSE; /* print and exit */ 123 static jboolean showVersion = JNI_FALSE; /* print but continue */ 124 static char *progname; 125 jboolean _launcher_debug = JNI_FALSE; 126 127 #ifndef GAMMA 128 /* 129 * Entries for splash screen environment variables. 130 * putenv is performed in SelectVersion. We need 131 * them in memory until UnsetEnv, so they are made static 132 * global instead of auto local. 133 */ 134 static char* splash_file_entry = NULL; 135 static char* splash_jar_entry = NULL; 136 #endif 137 138 /* 139 * List of VM options to be specified when the VM is created. 140 */ 141 static JavaVMOption *options; 142 static int numOptions, maxOptions; 143 144 /* 145 * Prototypes for functions internal to launcher. 146 */ 147 static void SetClassPath(const char *s); 148 static void SelectVersion(int argc, char **argv, char **main_class); 149 static jboolean ParseArguments(int *pargc, char ***pargv, char **pjarfile, 150 char **pclassname, int *pret, const char *jvmpath); 151 static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv, 152 InvocationFunctions *ifn); 153 static jstring NewPlatformString(JNIEnv *env, char *s); 154 static jobjectArray NewPlatformStringArray(JNIEnv *env, char **strv, int strc); 155 static jclass LoadClass(JNIEnv *env, char *name); 156 static jstring GetMainClassName(JNIEnv *env, char *jarname); 157 static void SetJavaCommandLineProp(char* classname, char* jarfile, int argc, char** argv); 158 #ifdef GAMMA 159 static void SetJavaLauncherProp(void); 160 #endif 161 162 #ifdef JAVA_ARGS 163 static void TranslateApplicationArgs(int *pargc, char ***pargv); 164 static jboolean AddApplicationOptions(void); 165 #endif 166 167 static void PrintJavaVersion(JNIEnv *env); 168 static void PrintUsage(void); 169 static jint PrintXUsage(const char *jvmpath); 170 171 static void SetPaths(int argc, char **argv); 172 173 /* Maximum supported entries from jvm.cfg. */ 174 #define INIT_MAX_KNOWN_VMS 10 175 /* Values for vmdesc.flag */ 176 #define VM_UNKNOWN -1 177 #define VM_KNOWN 0 178 #define VM_ALIASED_TO 1 179 #define VM_WARN 2 180 #define VM_ERROR 3 181 #define VM_IF_SERVER_CLASS 4 182 #define VM_IGNORE 5 183 struct vmdesc { 184 char *name; 185 int flag; 186 char *alias; 187 char *server_class; 188 }; 189 static struct vmdesc *knownVMs = NULL; 190 static int knownVMsCount = 0; 191 static int knownVMsLimit = 0; 192 193 static void GrowKnownVMs(); 194 static int KnownVMIndex(const char* name); 195 static void FreeKnownVMs(); 196 #ifndef GAMMA 197 static void ShowSplashScreen(); 198 #endif 199 200 jboolean ServerClassMachine(); 201 202 /* flag which if set suppresses error messages from the launcher */ 203 static int noExitErrorMessage = 0; 204 205 /* 206 * Running Java code in primordial thread caused many problems. We will 207 * create a new thread to invoke JVM. See 6316197 for more information. 208 */ 209 static jlong threadStackSize = 0; /* stack size of the new thread */ 210 211 int JNICALL JavaMain(void * args); /* entry point */ 212 213 struct JavaMainArgs { 214 int argc; 215 char ** argv; 216 char * jarfile; 217 char * classname; 218 InvocationFunctions ifn; 219 }; 220 221 /* 222 * Entry point. 223 */ 224 int 225 main(int argc, char ** argv) 226 { 227 char *jarfile = 0; 228 char *classname = 0; 229 char *s = 0; 230 char *main_class = NULL; 231 int ret; 232 InvocationFunctions ifn; 233 jlong start, end; 234 char jrepath[MAXPATHLEN], jvmpath[MAXPATHLEN]; 235 char ** original_argv = argv; 236 237 if (getenv("_JAVA_LAUNCHER_DEBUG") != 0) { 238 _launcher_debug = JNI_TRUE; 239 printf("----_JAVA_LAUNCHER_DEBUG----\n"); 240 } 241 242 #ifndef GAMMA 243 /* 244 * Make sure the specified version of the JRE is running. 245 * 246 * There are three things to note about the SelectVersion() routine: 247 * 1) If the version running isn't correct, this routine doesn't 248 * return (either the correct version has been exec'd or an error 249 * was issued). 250 * 2) Argc and Argv in this scope are *not* altered by this routine. 251 * It is the responsibility of subsequent code to ignore the 252 * arguments handled by this routine. 253 * 3) As a side-effect, the variable "main_class" is guaranteed to 254 * be set (if it should ever be set). This isn't exactly the 255 * poster child for structured programming, but it is a small 256 * price to pay for not processing a jar file operand twice. 257 * (Note: This side effect has been disabled. See comment on 258 * bugid 5030265 below.) 259 */ 260 SelectVersion(argc, argv, &main_class); 261 #endif /* ifndef GAMMA */ 262 263 /* copy original argv */ 264 { 265 int i; 266 original_argv = (char**)JLI_MemAlloc(sizeof(char*)*(argc+1)); 267 for(i = 0; i < argc+1; i++) 268 original_argv[i] = argv[i]; 269 } 270 271 CreateExecutionEnvironment(&argc, &argv, 272 jrepath, sizeof(jrepath), 273 jvmpath, sizeof(jvmpath), 274 original_argv); 275 276 ifn.CreateJavaVM = 0; 277 ifn.GetDefaultJavaVMInitArgs = 0; 278 279 if (_launcher_debug) 280 start = CounterGet(); 281 if (!LoadJavaVM(jvmpath, &ifn)) { 282 exit(6); 283 } 284 if (_launcher_debug) { 285 end = CounterGet(); 286 printf("%ld micro seconds to LoadJavaVM\n", 287 (long)(jint)Counter2Micros(end-start)); 288 } 289 290 #ifdef JAVA_ARGS /* javac, jar and friends. */ 291 progname = "java"; 292 #else /* java, oldjava, javaw and friends */ 293 #ifdef PROGNAME 294 progname = PROGNAME; 295 #else 296 progname = *argv; 297 if ((s = strrchr(progname, FILE_SEPARATOR)) != 0) { 298 progname = s + 1; 299 } 300 #endif /* PROGNAME */ 301 #endif /* JAVA_ARGS */ 302 ++argv; 303 --argc; 304 305 #ifdef JAVA_ARGS 306 /* Preprocess wrapper arguments */ 307 TranslateApplicationArgs(&argc, &argv); 308 if (!AddApplicationOptions()) { 309 exit(1); 310 } 311 #endif 312 313 /* Set default CLASSPATH */ 314 if ((s = getenv("CLASSPATH")) == 0) { 315 s = "."; 316 } 317 #ifndef JAVA_ARGS 318 SetClassPath(s); 319 #endif 320 321 /* 322 * Parse command line options; if the return value of 323 * ParseArguments is false, the program should exit. 324 */ 325 if (!ParseArguments(&argc, &argv, &jarfile, &classname, &ret, jvmpath)) { 326 exit(ret); 327 } 328 329 /* Override class path if -jar flag was specified */ 330 if (jarfile != 0) { 331 SetClassPath(jarfile); 332 } 333 334 /* set the -Dsun.java.command pseudo property */ 335 SetJavaCommandLineProp(classname, jarfile, argc, argv); 336 337 #ifdef GAMMA 338 /* Set the -Dsun.java.launcher pseudo property */ 339 SetJavaLauncherProp(); 340 #endif 341 342 /* set the -Dsun.java.launcher.* platform properties */ 343 SetJavaLauncherPlatformProps(); 344 345 #ifndef GAMMA 346 /* Show the splash screen if needed */ 347 ShowSplashScreen(); 348 #endif 349 350 /* 351 * Done with all command line processing and potential re-execs so 352 * clean up the environment. 353 */ 354 (void)UnsetEnv(ENV_ENTRY); 355 #ifndef GAMMA 356 (void)UnsetEnv(SPLASH_FILE_ENV_ENTRY); 357 (void)UnsetEnv(SPLASH_JAR_ENV_ENTRY); 358 359 JLI_MemFree(splash_jar_entry); 360 JLI_MemFree(splash_file_entry); 361 #endif 362 363 /* 364 * If user doesn't specify stack size, check if VM has a preference. 365 * Note that HotSpot no longer supports JNI_VERSION_1_1 but it will 366 * return its default stack size through the init args structure. 367 */ 368 if (threadStackSize == 0) { 369 struct JDK1_1InitArgs args1_1; 370 memset((void*)&args1_1, 0, sizeof(args1_1)); 371 args1_1.version = JNI_VERSION_1_1; 372 ifn.GetDefaultJavaVMInitArgs(&args1_1); /* ignore return value */ 373 if (args1_1.javaStackSize > 0) { 374 threadStackSize = args1_1.javaStackSize; 375 } 376 } 377 378 { /* Create a new thread to create JVM and invoke main method */ 379 struct JavaMainArgs args; 380 381 args.argc = argc; 382 args.argv = argv; 383 args.jarfile = jarfile; 384 args.classname = classname; 385 args.ifn = ifn; 386 387 return ContinueInNewThread(JavaMain, threadStackSize, (void*)&args); 388 } 389 } 390 391 int JNICALL 392 JavaMain(void * _args) 393 { 394 struct JavaMainArgs *args = (struct JavaMainArgs *)_args; 395 int argc = args->argc; 396 char **argv = args->argv; 397 char *jarfile = args->jarfile; 398 char *classname = args->classname; 399 InvocationFunctions ifn = args->ifn; 400 401 JavaVM *vm = 0; 402 JNIEnv *env = 0; 403 jstring mainClassName; 404 jclass mainClass; 405 jmethodID mainID; 406 jobjectArray mainArgs; 407 int ret = 0; 408 jlong start, end; 409 410 /* 411 * Error message to print or display; by default the message will 412 * only be displayed in a window. 413 */ 414 char * message = "Fatal exception occurred. Program will exit."; 415 jboolean messageDest = JNI_FALSE; 416 417 /* Initialize the virtual machine */ 418 419 if (_launcher_debug) 420 start = CounterGet(); 421 if (!InitializeJVM(&vm, &env, &ifn)) { 422 ReportErrorMessage("Could not create the Java virtual machine.", 423 JNI_TRUE); 424 exit(1); 425 } 426 427 if (printVersion || showVersion) { 428 PrintJavaVersion(env); 429 if ((*env)->ExceptionOccurred(env)) { 430 ReportExceptionDescription(env); 431 goto leave; 432 } 433 if (printVersion) { 434 ret = 0; 435 message = NULL; 436 goto leave; 437 } 438 if (showVersion) { 439 fprintf(stderr, "\n"); 440 } 441 } 442 443 /* If the user specified neither a class name nor a JAR file */ 444 if (jarfile == 0 && classname == 0) { 445 PrintUsage(); 446 message = NULL; 447 goto leave; 448 } 449 450 #ifndef GAMMA 451 FreeKnownVMs(); /* after last possible PrintUsage() */ 452 #endif 453 454 if (_launcher_debug) { 455 end = CounterGet(); 456 printf("%ld micro seconds to InitializeJVM\n", 457 (long)(jint)Counter2Micros(end-start)); 458 } 459 460 /* At this stage, argc/argv have the applications' arguments */ 461 if (_launcher_debug) { 462 int i = 0; 463 printf("Main-Class is '%s'\n", classname ? classname : ""); 464 printf("Apps' argc is %d\n", argc); 465 for (; i < argc; i++) { 466 printf(" argv[%2d] = '%s'\n", i, argv[i]); 467 } 468 } 469 470 ret = 1; 471 472 /* 473 * Get the application's main class. 474 * 475 * See bugid 5030265. The Main-Class name has already been parsed 476 * from the manifest, but not parsed properly for UTF-8 support. 477 * Hence the code here ignores the value previously extracted and 478 * uses the pre-existing code to reextract the value. This is 479 * possibly an end of release cycle expedient. However, it has 480 * also been discovered that passing some character sets through 481 * the environment has "strange" behavior on some variants of 482 * Windows. Hence, maybe the manifest parsing code local to the 483 * launcher should never be enhanced. 484 * 485 * Hence, future work should either: 486 * 1) Correct the local parsing code and verify that the 487 * Main-Class attribute gets properly passed through 488 * all environments, 489 * 2) Remove the vestages of maintaining main_class through 490 * the environment (and remove these comments). 491 */ 492 if (jarfile != 0) { 493 mainClassName = GetMainClassName(env, jarfile); 494 if ((*env)->ExceptionOccurred(env)) { 495 ReportExceptionDescription(env); 496 goto leave; 497 } 498 if (mainClassName == NULL) { 499 const char * format = "Failed to load Main-Class manifest " 500 "attribute from\n%s"; 501 message = (char*)JLI_MemAlloc((strlen(format) + strlen(jarfile)) * 502 sizeof(char)); 503 sprintf(message, format, jarfile); 504 messageDest = JNI_TRUE; 505 goto leave; 506 } 507 classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); 508 if (classname == NULL) { 509 ReportExceptionDescription(env); 510 goto leave; 511 } 512 mainClass = LoadClass(env, classname); 513 if(mainClass == NULL) { /* exception occured */ 514 const char * format = "Could not find the main class: %s. Program will exit."; 515 ReportExceptionDescription(env); 516 message = (char *)JLI_MemAlloc((strlen(format) + 517 strlen(classname)) * sizeof(char) ); 518 messageDest = JNI_TRUE; 519 sprintf(message, format, classname); 520 goto leave; 521 } 522 (*env)->ReleaseStringUTFChars(env, mainClassName, classname); 523 } else { 524 mainClassName = NewPlatformString(env, classname); 525 if (mainClassName == NULL) { 526 const char * format = "Failed to load Main Class: %s"; 527 message = (char *)JLI_MemAlloc((strlen(format) + strlen(classname)) * 528 sizeof(char) ); 529 sprintf(message, format, classname); 530 messageDest = JNI_TRUE; 531 goto leave; 532 } 533 classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0); 534 if (classname == NULL) { 535 ReportExceptionDescription(env); 536 goto leave; 537 } 538 mainClass = LoadClass(env, classname); 539 if(mainClass == NULL) { /* exception occured */ 540 const char * format = "Could not find the main class: %s. Program will exit."; 541 ReportExceptionDescription(env); 542 message = (char *)JLI_MemAlloc((strlen(format) + 543 strlen(classname)) * sizeof(char) ); 544 messageDest = JNI_TRUE; 545 sprintf(message, format, classname); 546 goto leave; 547 } 548 (*env)->ReleaseStringUTFChars(env, mainClassName, classname); 549 } 550 551 /* Get the application's main method */ 552 mainID = (*env)->GetStaticMethodID(env, mainClass, "main", 553 "([Ljava/lang/String;)V"); 554 if (mainID == NULL) { 555 if ((*env)->ExceptionOccurred(env)) { 556 ReportExceptionDescription(env); 557 } else { 558 message = "No main method found in specified class."; 559 messageDest = JNI_TRUE; 560 } 561 goto leave; 562 } 563 564 { /* Make sure the main method is public */ 565 jint mods; 566 jmethodID mid; 567 jobject obj = (*env)->ToReflectedMethod(env, mainClass, 568 mainID, JNI_TRUE); 569 570 if( obj == NULL) { /* exception occurred */ 571 ReportExceptionDescription(env); 572 goto leave; 573 } 574 575 mid = 576 (*env)->GetMethodID(env, 577 (*env)->GetObjectClass(env, obj), 578 "getModifiers", "()I"); 579 if ((*env)->ExceptionOccurred(env)) { 580 ReportExceptionDescription(env); 581 goto leave; 582 } 583 584 mods = (*env)->CallIntMethod(env, obj, mid); 585 if ((mods & 1) == 0) { /* if (!Modifier.isPublic(mods)) ... */ 586 message = "Main method not public."; 587 messageDest = JNI_TRUE; 588 goto leave; 589 } 590 } 591 592 /* Build argument array */ 593 mainArgs = NewPlatformStringArray(env, argv, argc); 594 if (mainArgs == NULL) { 595 ReportExceptionDescription(env); 596 goto leave; 597 } 598 599 /* Invoke main method. */ 600 (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); 601 602 /* 603 * The launcher's exit code (in the absence of calls to 604 * System.exit) will be non-zero if main threw an exception. 605 */ 606 ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1; 607 608 /* 609 * Detach the main thread so that it appears to have ended when 610 * the application's main method exits. This will invoke the 611 * uncaught exception handler machinery if main threw an 612 * exception. An uncaught exception handler cannot change the 613 * launcher's return code except by calling System.exit. 614 */ 615 if ((*vm)->DetachCurrentThread(vm) != 0) { 616 message = "Could not detach main thread."; 617 messageDest = JNI_TRUE; 618 ret = 1; 619 goto leave; 620 } 621 622 message = NULL; 623 624 leave: 625 /* 626 * Wait for all non-daemon threads to end, then destroy the VM. 627 * This will actually create a trivial new Java waiter thread 628 * named "DestroyJavaVM", but this will be seen as a different 629 * thread from the one that executed main, even though they are 630 * the same C thread. This allows mainThread.join() and 631 * mainThread.isAlive() to work as expected. 632 */ 633 (*vm)->DestroyJavaVM(vm); 634 635 if(message != NULL && !noExitErrorMessage) 636 ReportErrorMessage(message, messageDest); 637 return ret; 638 } 639 640 641 #ifndef GAMMA 642 /* 643 * Checks the command line options to find which JVM type was 644 * specified. If no command line option was given for the JVM type, 645 * the default type is used. The environment variable 646 * JDK_ALTERNATE_VM and the command line option -XXaltjvm= are also 647 * checked as ways of specifying which JVM type to invoke. 648 */ 649 char * 650 CheckJvmType(int *pargc, char ***argv, jboolean speculative) { 651 int i, argi; 652 int argc; 653 char **newArgv; 654 int newArgvIdx = 0; 655 int isVMType; 656 int jvmidx = -1; 657 char *jvmtype = getenv("JDK_ALTERNATE_VM"); 658 659 argc = *pargc; 660 661 /* To make things simpler we always copy the argv array */ 662 newArgv = JLI_MemAlloc((argc + 1) * sizeof(char *)); 663 664 /* The program name is always present */ 665 newArgv[newArgvIdx++] = (*argv)[0]; 666 667 for (argi = 1; argi < argc; argi++) { 668 char *arg = (*argv)[argi]; 669 isVMType = 0; 670 671 #ifdef JAVA_ARGS 672 if (arg[0] != '-') { 673 newArgv[newArgvIdx++] = arg; 674 continue; 675 } 676 #else 677 if (strcmp(arg, "-classpath") == 0 || 678 strcmp(arg, "-cp") == 0) { 679 newArgv[newArgvIdx++] = arg; 680 argi++; 681 if (argi < argc) { 682 newArgv[newArgvIdx++] = (*argv)[argi]; 683 } 684 continue; 685 } 686 if (arg[0] != '-') break; 687 #endif 688 689 /* Did the user pass an explicit VM type? */ 690 i = KnownVMIndex(arg); 691 if (i >= 0) { 692 jvmtype = knownVMs[jvmidx = i].name + 1; /* skip the - */ 693 isVMType = 1; 694 *pargc = *pargc - 1; 695 } 696 697 /* Did the user specify an "alternate" VM? */ 698 else if (strncmp(arg, "-XXaltjvm=", 10) == 0 || strncmp(arg, "-J-XXaltjvm=", 12) == 0) { 699 isVMType = 1; 700 jvmtype = arg+((arg[1]=='X')? 10 : 12); 701 jvmidx = -1; 702 } 703 704 if (!isVMType) { 705 newArgv[newArgvIdx++] = arg; 706 } 707 } 708 709 /* 710 * Finish copying the arguments if we aborted the above loop. 711 * NOTE that if we aborted via "break" then we did NOT copy the 712 * last argument above, and in addition argi will be less than 713 * argc. 714 */ 715 while (argi < argc) { 716 newArgv[newArgvIdx++] = (*argv)[argi]; 717 argi++; 718 } 719 720 /* argv is null-terminated */ 721 newArgv[newArgvIdx] = 0; 722 723 /* Copy back argv */ 724 *argv = newArgv; 725 *pargc = newArgvIdx; 726 727 /* use the default VM type if not specified (no alias processing) */ 728 if (jvmtype == NULL) { 729 char* result = knownVMs[0].name+1; 730 /* Use a different VM type if we are on a server class machine? */ 731 if ((knownVMs[0].flag == VM_IF_SERVER_CLASS) && 732 (ServerClassMachine() == JNI_TRUE)) { 733 result = knownVMs[0].server_class+1; 734 } 735 if (_launcher_debug) { 736 printf("Default VM: %s\n", result); 737 } 738 return result; 739 } 740 741 /* if using an alternate VM, no alias processing */ 742 if (jvmidx < 0) 743 return jvmtype; 744 745 /* Resolve aliases first */ 746 { 747 int loopCount = 0; 748 while (knownVMs[jvmidx].flag == VM_ALIASED_TO) { 749 int nextIdx = KnownVMIndex(knownVMs[jvmidx].alias); 750 751 if (loopCount > knownVMsCount) { 752 if (!speculative) { 753 ReportErrorMessage("Error: Corrupt jvm.cfg file; cycle in alias list.", 754 JNI_TRUE); 755 exit(1); 756 } else { 757 return "ERROR"; 758 /* break; */ 759 } 760 } 761 762 if (nextIdx < 0) { 763 if (!speculative) { 764 ReportErrorMessage2("Error: Unable to resolve VM alias %s", 765 knownVMs[jvmidx].alias, JNI_TRUE); 766 exit(1); 767 } else { 768 return "ERROR"; 769 } 770 } 771 jvmidx = nextIdx; 772 jvmtype = knownVMs[jvmidx].name+1; 773 loopCount++; 774 } 775 } 776 777 switch (knownVMs[jvmidx].flag) { 778 case VM_WARN: 779 if (!speculative) { 780 fprintf(stderr, "Warning: %s VM not supported; %s VM will be used\n", 781 jvmtype, knownVMs[0].name + 1); 782 } 783 /* fall through */ 784 case VM_IGNORE: 785 jvmtype = knownVMs[jvmidx=0].name + 1; 786 /* fall through */ 787 case VM_KNOWN: 788 break; 789 case VM_ERROR: 790 if (!speculative) { 791 ReportErrorMessage2("Error: %s VM not supported", jvmtype, JNI_TRUE); 792 exit(1); 793 } else { 794 return "ERROR"; 795 } 796 } 797 798 return jvmtype; 799 } 800 #endif /* ifndef GAMMA */ 801 802 # define KB (1024UL) 803 # define MB (1024UL * KB) 804 # define GB (1024UL * MB) 805 806 /* copied from HotSpot function "atomll()" */ 807 static int 808 parse_stack_size(const char *s, jlong *result) { 809 jlong n = 0; 810 int args_read = sscanf(s, jlong_format_specifier(), &n); 811 if (args_read != 1) { 812 return 0; 813 } 814 while (*s != '\0' && *s >= '0' && *s <= '9') { 815 s++; 816 } 817 // 4705540: illegal if more characters are found after the first non-digit 818 if (strlen(s) > 1) { 819 return 0; 820 } 821 switch (*s) { 822 case 'T': case 't': 823 *result = n * GB * KB; 824 return 1; 825 case 'G': case 'g': 826 *result = n * GB; 827 return 1; 828 case 'M': case 'm': 829 *result = n * MB; 830 return 1; 831 case 'K': case 'k': 832 *result = n * KB; 833 return 1; 834 case '\0': 835 *result = n; 836 return 1; 837 default: 838 /* Create JVM with default stack and let VM handle malformed -Xss string*/ 839 return 0; 840 } 841 } 842 843 /* 844 * Adds a new VM option with the given given name and value. 845 */ 846 void 847 AddOption(char *str, void *info) 848 { 849 /* 850 * Expand options array if needed to accommodate at least one more 851 * VM option. 852 */ 853 if (numOptions >= maxOptions) { 854 if (options == 0) { 855 maxOptions = 4; 856 options = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption)); 857 } else { 858 JavaVMOption *tmp; 859 maxOptions *= 2; 860 tmp = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption)); 861 memcpy(tmp, options, numOptions * sizeof(JavaVMOption)); 862 JLI_MemFree(options); 863 options = tmp; 864 } 865 } 866 options[numOptions].optionString = str; 867 options[numOptions++].extraInfo = info; 868 869 if (strncmp(str, "-Xss", 4) == 0) { 870 jlong tmp; 871 if (parse_stack_size(str + 4, &tmp)) { 872 threadStackSize = tmp; 873 } 874 } 875 } 876 877 static void 878 SetClassPath(const char *s) 879 { 880 char *def; 881 #ifndef GAMMA 882 s = JLI_WildcardExpandClasspath(s); 883 #endif 884 def = JLI_MemAlloc(strlen(s) + 40); 885 sprintf(def, "-Djava.class.path=%s", s); 886 AddOption(def, NULL); 887 } 888 889 #ifndef GAMMA 890 /* 891 * The SelectVersion() routine ensures that an appropriate version of 892 * the JRE is running. The specification for the appropriate version 893 * is obtained from either the manifest of a jar file (preferred) or 894 * from command line options. 895 * The routine also parses splash screen command line options and 896 * passes on their values in private environment variables. 897 */ 898 static void 899 SelectVersion(int argc, char **argv, char **main_class) 900 { 901 char *arg; 902 char **new_argv; 903 char **new_argp; 904 char *operand; 905 char *version = NULL; 906 char *jre = NULL; 907 int jarflag = 0; 908 int headlessflag = 0; 909 int restrict_search = -1; /* -1 implies not known */ 910 manifest_info info; 911 char env_entry[MAXNAMELEN + 24] = ENV_ENTRY "="; 912 char *splash_file_name = NULL; 913 char *splash_jar_name = NULL; 914 char *env_in; 915 int res; 916 917 /* 918 * If the version has already been selected, set *main_class 919 * with the value passed through the environment (if any) and 920 * simply return. 921 */ 922 if ((env_in = getenv(ENV_ENTRY)) != NULL) { 923 if (*env_in != '\0') 924 *main_class = JLI_StringDup(env_in); 925 return; 926 } 927 928 /* 929 * Scan through the arguments for options relevant to multiple JRE 930 * support. For reference, the command line syntax is defined as: 931 * 932 * SYNOPSIS 933 * java [options] class [argument...] 934 * 935 * java [options] -jar file.jar [argument...] 936 * 937 * As the scan is performed, make a copy of the argument list with 938 * the version specification options (new to 1.5) removed, so that 939 * a version less than 1.5 can be exec'd. 940 * 941 * Note that due to the syntax of the native Windows interface 942 * CreateProcess(), processing similar to the following exists in 943 * the Windows platform specific routine ExecJRE (in java_md.c). 944 * Changes here should be reproduced there. 945 */ 946 new_argv = JLI_MemAlloc((argc + 1) * sizeof(char*)); 947 new_argv[0] = argv[0]; 948 new_argp = &new_argv[1]; 949 argc--; 950 argv++; 951 while ((arg = *argv) != 0 && *arg == '-') { 952 if (strncmp(arg, "-version:", 9) == 0) { 953 version = arg + 9; 954 } else if (strcmp(arg, "-jre-restrict-search") == 0) { 955 restrict_search = 1; 956 } else if (strcmp(arg, "-no-jre-restrict-search") == 0) { 957 restrict_search = 0; 958 } else { 959 if (strcmp(arg, "-jar") == 0) 960 jarflag = 1; 961 /* deal with "unfortunate" classpath syntax */ 962 if ((strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) && 963 (argc >= 2)) { 964 *new_argp++ = arg; 965 argc--; 966 argv++; 967 arg = *argv; 968 } 969 970 /* 971 * Checking for headless toolkit option in the some way as AWT does: 972 * "true" means true and any other value means false 973 */ 974 if (strcmp(arg, "-Djava.awt.headless=true") == 0) { 975 headlessflag = 1; 976 } else if (strncmp(arg, "-Djava.awt.headless=", 20) == 0) { 977 headlessflag = 0; 978 } else if (strncmp(arg, "-splash:", 8) == 0) { 979 splash_file_name = arg+8; 980 } 981 *new_argp++ = arg; 982 } 983 argc--; 984 argv++; 985 } 986 if (argc <= 0) { /* No operand? Possibly legit with -[full]version */ 987 operand = NULL; 988 } else { 989 argc--; 990 *new_argp++ = operand = *argv++; 991 } 992 while (argc-- > 0) /* Copy over [argument...] */ 993 *new_argp++ = *argv++; 994 *new_argp = NULL; 995 996 /* 997 * If there is a jar file, read the manifest. If the jarfile can't be 998 * read, the manifest can't be read from the jar file, or the manifest 999 * is corrupt, issue the appropriate error messages and exit. 1000 * 1001 * Even if there isn't a jar file, construct a manifest_info structure 1002 * containing the command line information. It's a convenient way to carry 1003 * this data around. 1004 */ 1005 if (jarflag && operand) { 1006 if ((res = JLI_ParseManifest(operand, &info)) != 0) { 1007 if (res == -1) 1008 ReportErrorMessage2("Unable to access jarfile %s", 1009 operand, JNI_TRUE); 1010 else 1011 ReportErrorMessage2("Invalid or corrupt jarfile %s", 1012 operand, JNI_TRUE); 1013 exit(1); 1014 } 1015 1016 /* 1017 * Command line splash screen option should have precedence 1018 * over the manifest, so the manifest data is used only if 1019 * splash_file_name has not been initialized above during command 1020 * line parsing 1021 */ 1022 if (!headlessflag && !splash_file_name && info.splashscreen_image_file_name) { 1023 splash_file_name = info.splashscreen_image_file_name; 1024 splash_jar_name = operand; 1025 } 1026 } else { 1027 info.manifest_version = NULL; 1028 info.main_class = NULL; 1029 info.jre_version = NULL; 1030 info.jre_restrict_search = 0; 1031 } 1032 1033 /* 1034 * Passing on splash screen info in environment variables 1035 */ 1036 if (splash_file_name && !headlessflag) { 1037 char* splash_file_entry = JLI_MemAlloc(strlen(SPLASH_FILE_ENV_ENTRY "=")+strlen(splash_file_name)+1); 1038 strcpy(splash_file_entry, SPLASH_FILE_ENV_ENTRY "="); 1039 strcat(splash_file_entry, splash_file_name); 1040 putenv(splash_file_entry); 1041 } 1042 if (splash_jar_name && !headlessflag) { 1043 char* splash_jar_entry = JLI_MemAlloc(strlen(SPLASH_JAR_ENV_ENTRY "=")+strlen(splash_jar_name)+1); 1044 strcpy(splash_jar_entry, SPLASH_JAR_ENV_ENTRY "="); 1045 strcat(splash_jar_entry, splash_jar_name); 1046 putenv(splash_jar_entry); 1047 } 1048 1049 /* 1050 * The JRE-Version and JRE-Restrict-Search values (if any) from the 1051 * manifest are overwritten by any specified on the command line. 1052 */ 1053 if (version != NULL) 1054 info.jre_version = version; 1055 if (restrict_search != -1) 1056 info.jre_restrict_search = restrict_search; 1057 1058 /* 1059 * "Valid" returns (other than unrecoverable errors) follow. Set 1060 * main_class as a side-effect of this routine. 1061 */ 1062 if (info.main_class != NULL) 1063 *main_class = JLI_StringDup(info.main_class); 1064 1065 /* 1066 * If no version selection information is found either on the command 1067 * line or in the manifest, simply return. 1068 */ 1069 if (info.jre_version == NULL) { 1070 JLI_FreeManifest(); 1071 JLI_MemFree(new_argv); 1072 return; 1073 } 1074 1075 /* 1076 * Check for correct syntax of the version specification (JSR 56). 1077 */ 1078 if (!JLI_ValidVersionString(info.jre_version)) { 1079 ReportErrorMessage2("Syntax error in version specification \"%s\"", 1080 info.jre_version, JNI_TRUE); 1081 exit(1); 1082 } 1083 1084 /* 1085 * Find the appropriate JVM on the system. Just to be as forgiving as 1086 * possible, if the standard algorithms don't locate an appropriate 1087 * jre, check to see if the one running will satisfy the requirements. 1088 * This can happen on systems which haven't been set-up for multiple 1089 * JRE support. 1090 */ 1091 jre = LocateJRE(&info); 1092 if (_launcher_debug) 1093 printf("JRE-Version = %s, JRE-Restrict-Search = %s Selected = %s\n", 1094 (info.jre_version?info.jre_version:"null"), 1095 (info.jre_restrict_search?"true":"false"), (jre?jre:"null")); 1096 if (jre == NULL) { 1097 if (JLI_AcceptableRelease(FULL_VERSION, info.jre_version)) { 1098 JLI_FreeManifest(); 1099 JLI_MemFree(new_argv); 1100 return; 1101 } else { 1102 ReportErrorMessage2( 1103 "Unable to locate JRE meeting specification \"%s\"", 1104 info.jre_version, JNI_TRUE); 1105 exit(1); 1106 } 1107 } 1108 1109 /* 1110 * If I'm not the chosen one, exec the chosen one. Returning from 1111 * ExecJRE indicates that I am indeed the chosen one. 1112 * 1113 * The private environment variable _JAVA_VERSION_SET is used to 1114 * prevent the chosen one from re-reading the manifest file and 1115 * using the values found within to override the (potential) command 1116 * line flags stripped from argv (because the target may not 1117 * understand them). Passing the MainClass value is an optimization 1118 * to avoid locating, expanding and parsing the manifest extra 1119 * times. 1120 */ 1121 if (info.main_class != NULL) { 1122 if (strlen(info.main_class) <= MAXNAMELEN) { 1123 (void)strcat(env_entry, info.main_class); 1124 } else { 1125 ReportErrorMessage("Error: main-class: attribute exceeds system limits\n", JNI_TRUE); 1126 exit(1); 1127 } 1128 } 1129 (void)putenv(env_entry); 1130 ExecJRE(jre, new_argv); 1131 JLI_FreeManifest(); 1132 JLI_MemFree(new_argv); 1133 return; 1134 } 1135 #endif /* ifndef GAMMA */ 1136 1137 /* 1138 * Parses command line arguments. Returns JNI_FALSE if launcher 1139 * should exit without starting vm (e.g. certain version and usage 1140 * options); returns JNI_TRUE if vm needs to be started to process 1141 * given options. *pret (the launcher process return value) is set to 1142 * 0 for a normal exit. 1143 */ 1144 static jboolean 1145 ParseArguments(int *pargc, char ***pargv, char **pjarfile, 1146 char **pclassname, int *pret, const char *jvmpath) 1147 { 1148 int argc = *pargc; 1149 char **argv = *pargv; 1150 jboolean jarflag = JNI_FALSE; 1151 char *arg; 1152 1153 *pret = 1; 1154 while ((arg = *argv) != 0 && *arg == '-') { 1155 argv++; --argc; 1156 if (strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) { 1157 if (argc < 1) { 1158 ReportErrorMessage2("%s requires class path specification", 1159 arg, JNI_TRUE); 1160 PrintUsage(); 1161 return JNI_FALSE; 1162 } 1163 SetClassPath(*argv); 1164 argv++; --argc; 1165 } else if (strcmp(arg, "-jar") == 0) { 1166 jarflag = JNI_TRUE; 1167 } else if (strcmp(arg, "-help") == 0 || 1168 strcmp(arg, "-h") == 0 || 1169 strcmp(arg, "-?") == 0) { 1170 PrintUsage(); 1171 *pret = 0; 1172 return JNI_FALSE; 1173 } else if (strcmp(arg, "-version") == 0) { 1174 printVersion = JNI_TRUE; 1175 return JNI_TRUE; 1176 } else if (strcmp(arg, "-showversion") == 0) { 1177 showVersion = JNI_TRUE; 1178 } else if (strcmp(arg, "-X") == 0) { 1179 *pret = PrintXUsage(jvmpath); 1180 return JNI_FALSE; 1181 /* 1182 * The following case provide backward compatibility with old-style 1183 * command line options. 1184 */ 1185 } else if (strcmp(arg, "-fullversion") == 0) { 1186 fprintf(stderr, "%s full version \"%s\"\n", progname, 1187 FULL_VERSION); 1188 *pret = 0; 1189 return JNI_FALSE; 1190 } else if (strcmp(arg, "-verbosegc") == 0) { 1191 AddOption("-verbose:gc", NULL); 1192 } else if (strcmp(arg, "-t") == 0) { 1193 AddOption("-Xt", NULL); 1194 } else if (strcmp(arg, "-tm") == 0) { 1195 AddOption("-Xtm", NULL); 1196 } else if (strcmp(arg, "-debug") == 0) { 1197 AddOption("-Xdebug", NULL); 1198 } else if (strcmp(arg, "-noclassgc") == 0) { 1199 AddOption("-Xnoclassgc", NULL); 1200 } else if (strcmp(arg, "-Xfuture") == 0) { 1201 AddOption("-Xverify:all", NULL); 1202 } else if (strcmp(arg, "-verify") == 0) { 1203 AddOption("-Xverify:all", NULL); 1204 } else if (strcmp(arg, "-verifyremote") == 0) { 1205 AddOption("-Xverify:remote", NULL); 1206 } else if (strcmp(arg, "-noverify") == 0) { 1207 AddOption("-Xverify:none", NULL); 1208 } else if (strcmp(arg, "-XXsuppressExitMessage") == 0) { 1209 noExitErrorMessage = 1; 1210 } else if (strncmp(arg, "-prof", 5) == 0) { 1211 char *p = arg + 5; 1212 char *tmp = JLI_MemAlloc(strlen(arg) + 50); 1213 if (*p) { 1214 sprintf(tmp, "-Xrunhprof:cpu=old,file=%s", p + 1); 1215 } else { 1216 sprintf(tmp, "-Xrunhprof:cpu=old,file=java.prof"); 1217 } 1218 AddOption(tmp, NULL); 1219 } else if (strncmp(arg, "-ss", 3) == 0 || 1220 strncmp(arg, "-oss", 4) == 0 || 1221 strncmp(arg, "-ms", 3) == 0 || 1222 strncmp(arg, "-mx", 3) == 0) { 1223 char *tmp = JLI_MemAlloc(strlen(arg) + 6); 1224 sprintf(tmp, "-X%s", arg + 1); /* skip '-' */ 1225 AddOption(tmp, NULL); 1226 } else if (strcmp(arg, "-checksource") == 0 || 1227 strcmp(arg, "-cs") == 0 || 1228 strcmp(arg, "-noasyncgc") == 0) { 1229 /* No longer supported */ 1230 fprintf(stderr, 1231 "Warning: %s option is no longer supported.\n", 1232 arg); 1233 } else if (strncmp(arg, "-version:", 9) == 0 || 1234 strcmp(arg, "-no-jre-restrict-search") == 0 || 1235 strcmp(arg, "-jre-restrict-search") == 0 || 1236 strncmp(arg, "-splash:", 8) == 0) { 1237 ; /* Ignore machine independent options already handled */ 1238 } else if (RemovableMachineDependentOption(arg) ) { 1239 ; /* Do not pass option to vm. */ 1240 } 1241 else { 1242 AddOption(arg, NULL); 1243 } 1244 } 1245 1246 if (--argc >= 0) { 1247 if (jarflag) { 1248 *pjarfile = *argv++; 1249 *pclassname = 0; 1250 } else { 1251 *pjarfile = 0; 1252 *pclassname = *argv++; 1253 } 1254 *pargc = argc; 1255 *pargv = argv; 1256 } 1257 1258 return JNI_TRUE; 1259 } 1260 1261 /* 1262 * Initializes the Java Virtual Machine. Also frees options array when 1263 * finished. 1264 */ 1265 static jboolean 1266 InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn) 1267 { 1268 JavaVMInitArgs args; 1269 jint r; 1270 1271 memset(&args, 0, sizeof(args)); 1272 args.version = JNI_VERSION_1_2; 1273 args.nOptions = numOptions; 1274 args.options = options; 1275 args.ignoreUnrecognized = JNI_FALSE; 1276 1277 if (_launcher_debug) { 1278 int i = 0; 1279 printf("JavaVM args:\n "); 1280 printf("version 0x%08lx, ", (long)args.version); 1281 printf("ignoreUnrecognized is %s, ", 1282 args.ignoreUnrecognized ? "JNI_TRUE" : "JNI_FALSE"); 1283 printf("nOptions is %ld\n", (long)args.nOptions); 1284 for (i = 0; i < numOptions; i++) 1285 printf(" option[%2d] = '%s'\n", 1286 i, args.options[i].optionString); 1287 } 1288 1289 r = ifn->CreateJavaVM(pvm, (void **)penv, &args); 1290 JLI_MemFree(options); 1291 return r == JNI_OK; 1292 } 1293 1294 1295 #define NULL_CHECK0(e) if ((e) == 0) return 0 1296 #define NULL_CHECK(e) if ((e) == 0) return 1297 1298 static jstring platformEncoding = NULL; 1299 static jstring getPlatformEncoding(JNIEnv *env) { 1300 if (platformEncoding == NULL) { 1301 jstring propname = (*env)->NewStringUTF(env, "sun.jnu.encoding"); 1302 if (propname) { 1303 jclass cls; 1304 jmethodID mid; 1305 NULL_CHECK0 (cls = (*env)->FindClass(env, "java/lang/System")); 1306 NULL_CHECK0 (mid = (*env)->GetStaticMethodID( 1307 env, cls, 1308 "getProperty", 1309 "(Ljava/lang/String;)Ljava/lang/String;")); 1310 platformEncoding = (*env)->CallStaticObjectMethod ( 1311 env, cls, mid, propname); 1312 } 1313 } 1314 return platformEncoding; 1315 } 1316 1317 static jboolean isEncodingSupported(JNIEnv *env, jstring enc) { 1318 jclass cls; 1319 jmethodID mid; 1320 NULL_CHECK0 (cls = (*env)->FindClass(env, "java/nio/charset/Charset")); 1321 NULL_CHECK0 (mid = (*env)->GetStaticMethodID( 1322 env, cls, 1323 "isSupported", 1324 "(Ljava/lang/String;)Z")); 1325 return (*env)->CallStaticBooleanMethod(env, cls, mid, enc); 1326 } 1327 1328 /* 1329 * Returns a new Java string object for the specified platform string. 1330 */ 1331 static jstring 1332 NewPlatformString(JNIEnv *env, char *s) 1333 { 1334 int len = (int)strlen(s); 1335 jclass cls; 1336 jmethodID mid; 1337 jbyteArray ary; 1338 jstring enc; 1339 1340 if (s == NULL) 1341 return 0; 1342 enc = getPlatformEncoding(env); 1343 1344 ary = (*env)->NewByteArray(env, len); 1345 if (ary != 0) { 1346 jstring str = 0; 1347 (*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s); 1348 if (!(*env)->ExceptionOccurred(env)) { 1349 #ifdef GAMMA 1350 /* We support running JVM with older JDK, so here we have to deal */ 1351 /* with the case that sun.jnu.encoding is undefined (enc == NULL) */ 1352 if (enc != NULL && isEncodingSupported(env, enc) == JNI_TRUE) { 1353 #else 1354 if (isEncodingSupported(env, enc) == JNI_TRUE) { 1355 #endif 1356 NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String")); 1357 NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", 1358 "([BLjava/lang/String;)V")); 1359 str = (*env)->NewObject(env, cls, mid, ary, enc); 1360 } else { 1361 /*If the encoding specified in sun.jnu.encoding is not 1362 endorsed by "Charset.isSupported" we have to fall back 1363 to use String(byte[]) explicitly here without specifying 1364 the encoding name, in which the StringCoding class will 1365 pickup the iso-8859-1 as the fallback converter for us. 1366 */ 1367 NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String")); 1368 NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", 1369 "([B)V")); 1370 str = (*env)->NewObject(env, cls, mid, ary); 1371 } 1372 (*env)->DeleteLocalRef(env, ary); 1373 return str; 1374 } 1375 } 1376 return 0; 1377 } 1378 1379 /* 1380 * Returns a new array of Java string objects for the specified 1381 * array of platform strings. 1382 */ 1383 static jobjectArray 1384 NewPlatformStringArray(JNIEnv *env, char **strv, int strc) 1385 { 1386 jarray cls; 1387 jarray ary; 1388 int i; 1389 1390 NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String")); 1391 NULL_CHECK0(ary = (*env)->NewObjectArray(env, strc, cls, 0)); 1392 for (i = 0; i < strc; i++) { 1393 jstring str = NewPlatformString(env, *strv++); 1394 NULL_CHECK0(str); 1395 (*env)->SetObjectArrayElement(env, ary, i, str); 1396 (*env)->DeleteLocalRef(env, str); 1397 } 1398 return ary; 1399 } 1400 1401 /* 1402 * Loads a class, convert the '.' to '/'. 1403 */ 1404 static jclass 1405 LoadClass(JNIEnv *env, char *name) 1406 { 1407 char *buf = JLI_MemAlloc(strlen(name) + 1); 1408 char *s = buf, *t = name, c; 1409 jclass cls; 1410 jlong start, end; 1411 1412 if (_launcher_debug) 1413 start = CounterGet(); 1414 1415 do { 1416 c = *t++; 1417 *s++ = (c == '.') ? '/' : c; 1418 } while (c != '\0'); 1419 cls = (*env)->FindClass(env, buf); 1420 JLI_MemFree(buf); 1421 1422 if (_launcher_debug) { 1423 end = CounterGet(); 1424 printf("%ld micro seconds to load main class\n", 1425 (long)(jint)Counter2Micros(end-start)); 1426 printf("----_JAVA_LAUNCHER_DEBUG----\n"); 1427 } 1428 1429 return cls; 1430 } 1431 1432 1433 /* 1434 * Returns the main class name for the specified jar file. 1435 */ 1436 static jstring 1437 GetMainClassName(JNIEnv *env, char *jarname) 1438 { 1439 #define MAIN_CLASS "Main-Class" 1440 jclass cls; 1441 jmethodID mid; 1442 jobject jar, man, attr; 1443 jstring str, result = 0; 1444 1445 NULL_CHECK0(cls = (*env)->FindClass(env, "java/util/jar/JarFile")); 1446 NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", 1447 "(Ljava/lang/String;)V")); 1448 NULL_CHECK0(str = NewPlatformString(env, jarname)); 1449 NULL_CHECK0(jar = (*env)->NewObject(env, cls, mid, str)); 1450 NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "getManifest", 1451 "()Ljava/util/jar/Manifest;")); 1452 man = (*env)->CallObjectMethod(env, jar, mid); 1453 if (man != 0) { 1454 NULL_CHECK0(mid = (*env)->GetMethodID(env, 1455 (*env)->GetObjectClass(env, man), 1456 "getMainAttributes", 1457 "()Ljava/util/jar/Attributes;")); 1458 attr = (*env)->CallObjectMethod(env, man, mid); 1459 if (attr != 0) { 1460 NULL_CHECK0(mid = (*env)->GetMethodID(env, 1461 (*env)->GetObjectClass(env, attr), 1462 "getValue", 1463 "(Ljava/lang/String;)Ljava/lang/String;")); 1464 NULL_CHECK0(str = NewPlatformString(env, MAIN_CLASS)); 1465 result = (*env)->CallObjectMethod(env, attr, mid, str); 1466 } 1467 } 1468 return result; 1469 } 1470 1471 #ifdef JAVA_ARGS 1472 static char *java_args[] = JAVA_ARGS; 1473 static char *app_classpath[] = APP_CLASSPATH; 1474 1475 /* 1476 * For tools, convert command line args thus: 1477 * javac -cp foo:foo/"*" -J-ms32m ... 1478 * java -ms32m -cp JLI_WildcardExpandClasspath(foo:foo/"*") ... 1479 */ 1480 static void 1481 TranslateApplicationArgs(int *pargc, char ***pargv) 1482 { 1483 const int NUM_ARGS = (sizeof(java_args) / sizeof(char *)); 1484 int argc = *pargc; 1485 char **argv = *pargv; 1486 int nargc = argc + NUM_ARGS; 1487 char **nargv = JLI_MemAlloc((nargc + 1) * sizeof(char *)); 1488 int i; 1489 1490 *pargc = nargc; 1491 *pargv = nargv; 1492 1493 /* Copy the VM arguments (i.e. prefixed with -J) */ 1494 for (i = 0; i < NUM_ARGS; i++) { 1495 char *arg = java_args[i]; 1496 if (arg[0] == '-' && arg[1] == 'J') { 1497 *nargv++ = arg + 2; 1498 } 1499 } 1500 1501 for (i = 0; i < argc; i++) { 1502 char *arg = argv[i]; 1503 if (arg[0] == '-' && arg[1] == 'J') { 1504 if (arg[2] == '\0') { 1505 ReportErrorMessage("Error: the -J option should not be " 1506 "followed by a space.", JNI_TRUE); 1507 exit(1); 1508 } 1509 *nargv++ = arg + 2; 1510 } 1511 } 1512 1513 /* Copy the rest of the arguments */ 1514 for (i = 0; i < NUM_ARGS; i++) { 1515 char *arg = java_args[i]; 1516 if (arg[0] != '-' || arg[1] != 'J') { 1517 *nargv++ = arg; 1518 } 1519 } 1520 for (i = 0; i < argc; i++) { 1521 char *arg = argv[i]; 1522 if (arg[0] == '-') { 1523 if (arg[1] == 'J') 1524 continue; 1525 #ifdef EXPAND_CLASSPATH_WILDCARDS 1526 if (arg[1] == 'c' 1527 && (strcmp(arg, "-cp") == 0 || 1528 strcmp(arg, "-classpath") == 0) 1529 && i < argc - 1) { 1530 *nargv++ = arg; 1531 *nargv++ = (char *) JLI_WildcardExpandClasspath(argv[i+1]); 1532 i++; 1533 continue; 1534 } 1535 #endif 1536 } 1537 *nargv++ = arg; 1538 } 1539 *nargv = 0; 1540 } 1541 1542 /* 1543 * For our tools, we try to add 3 VM options: 1544 * -Denv.class.path=<envcp> 1545 * -Dapplication.home=<apphome> 1546 * -Djava.class.path=<appcp> 1547 * <envcp> is the user's setting of CLASSPATH -- for instance the user 1548 * tells javac where to find binary classes through this environment 1549 * variable. Notice that users will be able to compile against our 1550 * tools classes (sun.tools.javac.Main) only if they explicitly add 1551 * tools.jar to CLASSPATH. 1552 * <apphome> is the directory where the application is installed. 1553 * <appcp> is the classpath to where our apps' classfiles are. 1554 */ 1555 static jboolean 1556 AddApplicationOptions() 1557 { 1558 const int NUM_APP_CLASSPATH = (sizeof(app_classpath) / sizeof(char *)); 1559 char *envcp, *appcp, *apphome; 1560 char home[MAXPATHLEN]; /* application home */ 1561 char separator[] = { PATH_SEPARATOR, '\0' }; 1562 int size, i; 1563 int strlenHome; 1564 1565 { 1566 const char *s = getenv("CLASSPATH"); 1567 if (s) { 1568 s = (char *) JLI_WildcardExpandClasspath(s); 1569 /* 40 for -Denv.class.path= */ 1570 envcp = (char *)JLI_MemAlloc(strlen(s) + 40); 1571 sprintf(envcp, "-Denv.class.path=%s", s); 1572 AddOption(envcp, NULL); 1573 } 1574 } 1575 1576 if (!GetApplicationHome(home, sizeof(home))) { 1577 ReportErrorMessage("Can't determine application home", JNI_TRUE); 1578 return JNI_FALSE; 1579 } 1580 1581 /* 40 for '-Dapplication.home=' */ 1582 apphome = (char *)JLI_MemAlloc(strlen(home) + 40); 1583 sprintf(apphome, "-Dapplication.home=%s", home); 1584 AddOption(apphome, NULL); 1585 1586 /* How big is the application's classpath? */ 1587 size = 40; /* 40: "-Djava.class.path=" */ 1588 strlenHome = (int)strlen(home); 1589 for (i = 0; i < NUM_APP_CLASSPATH; i++) { 1590 size += strlenHome + (int)strlen(app_classpath[i]) + 1; /* 1: separator */ 1591 } 1592 appcp = (char *)JLI_MemAlloc(size + 1); 1593 strcpy(appcp, "-Djava.class.path="); 1594 for (i = 0; i < NUM_APP_CLASSPATH; i++) { 1595 strcat(appcp, home); /* c:\program files\myapp */ 1596 strcat(appcp, app_classpath[i]); /* \lib\myapp.jar */ 1597 strcat(appcp, separator); /* ; */ 1598 } 1599 appcp[strlen(appcp)-1] = '\0'; /* remove trailing path separator */ 1600 AddOption(appcp, NULL); 1601 return JNI_TRUE; 1602 } 1603 #endif /* JAVA_ARGS */ 1604 1605 /* 1606 * inject the -Dsun.java.command pseudo property into the args structure 1607 * this pseudo property is used in the HotSpot VM to expose the 1608 * Java class name and arguments to the main method to the VM. The 1609 * HotSpot VM uses this pseudo property to store the Java class name 1610 * (or jar file name) and the arguments to the class's main method 1611 * to the instrumentation memory region. The sun.java.command pseudo 1612 * property is not exported by HotSpot to the Java layer. 1613 */ 1614 void 1615 SetJavaCommandLineProp(char *classname, char *jarfile, 1616 int argc, char **argv) 1617 { 1618 1619 int i = 0; 1620 size_t len = 0; 1621 char* javaCommand = NULL; 1622 char* dashDstr = "-Dsun.java.command="; 1623 1624 if (classname == NULL && jarfile == NULL) { 1625 /* unexpected, one of these should be set. just return without 1626 * setting the property 1627 */ 1628 return; 1629 } 1630 1631 /* if the class name is not set, then use the jarfile name */ 1632 if (classname == NULL) { 1633 classname = jarfile; 1634 } 1635 1636 /* determine the amount of memory to allocate assuming 1637 * the individual components will be space separated 1638 */ 1639 len = strlen(classname); 1640 for (i = 0; i < argc; i++) { 1641 len += strlen(argv[i]) + 1; 1642 } 1643 1644 /* allocate the memory */ 1645 javaCommand = (char*) JLI_MemAlloc(len + strlen(dashDstr) + 1); 1646 1647 /* build the -D string */ 1648 *javaCommand = '\0'; 1649 strcat(javaCommand, dashDstr); 1650 strcat(javaCommand, classname); 1651 1652 for (i = 0; i < argc; i++) { 1653 /* the components of the string are space separated. In 1654 * the case of embedded white space, the relationship of 1655 * the white space separated components to their true 1656 * positional arguments will be ambiguous. This issue may 1657 * be addressed in a future release. 1658 */ 1659 strcat(javaCommand, " "); 1660 strcat(javaCommand, argv[i]); 1661 } 1662 1663 AddOption(javaCommand, NULL); 1664 } 1665 1666 /* 1667 * JVM would like to know if it's created by a standard Sun launcher, or by 1668 * user native application, the following property indicates the former. 1669 */ 1670 #ifdef GAMMA 1671 void SetJavaLauncherProp() { 1672 AddOption("-Dsun.java.launcher=" LAUNCHER_TYPE, NULL); 1673 } 1674 #endif 1675 1676 /* 1677 * Prints the version information from the java.version and other properties. 1678 */ 1679 static void 1680 PrintJavaVersion(JNIEnv *env) 1681 { 1682 jclass ver; 1683 jmethodID print; 1684 1685 NULL_CHECK(ver = (*env)->FindClass(env, "sun/misc/Version")); 1686 NULL_CHECK(print = (*env)->GetStaticMethodID(env, ver, "print", "()V")); 1687 1688 (*env)->CallStaticVoidMethod(env, ver, print); 1689 } 1690 1691 /* 1692 * Prints default usage message. 1693 */ 1694 static void 1695 PrintUsage(void) 1696 { 1697 #ifndef GAMMA 1698 int i; 1699 #endif 1700 1701 fprintf(stdout, 1702 "Usage: %s [-options] class [args...]\n" 1703 " (to execute a class)\n" 1704 " or %s [-options] -jar jarfile [args...]\n" 1705 " (to execute a jar file)\n" 1706 "\n" 1707 "where options include:\n", 1708 progname, 1709 progname); 1710 1711 #ifndef GAMMA 1712 PrintMachineDependentOptions(); 1713 1714 if ((knownVMs[0].flag == VM_KNOWN) || 1715 (knownVMs[0].flag == VM_IF_SERVER_CLASS)) { 1716 fprintf(stdout, " %s\t to select the \"%s\" VM\n", 1717 knownVMs[0].name, knownVMs[0].name+1); 1718 } 1719 for (i=1; i<knownVMsCount; i++) { 1720 if (knownVMs[i].flag == VM_KNOWN) 1721 fprintf(stdout, " %s\t to select the \"%s\" VM\n", 1722 knownVMs[i].name, knownVMs[i].name+1); 1723 } 1724 for (i=1; i<knownVMsCount; i++) { 1725 if (knownVMs[i].flag == VM_ALIASED_TO) 1726 fprintf(stdout, " %s\t is a synonym for " 1727 "the \"%s\" VM [deprecated]\n", 1728 knownVMs[i].name, knownVMs[i].alias+1); 1729 } 1730 /* The first known VM is the default */ 1731 { 1732 const char* defaultVM = knownVMs[0].name+1; 1733 const char* punctuation = "."; 1734 const char* reason = ""; 1735 if ((knownVMs[0].flag == VM_IF_SERVER_CLASS) && 1736 (ServerClassMachine() == JNI_TRUE)) { 1737 defaultVM = knownVMs[0].server_class+1; 1738 punctuation = ", "; 1739 reason = "because you are running on a server-class machine.\n"; 1740 } 1741 fprintf(stdout, " The default VM is %s%s\n", 1742 defaultVM, punctuation); 1743 fprintf(stdout, " %s\n", 1744 reason); 1745 } 1746 #endif /* ifndef GAMMA */ 1747 1748 fprintf(stdout, 1749 " -cp <class search path of directories and zip/jar files>\n" 1750 " -classpath <class search path of directories and zip/jar files>\n" 1751 " A %c separated list of directories, JAR archives,\n" 1752 " and ZIP archives to search for class files.\n" 1753 " -D<name>=<value>\n" 1754 " set a system property\n" 1755 " -verbose[:class|gc|jni]\n" 1756 " enable verbose output\n" 1757 " -version print product version and exit\n" 1758 " -version:<value>\n" 1759 " require the specified version to run\n" 1760 " -showversion print product version and continue\n" 1761 " -jre-restrict-search | -jre-no-restrict-search\n" 1762 " include/exclude user private JREs in the version search\n" 1763 " -? -help print this help message\n" 1764 " -X print help on non-standard options\n" 1765 " -ea[:<packagename>...|:<classname>]\n" 1766 " -enableassertions[:<packagename>...|:<classname>]\n" 1767 " enable assertions\n" 1768 " -da[:<packagename>...|:<classname>]\n" 1769 " -disableassertions[:<packagename>...|:<classname>]\n" 1770 " disable assertions\n" 1771 " -esa | -enablesystemassertions\n" 1772 " enable system assertions\n" 1773 " -dsa | -disablesystemassertions\n" 1774 " disable system assertions\n" 1775 " -agentlib:<libname>[=<options>]\n" 1776 " load native agent library <libname>, e.g. -agentlib:hprof\n" 1777 " see also, -agentlib:jdwp=help and -agentlib:hprof=help\n" 1778 " -agentpath:<pathname>[=<options>]\n" 1779 " load native agent library by full pathname\n" 1780 " -javaagent:<jarpath>[=<options>]\n" 1781 " load Java programming language agent, see java.lang.instrument\n" 1782 " -splash:<imagepath>\n" 1783 " show splash screen with specified image\n" 1784 1785 ,PATH_SEPARATOR); 1786 } 1787 1788 /* 1789 * Print usage message for -X options. 1790 */ 1791 static jint 1792 PrintXUsage(const char *jvmpath) 1793 { 1794 /* 1795 A 32 bit cushion to prevent buffer overrun, noting that 1796 fopen(3C) may fail if the buffer exceeds MAXPATHLEN. 1797 */ 1798 char path[MAXPATHLEN+32]; 1799 char buf[128]; 1800 size_t n; 1801 FILE *fp; 1802 static const char Xusage_txt[] = "/Xusage.txt"; 1803 1804 strcpy(path, jvmpath); 1805 /* Note the FILE_SEPARATOR is platform dependent */ 1806 strcpy(strrchr(path, FILE_SEPARATOR), Xusage_txt); 1807 fp = fopen(path, "r"); 1808 if (fp == 0) { 1809 fprintf(stderr, "Can't open %s\n", path); 1810 return 1; 1811 } 1812 while ((n = fread(buf, 1, sizeof(buf), fp)) != 0) { 1813 fwrite(buf, 1, n, stdout); 1814 } 1815 fclose(fp); 1816 return 0; 1817 } 1818 1819 #ifndef GAMMA 1820 1821 /* 1822 * Read the jvm.cfg file and fill the knownJVMs[] array. 1823 * 1824 * The functionality of the jvm.cfg file is subject to change without 1825 * notice and the mechanism will be removed in the future. 1826 * 1827 * The lexical structure of the jvm.cfg file is as follows: 1828 * 1829 * jvmcfg := { vmLine } 1830 * vmLine := knownLine 1831 * | aliasLine 1832 * | warnLine 1833 * | ignoreLine 1834 * | errorLine 1835 * | predicateLine 1836 * | commentLine 1837 * knownLine := flag "KNOWN" EOL 1838 * warnLine := flag "WARN" EOL 1839 * ignoreLine := flag "IGNORE" EOL 1840 * errorLine := flag "ERROR" EOL 1841 * aliasLine := flag "ALIASED_TO" flag EOL 1842 * predicateLine := flag "IF_SERVER_CLASS" flag EOL 1843 * commentLine := "#" text EOL 1844 * flag := "-" identifier 1845 * 1846 * The semantics are that when someone specifies a flag on the command line: 1847 * - if the flag appears on a knownLine, then the identifier is used as 1848 * the name of the directory holding the JVM library (the name of the JVM). 1849 * - if the flag appears as the first flag on an aliasLine, the identifier 1850 * of the second flag is used as the name of the JVM. 1851 * - if the flag appears on a warnLine, the identifier is used as the 1852 * name of the JVM, but a warning is generated. 1853 * - if the flag appears on an ignoreLine, the identifier is recognized as the 1854 * name of a JVM, but the identifier is ignored and the default vm used 1855 * - if the flag appears on an errorLine, an error is generated. 1856 * - if the flag appears as the first flag on a predicateLine, and 1857 * the machine on which you are running passes the predicate indicated, 1858 * then the identifier of the second flag is used as the name of the JVM, 1859 * otherwise the identifier of the first flag is used as the name of the JVM. 1860 * If no flag is given on the command line, the first vmLine of the jvm.cfg 1861 * file determines the name of the JVM. 1862 * PredicateLines are only interpreted on first vmLine of a jvm.cfg file, 1863 * since they only make sense if someone hasn't specified the name of the 1864 * JVM on the command line. 1865 * 1866 * The intent of the jvm.cfg file is to allow several JVM libraries to 1867 * be installed in different subdirectories of a single JRE installation, 1868 * for space-savings and convenience in testing. 1869 * The intent is explicitly not to provide a full aliasing or predicate 1870 * mechanism. 1871 */ 1872 jint 1873 ReadKnownVMs(const char *jrepath, char * arch, jboolean speculative) 1874 { 1875 FILE *jvmCfg; 1876 char jvmCfgName[MAXPATHLEN+20]; 1877 char line[MAXPATHLEN+20]; 1878 int cnt = 0; 1879 int lineno = 0; 1880 jlong start, end; 1881 int vmType; 1882 char *tmpPtr; 1883 char *altVMName = NULL; 1884 char *serverClassVMName = NULL; 1885 static char *whiteSpace = " \t"; 1886 if (_launcher_debug) { 1887 start = CounterGet(); 1888 } 1889 1890 strcpy(jvmCfgName, jrepath); 1891 strcat(jvmCfgName, FILESEP "lib" FILESEP); 1892 strcat(jvmCfgName, arch); 1893 strcat(jvmCfgName, FILESEP "jvm.cfg"); 1894 1895 jvmCfg = fopen(jvmCfgName, "r"); 1896 if (jvmCfg == NULL) { 1897 if (!speculative) { 1898 ReportErrorMessage2("Error: could not open `%s'", jvmCfgName, 1899 JNI_TRUE); 1900 exit(1); 1901 } else { 1902 return -1; 1903 } 1904 } 1905 while (fgets(line, sizeof(line), jvmCfg) != NULL) { 1906 vmType = VM_UNKNOWN; 1907 lineno++; 1908 if (line[0] == '#') 1909 continue; 1910 if (line[0] != '-') { 1911 fprintf(stderr, "Warning: no leading - on line %d of `%s'\n", 1912 lineno, jvmCfgName); 1913 } 1914 if (cnt >= knownVMsLimit) { 1915 GrowKnownVMs(cnt); 1916 } 1917 line[strlen(line)-1] = '\0'; /* remove trailing newline */ 1918 tmpPtr = line + strcspn(line, whiteSpace); 1919 if (*tmpPtr == 0) { 1920 fprintf(stderr, "Warning: missing VM type on line %d of `%s'\n", 1921 lineno, jvmCfgName); 1922 } else { 1923 /* Null-terminate this string for JLI_StringDup below */ 1924 *tmpPtr++ = 0; 1925 tmpPtr += strspn(tmpPtr, whiteSpace); 1926 if (*tmpPtr == 0) { 1927 fprintf(stderr, "Warning: missing VM type on line %d of `%s'\n", 1928 lineno, jvmCfgName); 1929 } else { 1930 if (!strncmp(tmpPtr, "KNOWN", strlen("KNOWN"))) { 1931 vmType = VM_KNOWN; 1932 } else if (!strncmp(tmpPtr, "ALIASED_TO", strlen("ALIASED_TO"))) { 1933 tmpPtr += strcspn(tmpPtr, whiteSpace); 1934 if (*tmpPtr != 0) { 1935 tmpPtr += strspn(tmpPtr, whiteSpace); 1936 } 1937 if (*tmpPtr == 0) { 1938 fprintf(stderr, "Warning: missing VM alias on line %d of `%s'\n", 1939 lineno, jvmCfgName); 1940 } else { 1941 /* Null terminate altVMName */ 1942 altVMName = tmpPtr; 1943 tmpPtr += strcspn(tmpPtr, whiteSpace); 1944 *tmpPtr = 0; 1945 vmType = VM_ALIASED_TO; 1946 } 1947 } else if (!strncmp(tmpPtr, "WARN", strlen("WARN"))) { 1948 vmType = VM_WARN; 1949 } else if (!strncmp(tmpPtr, "IGNORE", strlen("IGNORE"))) { 1950 vmType = VM_IGNORE; 1951 } else if (!strncmp(tmpPtr, "ERROR", strlen("ERROR"))) { 1952 vmType = VM_ERROR; 1953 } else if (!strncmp(tmpPtr, 1954 "IF_SERVER_CLASS", 1955 strlen("IF_SERVER_CLASS"))) { 1956 tmpPtr += strcspn(tmpPtr, whiteSpace); 1957 if (*tmpPtr != 0) { 1958 tmpPtr += strspn(tmpPtr, whiteSpace); 1959 } 1960 if (*tmpPtr == 0) { 1961 fprintf(stderr, "Warning: missing server class VM on line %d of `%s'\n", 1962 lineno, jvmCfgName); 1963 } else { 1964 /* Null terminate server class VM name */ 1965 serverClassVMName = tmpPtr; 1966 tmpPtr += strcspn(tmpPtr, whiteSpace); 1967 *tmpPtr = 0; 1968 vmType = VM_IF_SERVER_CLASS; 1969 } 1970 } else { 1971 fprintf(stderr, "Warning: unknown VM type on line %d of `%s'\n", 1972 lineno, &jvmCfgName[0]); 1973 vmType = VM_KNOWN; 1974 } 1975 } 1976 } 1977 1978 if (_launcher_debug) 1979 printf("jvm.cfg[%d] = ->%s<-\n", cnt, line); 1980 if (vmType != VM_UNKNOWN) { 1981 knownVMs[cnt].name = JLI_StringDup(line); 1982 knownVMs[cnt].flag = vmType; 1983 switch (vmType) { 1984 default: 1985 break; 1986 case VM_ALIASED_TO: 1987 knownVMs[cnt].alias = JLI_StringDup(altVMName); 1988 if (_launcher_debug) { 1989 printf(" name: %s vmType: %s alias: %s\n", 1990 knownVMs[cnt].name, "VM_ALIASED_TO", knownVMs[cnt].alias); 1991 } 1992 break; 1993 case VM_IF_SERVER_CLASS: 1994 knownVMs[cnt].server_class = JLI_StringDup(serverClassVMName); 1995 if (_launcher_debug) { 1996 printf(" name: %s vmType: %s server_class: %s\n", 1997 knownVMs[cnt].name, "VM_IF_SERVER_CLASS", knownVMs[cnt].server_class); 1998 } 1999 break; 2000 } 2001 cnt++; 2002 } 2003 } 2004 fclose(jvmCfg); 2005 knownVMsCount = cnt; 2006 2007 if (_launcher_debug) { 2008 end = CounterGet(); 2009 printf("%ld micro seconds to parse jvm.cfg\n", 2010 (long)(jint)Counter2Micros(end-start)); 2011 } 2012 2013 return cnt; 2014 } 2015 2016 2017 static void 2018 GrowKnownVMs(int minimum) 2019 { 2020 struct vmdesc* newKnownVMs; 2021 int newMax; 2022 2023 newMax = (knownVMsLimit == 0 ? INIT_MAX_KNOWN_VMS : (2 * knownVMsLimit)); 2024 if (newMax <= minimum) { 2025 newMax = minimum; 2026 } 2027 newKnownVMs = (struct vmdesc*) JLI_MemAlloc(newMax * sizeof(struct vmdesc)); 2028 if (knownVMs != NULL) { 2029 memcpy(newKnownVMs, knownVMs, knownVMsLimit * sizeof(struct vmdesc)); 2030 } 2031 JLI_MemFree(knownVMs); 2032 knownVMs = newKnownVMs; 2033 knownVMsLimit = newMax; 2034 } 2035 2036 2037 /* Returns index of VM or -1 if not found */ 2038 static int 2039 KnownVMIndex(const char* name) 2040 { 2041 int i; 2042 if (strncmp(name, "-J", 2) == 0) name += 2; 2043 for (i = 0; i < knownVMsCount; i++) { 2044 if (!strcmp(name, knownVMs[i].name)) { 2045 return i; 2046 } 2047 } 2048 return -1; 2049 } 2050 2051 static void 2052 FreeKnownVMs() 2053 { 2054 int i; 2055 for (i = 0; i < knownVMsCount; i++) { 2056 JLI_MemFree(knownVMs[i].name); 2057 knownVMs[i].name = NULL; 2058 } 2059 JLI_MemFree(knownVMs); 2060 } 2061 2062 2063 /* 2064 * Displays the splash screen according to the jar file name 2065 * and image file names stored in environment variables 2066 */ 2067 static void 2068 ShowSplashScreen() 2069 { 2070 const char *jar_name = getenv(SPLASH_JAR_ENV_ENTRY); 2071 const char *file_name = getenv(SPLASH_FILE_ENV_ENTRY); 2072 int data_size; 2073 void *image_data; 2074 if (jar_name) { 2075 image_data = JLI_JarUnpackFile(jar_name, file_name, &data_size); 2076 if (image_data) { 2077 DoSplashInit(); 2078 DoSplashLoadMemory(image_data, data_size); 2079 JLI_MemFree(image_data); 2080 } 2081 } else if (file_name) { 2082 DoSplashInit(); 2083 DoSplashLoadFile(file_name); 2084 } else { 2085 return; 2086 } 2087 DoSplashSetFileJarName(file_name, jar_name); 2088 } 2089 2090 #endif /* ifndef GAMMA */