1/* Execute a Java program. 2 Copyright (C) 2001-2003 Free Software Foundation, Inc. 3 Written by Bruno Haible <haible@clisp.cons.org>, 2001. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2, or (at your option) 8 any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software Foundation, 17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 18 19#ifdef HAVE_CONFIG_H 20# include <config.h> 21#endif 22#include <alloca.h> 23 24/* Specification. */ 25#include "javaexec.h" 26 27#include <stdio.h> 28#include <stdlib.h> 29#include <string.h> 30 31#include "execute.h" 32#include "classpath.h" 33#include "xsetenv.h" 34#include "sh-quote.h" 35#include "pathname.h" 36#include "xalloc.h" 37#include "xallocsa.h" 38#include "error.h" 39#include "gettext.h" 40 41#define _(str) gettext (str) 42 43 44/* Survey of Java virtual machines. 45 46 A = does it work without CLASSPATH being set 47 B = does it work with CLASSPATH being set to empty 48 C = option to set CLASSPATH, other than setting it in the environment 49 T = test for presence 50 51 Program from A B C T 52 53 $JAVA unknown N Y n/a true 54 gij GCC 3.0 Y Y n/a gij --version >/dev/null 55 java JDK 1.1.8 Y Y -classpath P java -version 2>/dev/null 56 jre JDK 1.1.8 N Y -classpath P jre 2>/dev/null; test $? = 1 57 java JDK 1.3.0 Y Y -classpath P java -version 2>/dev/null 58 jview MS IE Y Y -cp P jview -? >nul; %errorlevel% = 1 59 60 The CLASSPATH is a colon separated list of pathnames. (On Windows: a 61 semicolon separated list of pathnames.) 62 63 We try the Java virtual machines in the following order: 64 1. getenv ("JAVA"), because the user must be able to override our 65 preferences, 66 2. "gij", because it is a completely free JVM, 67 3. "java", because it is a standard JVM, 68 4. "jre", comes last because it requires a CLASSPATH environment variable, 69 5. "jview", on Windows only, because it is frequently installed. 70 71 We unset the JAVA_HOME environment variable, because a wrong setting of 72 this variable can confuse the JDK's javac. 73 */ 74 75bool 76execute_java_class (const char *class_name, 77 const char * const *classpaths, 78 unsigned int classpaths_count, 79 bool use_minimal_classpath, 80 const char *exe_dir, 81 const char * const *args, 82 bool verbose, bool quiet, 83 execute_fn *executer, void *private_data) 84{ 85 bool err = false; 86 unsigned int nargs; 87 char *old_JAVA_HOME; 88 89 /* Count args. */ 90 { 91 const char * const *arg; 92 93 for (nargs = 0, arg = args; *arg != NULL; nargs++, arg++) 94 ; 95 } 96 97 /* First, try a class compiled to a native code executable. */ 98 if (exe_dir != NULL) 99 { 100 char *exe_pathname = concatenated_pathname (exe_dir, class_name, EXEEXT); 101 char *old_classpath; 102 char **argv = (char **) xallocsa ((1 + nargs + 1) * sizeof (char *)); 103 unsigned int i; 104 105 /* Set CLASSPATH. */ 106 old_classpath = 107 set_classpath (classpaths, classpaths_count, use_minimal_classpath, 108 verbose); 109 110 argv[0] = exe_pathname; 111 for (i = 0; i <= nargs; i++) 112 argv[1 + i] = (char *) args[i]; 113 114 if (verbose) 115 { 116 char *command = shell_quote_argv (argv); 117 printf ("%s\n", command); 118 free (command); 119 } 120 121 err = executer (class_name, exe_pathname, argv, private_data); 122 123 /* Reset CLASSPATH. */ 124 reset_classpath (old_classpath); 125 126 freesa (argv); 127 128 goto done1; 129 } 130 131 { 132 const char *java = getenv ("JAVA"); 133 if (java != NULL && java[0] != '\0') 134 { 135 /* Because $JAVA may consist of a command and options, we use the 136 shell. Because $JAVA has been set by the user, we leave all 137 all environment variables in place, including JAVA_HOME, and 138 we don't erase the user's CLASSPATH. */ 139 char *old_classpath; 140 unsigned int command_length; 141 char *command; 142 char *argv[4]; 143 const char * const *arg; 144 char *p; 145 146 /* Set CLASSPATH. */ 147 old_classpath = 148 set_classpath (classpaths, classpaths_count, false, 149 verbose); 150 151 command_length = strlen (java); 152 command_length += 1 + shell_quote_length (class_name); 153 for (arg = args; *arg != NULL; arg++) 154 command_length += 1 + shell_quote_length (*arg); 155 command_length += 1; 156 157 command = (char *) xallocsa (command_length); 158 p = command; 159 /* Don't shell_quote $JAVA, because it may consist of a command 160 and options. */ 161 memcpy (p, java, strlen (java)); 162 p += strlen (java); 163 *p++ = ' '; 164 p = shell_quote_copy (p, class_name); 165 for (arg = args; *arg != NULL; arg++) 166 { 167 *p++ = ' '; 168 p = shell_quote_copy (p, *arg); 169 } 170 *p++ = '\0'; 171 /* Ensure command_length was correctly calculated. */ 172 if (p - command > command_length) 173 abort (); 174 175 if (verbose) 176 printf ("%s\n", command); 177 178 argv[0] = "/bin/sh"; 179 argv[1] = "-c"; 180 argv[2] = command; 181 argv[3] = NULL; 182 err = executer (java, "/bin/sh", argv, private_data); 183 184 freesa (command); 185 186 /* Reset CLASSPATH. */ 187 reset_classpath (old_classpath); 188 189 goto done1; 190 } 191 } 192 193 /* Unset the JAVA_HOME environment variable. */ 194 old_JAVA_HOME = getenv ("JAVA_HOME"); 195 if (old_JAVA_HOME != NULL) 196 { 197 old_JAVA_HOME = xstrdup (old_JAVA_HOME); 198 unsetenv ("JAVA_HOME"); 199 } 200 201 { 202 static bool gij_tested; 203 static bool gij_present; 204 205 if (!gij_tested) 206 { 207 /* Test for presence of gij: "gij --version > /dev/null" */ 208 char *argv[3]; 209 int exitstatus; 210 211 argv[0] = "gij"; 212 argv[1] = "--version"; 213 argv[2] = NULL; 214 exitstatus = execute ("gij", "gij", argv, false, false, true, true, 215 true, false); 216 gij_present = (exitstatus == 0); 217 gij_tested = true; 218 } 219 220 if (gij_present) 221 { 222 char *old_classpath; 223 char **argv = (char **) xallocsa ((2 + nargs + 1) * sizeof (char *)); 224 unsigned int i; 225 226 /* Set CLASSPATH. */ 227 old_classpath = 228 set_classpath (classpaths, classpaths_count, use_minimal_classpath, 229 verbose); 230 231 argv[0] = "gij"; 232 argv[1] = (char *) class_name; 233 for (i = 0; i <= nargs; i++) 234 argv[2 + i] = (char *) args[i]; 235 236 if (verbose) 237 { 238 char *command = shell_quote_argv (argv); 239 printf ("%s\n", command); 240 free (command); 241 } 242 243 err = executer ("gij", "gij", argv, private_data); 244 245 /* Reset CLASSPATH. */ 246 reset_classpath (old_classpath); 247 248 freesa (argv); 249 250 goto done2; 251 } 252 } 253 254 { 255 static bool java_tested; 256 static bool java_present; 257 258 if (!java_tested) 259 { 260 /* Test for presence of java: "java -version 2> /dev/null" */ 261 char *argv[3]; 262 int exitstatus; 263 264 argv[0] = "java"; 265 argv[1] = "-version"; 266 argv[2] = NULL; 267 exitstatus = execute ("java", "java", argv, false, false, true, true, 268 true, false); 269 java_present = (exitstatus == 0); 270 java_tested = true; 271 } 272 273 if (java_present) 274 { 275 char *old_classpath; 276 char **argv = (char **) xallocsa ((2 + nargs + 1) * sizeof (char *)); 277 unsigned int i; 278 279 /* Set CLASSPATH. We don't use the "-classpath ..." option because 280 in JDK 1.1.x its argument should also contain the JDK's classes.zip, 281 but we don't know its location. (In JDK 1.3.0 it would work.) */ 282 old_classpath = 283 set_classpath (classpaths, classpaths_count, use_minimal_classpath, 284 verbose); 285 286 argv[0] = "java"; 287 argv[1] = (char *) class_name; 288 for (i = 0; i <= nargs; i++) 289 argv[2 + i] = (char *) args[i]; 290 291 if (verbose) 292 { 293 char *command = shell_quote_argv (argv); 294 printf ("%s\n", command); 295 free (command); 296 } 297 298 err = executer ("java", "java", argv, private_data); 299 300 /* Reset CLASSPATH. */ 301 reset_classpath (old_classpath); 302 303 freesa (argv); 304 305 goto done2; 306 } 307 } 308 309 { 310 static bool jre_tested; 311 static bool jre_present; 312 313 if (!jre_tested) 314 { 315 /* Test for presence of jre: "jre 2> /dev/null ; test $? = 1" */ 316 char *argv[2]; 317 int exitstatus; 318 319 argv[0] = "jre"; 320 argv[1] = NULL; 321 exitstatus = execute ("jre", "jre", argv, false, false, true, true, 322 true, false); 323 jre_present = (exitstatus == 0 || exitstatus == 1); 324 jre_tested = true; 325 } 326 327 if (jre_present) 328 { 329 char *old_classpath; 330 char **argv = (char **) xallocsa ((2 + nargs + 1) * sizeof (char *)); 331 unsigned int i; 332 333 /* Set CLASSPATH. We don't use the "-classpath ..." option because 334 in JDK 1.1.x its argument should also contain the JDK's classes.zip, 335 but we don't know its location. */ 336 old_classpath = 337 set_classpath (classpaths, classpaths_count, use_minimal_classpath, 338 verbose); 339 340 argv[0] = "jre"; 341 argv[1] = (char *) class_name; 342 for (i = 0; i <= nargs; i++) 343 argv[2 + i] = (char *) args[i]; 344 345 if (verbose) 346 { 347 char *command = shell_quote_argv (argv); 348 printf ("%s\n", command); 349 free (command); 350 } 351 352 err = executer ("jre", "jre", argv, private_data); 353 354 /* Reset CLASSPATH. */ 355 reset_classpath (old_classpath); 356 357 freesa (argv); 358 359 goto done2; 360 } 361 } 362 363#if defined _WIN32 || defined __WIN32__ 364 /* Win32 */ 365 { 366 static bool jview_tested; 367 static bool jview_present; 368 369 if (!jview_tested) 370 { 371 /* Test for presence of jview: "jview -? >nul ; test $? = 1" */ 372 char *argv[3]; 373 int exitstatus; 374 375 argv[0] = "jview"; 376 argv[1] = "-?"; 377 argv[2] = NULL; 378 exitstatus = execute ("jview", "jview", argv, false, false, true, true, 379 true, false); 380 jview_present = (exitstatus == 0 || exitstatus == 1); 381 jview_tested = true; 382 } 383 384 if (jview_present) 385 { 386 char *old_classpath; 387 char **argv = (char **) xallocsa ((2 + nargs + 1) * sizeof (char *)); 388 unsigned int i; 389 390 /* Set CLASSPATH. */ 391 old_classpath = 392 set_classpath (classpaths, classpaths_count, use_minimal_classpath, 393 verbose); 394 395 argv[0] = "jview"; 396 argv[1] = (char *) class_name; 397 for (i = 0; i <= nargs; i++) 398 argv[2 + i] = (char *) args[i]; 399 400 if (verbose) 401 { 402 char *command = shell_quote_argv (argv); 403 printf ("%s\n", command); 404 free (command); 405 } 406 407 err = executer ("jview", "jview", argv, private_data); 408 409 /* Reset CLASSPATH. */ 410 reset_classpath (old_classpath); 411 412 freesa (argv); 413 414 goto done2; 415 } 416 } 417#endif 418 419 if (!quiet) 420 error (0, 0, _("Java virtual machine not found, try installing gij or set $JAVA")); 421 err = true; 422 423 done2: 424 if (old_JAVA_HOME != NULL) 425 { 426 xsetenv ("JAVA_HOME", old_JAVA_HOME, 1); 427 free (old_JAVA_HOME); 428 } 429 430 done1: 431 return err; 432} 433