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