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