(root)/
gettext-0.22.4/
gettext-tools/
gnulib-lib/
javaexec.c
       1  /* Execute a Java program.
       2     Copyright (C) 2001-2003, 2006-2023 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 3 of the License, or
       8     (at your option) 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, see <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <config.h>
      19  #include <alloca.h>
      20  
      21  /* Specification.  */
      22  #include "javaexec.h"
      23  
      24  #include <stdio.h>
      25  #include <stdlib.h>
      26  #include <string.h>
      27  
      28  #include "execute.h"
      29  #include "classpath.h"
      30  #include "xsetenv.h"
      31  #include "sh-quote.h"
      32  #include "concat-filename.h"
      33  #include "xalloc.h"
      34  #include "xmalloca.h"
      35  #include "error.h"
      36  #include "gettext.h"
      37  
      38  #define _(str) gettext (str)
      39  
      40  
      41  /* Survey of Java virtual machines.
      42  
      43     A = does it work without CLASSPATH being set
      44     B = does it work with CLASSPATH being set to empty
      45     C = option to set CLASSPATH, other than setting it in the environment
      46     T = test for presence
      47  
      48     Program    from         A B  C              T
      49  
      50     $JAVA      unknown      N Y  n/a            true
      51     java       JDK 1.1.8    Y Y  -classpath P   java -version 2>/dev/null
      52     jre        JDK 1.1.8    N Y  -classpath P   jre 2>/dev/null; test $? = 1
      53     java       JDK 1.3.0    Y Y  -classpath P   java -version 2>/dev/null
      54  
      55     The CLASSPATH is a colon separated list of pathnames. (On Windows: a
      56     semicolon separated list of pathnames.)
      57  
      58     We try the Java virtual machines in the following order:
      59       1. getenv ("JAVA"), because the user must be able to override our
      60          preferences,
      61       2. "java", because it is a standard JVM,
      62       3. "jre", comes last because it requires a CLASSPATH environment variable.
      63  
      64     We unset the JAVA_HOME environment variable, because a wrong setting of
      65     this variable can confuse the JDK's javac.
      66   */
      67  
      68  bool
      69  execute_java_class (const char *class_name,
      70                      const char * const *classpaths,
      71                      unsigned int classpaths_count,
      72                      bool use_minimal_classpath,
      73                      const char *exe_dir,
      74                      const char * const *args,
      75                      bool verbose, bool quiet,
      76                      execute_fn *executer, void *private_data)
      77  {
      78    bool err = false;
      79    unsigned int nargs;
      80    char *old_JAVA_HOME;
      81  
      82    /* Count args.  */
      83    {
      84      const char * const *arg;
      85  
      86      for (nargs = 0, arg = args; *arg != NULL; nargs++, arg++)
      87       ;
      88    }
      89  
      90    /* First, try a class compiled to a native code executable.  */
      91    if (exe_dir != NULL)
      92      {
      93        char *exe_pathname = xconcatenated_filename (exe_dir, class_name, EXEEXT);
      94        char *old_classpath;
      95        const char **argv =
      96          (const char **) xmalloca ((1 + nargs + 1) * sizeof (const char *));
      97        unsigned int i;
      98  
      99        /* Set CLASSPATH.  */
     100        old_classpath =
     101          set_classpath (classpaths, classpaths_count, use_minimal_classpath,
     102                         verbose);
     103  
     104        argv[0] = exe_pathname;
     105        for (i = 0; i <= nargs; i++)
     106          argv[1 + i] = args[i];
     107  
     108        if (verbose)
     109          {
     110            char *command = shell_quote_argv (argv);
     111            printf ("%s\n", command);
     112            free (command);
     113          }
     114  
     115        err = executer (class_name, exe_pathname, argv, private_data);
     116  
     117        /* Reset CLASSPATH.  */
     118        reset_classpath (old_classpath);
     119  
     120        freea (argv);
     121  
     122        goto done1;
     123      }
     124  
     125    {
     126      const char *java = getenv ("JAVA");
     127      if (java != NULL && java[0] != '\0')
     128        {
     129          /* Because $JAVA may consist of a command and options, we use the
     130             shell.  Because $JAVA has been set by the user, we leave all
     131             all environment variables in place, including JAVA_HOME, and
     132             we don't erase the user's CLASSPATH.  */
     133          char *old_classpath;
     134          unsigned int command_length;
     135          char *command;
     136          const char *argv[4];
     137          const char * const *arg;
     138          char *p;
     139  
     140          /* Set CLASSPATH.  */
     141          old_classpath =
     142            set_classpath (classpaths, classpaths_count, false,
     143                           verbose);
     144  
     145          command_length = strlen (java);
     146          command_length += 1 + shell_quote_length (class_name);
     147          for (arg = args; *arg != NULL; arg++)
     148            command_length += 1 + shell_quote_length (*arg);
     149          command_length += 1;
     150  
     151          command = (char *) xmalloca (command_length);
     152          p = command;
     153          /* Don't shell_quote $JAVA, because it may consist of a command
     154             and options.  */
     155          memcpy (p, java, strlen (java));
     156          p += strlen (java);
     157          *p++ = ' ';
     158          p = shell_quote_copy (p, class_name);
     159          for (arg = args; *arg != NULL; arg++)
     160            {
     161              *p++ = ' ';
     162              p = shell_quote_copy (p, *arg);
     163            }
     164          *p++ = '\0';
     165          /* Ensure command_length was correctly calculated.  */
     166          if (p - command > command_length)
     167            abort ();
     168  
     169          if (verbose)
     170            printf ("%s\n", command);
     171  
     172          argv[0] = BOURNE_SHELL;
     173          argv[1] = "-c";
     174          argv[2] = command;
     175          argv[3] = NULL;
     176          err = executer (java, BOURNE_SHELL, argv, private_data);
     177  
     178          freea (command);
     179  
     180          /* Reset CLASSPATH.  */
     181          reset_classpath (old_classpath);
     182  
     183          goto done1;
     184        }
     185    }
     186  
     187    /* Unset the JAVA_HOME environment variable.  */
     188    old_JAVA_HOME = getenv ("JAVA_HOME");
     189    if (old_JAVA_HOME != NULL)
     190      {
     191        old_JAVA_HOME = xstrdup (old_JAVA_HOME);
     192        unsetenv ("JAVA_HOME");
     193      }
     194  
     195    {
     196      static bool java_tested;
     197      static bool java_present;
     198  
     199      if (!java_tested)
     200        {
     201          /* Test for presence of java: "java -version 2> /dev/null"  */
     202          const char *argv[3];
     203          int exitstatus;
     204  
     205          argv[0] = "java";
     206          argv[1] = "-version";
     207          argv[2] = NULL;
     208          exitstatus = execute ("java", "java", argv, NULL,
     209                                false, false, true, true,
     210                                true, false, NULL);
     211          java_present = (exitstatus == 0);
     212          java_tested = true;
     213        }
     214  
     215      if (java_present)
     216        {
     217          char *old_classpath;
     218          const char **argv =
     219            (const char **) xmalloca ((2 + nargs + 1) * sizeof (const char *));
     220          unsigned int i;
     221  
     222          /* Set CLASSPATH.  We don't use the "-classpath ..." option because
     223             in JDK 1.1.x its argument should also contain the JDK's classes.zip,
     224             but we don't know its location.  (In JDK 1.3.0 it would work.)  */
     225          old_classpath =
     226            set_classpath (classpaths, classpaths_count, use_minimal_classpath,
     227                           verbose);
     228  
     229          argv[0] = "java";
     230          argv[1] = class_name;
     231          for (i = 0; i <= nargs; i++)
     232            argv[2 + i] = 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 ("java", "java", argv, private_data);
     242  
     243          /* Reset CLASSPATH.  */
     244          reset_classpath (old_classpath);
     245  
     246          freea (argv);
     247  
     248          goto done2;
     249        }
     250    }
     251  
     252    {
     253      static bool jre_tested;
     254      static bool jre_present;
     255  
     256      if (!jre_tested)
     257        {
     258          /* Test for presence of jre: "jre 2> /dev/null ; test $? = 1"  */
     259          const char *argv[2];
     260          int exitstatus;
     261  
     262          argv[0] = "jre";
     263          argv[1] = NULL;
     264          exitstatus = execute ("jre", "jre", argv, NULL,
     265                                false, false, true, true,
     266                                true, false, NULL);
     267          jre_present = (exitstatus == 0 || exitstatus == 1);
     268          jre_tested = true;
     269        }
     270  
     271      if (jre_present)
     272        {
     273          char *old_classpath;
     274          const char **argv =
     275            (const char **) xmalloca ((2 + nargs + 1) * sizeof (const char *));
     276          unsigned int i;
     277  
     278          /* Set CLASSPATH.  We don't use the "-classpath ..." option because
     279             in JDK 1.1.x its argument should also contain the JDK's classes.zip,
     280             but we don't know its location.  */
     281          old_classpath =
     282            set_classpath (classpaths, classpaths_count, use_minimal_classpath,
     283                           verbose);
     284  
     285          argv[0] = "jre";
     286          argv[1] = class_name;
     287          for (i = 0; i <= nargs; i++)
     288            argv[2 + i] = args[i];
     289  
     290          if (verbose)
     291            {
     292              char *command = shell_quote_argv (argv);
     293              printf ("%s\n", command);
     294              free (command);
     295            }
     296  
     297          err = executer ("jre", "jre", argv, private_data);
     298  
     299          /* Reset CLASSPATH.  */
     300          reset_classpath (old_classpath);
     301  
     302          freea (argv);
     303  
     304          goto done2;
     305        }
     306    }
     307  
     308    if (!quiet)
     309      error (0, 0, _("Java virtual machine not found, try setting $JAVA"));
     310    err = true;
     311  
     312   done2:
     313    if (old_JAVA_HOME != NULL)
     314      {
     315        xsetenv ("JAVA_HOME", old_JAVA_HOME, 1);
     316        free (old_JAVA_HOME);
     317      }
     318  
     319   done1:
     320    return err;
     321  }