Home | History | Annotate | Line # | Download | only in gnulib-lib
      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