root/maint/gnulib/lib/javaexec.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. execute_java_class

   1 /* Execute a Java program.
   2    Copyright (C) 2001-2003, 2006-2021 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    gij        GCC 3.0      Y Y  n/a            gij --version >/dev/null
  52    java       JDK 1.1.8    Y Y  -classpath P   java -version 2>/dev/null
  53    jre        JDK 1.1.8    N Y  -classpath P   jre 2>/dev/null; test $? = 1
  54    java       JDK 1.3.0    Y Y  -classpath P   java -version 2>/dev/null
  55    jview      MS IE        Y Y  -cp P          jview -? >nul; %errorlevel% = 1
  56 
  57    The CLASSPATH is a colon separated list of pathnames. (On Windows: a
  58    semicolon separated list of pathnames.)
  59 
  60    We try the Java virtual machines in the following order:
  61      1. getenv ("JAVA"), because the user must be able to override our
  62         preferences,
  63      2. "gij", because it is a completely free JVM,
  64      3. "java", because it is a standard JVM,
  65      4. "jre", comes last because it requires a CLASSPATH environment variable,
  66      5. "jview", on Windows only, because it is frequently installed.
  67 
  68    We unset the JAVA_HOME environment variable, because a wrong setting of
  69    this variable can confuse the JDK's javac.
  70  */
  71 
  72 bool
  73 execute_java_class (const char *class_name,
     /* [previous][next][first][last][top][bottom][index][help] */
  74                     const char * const *classpaths,
  75                     unsigned int classpaths_count,
  76                     bool use_minimal_classpath,
  77                     const char *exe_dir,
  78                     const char * const *args,
  79                     bool verbose, bool quiet,
  80                     execute_fn *executer, void *private_data)
  81 {
  82   bool err = false;
  83   unsigned int nargs;
  84   char *old_JAVA_HOME;
  85 
  86   /* Count args.  */
  87   {
  88     const char * const *arg;
  89 
  90     for (nargs = 0, arg = args; *arg != NULL; nargs++, arg++)
  91      ;
  92   }
  93 
  94   /* First, try a class compiled to a native code executable.  */
  95   if (exe_dir != NULL)
  96     {
  97       char *exe_pathname = xconcatenated_filename (exe_dir, class_name, EXEEXT);
  98       char *old_classpath;
  99       const char **argv =
 100         (const char **) xmalloca ((1 + nargs + 1) * sizeof (const 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] = 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       freea (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         const 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 *) xmalloca (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] = BOURNE_SHELL;
 177         argv[1] = "-c";
 178         argv[2] = command;
 179         argv[3] = NULL;
 180         err = executer (java, BOURNE_SHELL, argv, private_data);
 181 
 182         freea (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         const 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, NULL,
 213                               false, false, true, true,
 214                               true, false, NULL);
 215         gij_present = (exitstatus == 0);
 216         gij_tested = true;
 217       }
 218 
 219     if (gij_present)
 220       {
 221         char *old_classpath;
 222         const char **argv =
 223           (const char **) xmalloca ((2 + nargs + 1) * sizeof (const 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] = class_name;
 233         for (i = 0; i <= nargs; i++)
 234           argv[2 + i] = 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         freea (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         const 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, NULL,
 268                               false, false, true, true,
 269                               true, false, NULL);
 270         java_present = (exitstatus == 0);
 271         java_tested = true;
 272       }
 273 
 274     if (java_present)
 275       {
 276         char *old_classpath;
 277         const char **argv =
 278           (const char **) xmalloca ((2 + nargs + 1) * sizeof (const char *));
 279         unsigned int i;
 280 
 281         /* Set CLASSPATH.  We don't use the "-classpath ..." option because
 282            in JDK 1.1.x its argument should also contain the JDK's classes.zip,
 283            but we don't know its location.  (In JDK 1.3.0 it would work.)  */
 284         old_classpath =
 285           set_classpath (classpaths, classpaths_count, use_minimal_classpath,
 286                          verbose);
 287 
 288         argv[0] = "java";
 289         argv[1] = class_name;
 290         for (i = 0; i <= nargs; i++)
 291           argv[2 + i] = args[i];
 292 
 293         if (verbose)
 294           {
 295             char *command = shell_quote_argv (argv);
 296             printf ("%s\n", command);
 297             free (command);
 298           }
 299 
 300         err = executer ("java", "java", argv, private_data);
 301 
 302         /* Reset CLASSPATH.  */
 303         reset_classpath (old_classpath);
 304 
 305         freea (argv);
 306 
 307         goto done2;
 308       }
 309   }
 310 
 311   {
 312     static bool jre_tested;
 313     static bool jre_present;
 314 
 315     if (!jre_tested)
 316       {
 317         /* Test for presence of jre: "jre 2> /dev/null ; test $? = 1"  */
 318         const char *argv[2];
 319         int exitstatus;
 320 
 321         argv[0] = "jre";
 322         argv[1] = NULL;
 323         exitstatus = execute ("jre", "jre", argv, NULL,
 324                               false, false, true, true,
 325                               true, false, NULL);
 326         jre_present = (exitstatus == 0 || exitstatus == 1);
 327         jre_tested = true;
 328       }
 329 
 330     if (jre_present)
 331       {
 332         char *old_classpath;
 333         const char **argv =
 334           (const char **) xmalloca ((2 + nargs + 1) * sizeof (const char *));
 335         unsigned int i;
 336 
 337         /* Set CLASSPATH.  We don't use the "-classpath ..." option because
 338            in JDK 1.1.x its argument should also contain the JDK's classes.zip,
 339            but we don't know its location.  */
 340         old_classpath =
 341           set_classpath (classpaths, classpaths_count, use_minimal_classpath,
 342                          verbose);
 343 
 344         argv[0] = "jre";
 345         argv[1] = class_name;
 346         for (i = 0; i <= nargs; i++)
 347           argv[2 + i] = args[i];
 348 
 349         if (verbose)
 350           {
 351             char *command = shell_quote_argv (argv);
 352             printf ("%s\n", command);
 353             free (command);
 354           }
 355 
 356         err = executer ("jre", "jre", argv, private_data);
 357 
 358         /* Reset CLASSPATH.  */
 359         reset_classpath (old_classpath);
 360 
 361         freea (argv);
 362 
 363         goto done2;
 364       }
 365   }
 366 
 367 #if defined _WIN32 || defined __CYGWIN__
 368   /* Native Windows, Cygwin */
 369   {
 370     static bool jview_tested;
 371     static bool jview_present;
 372 
 373     if (!jview_tested)
 374       {
 375         /* Test for presence of jview: "jview -? >nul ; test $? = 1"  */
 376         const char *argv[3];
 377         int exitstatus;
 378 
 379         argv[0] = "jview";
 380         argv[1] = "-?";
 381         argv[2] = NULL;
 382         exitstatus = execute ("jview", "jview", argv, NULL,
 383                               false, false, true, true,
 384                               true, false, NULL);
 385         jview_present = (exitstatus == 0 || exitstatus == 1);
 386         jview_tested = true;
 387       }
 388 
 389     if (jview_present)
 390       {
 391         char *old_classpath;
 392         const char **argv =
 393           (const char **) xmalloca ((2 + nargs + 1) * sizeof (const char *));
 394         unsigned int i;
 395 
 396         /* Set CLASSPATH.  */
 397         old_classpath =
 398           set_classpath (classpaths, classpaths_count, use_minimal_classpath,
 399                          verbose);
 400 
 401         argv[0] = "jview";
 402         argv[1] = class_name;
 403         for (i = 0; i <= nargs; i++)
 404           argv[2 + i] = args[i];
 405 
 406         if (verbose)
 407           {
 408             char *command = shell_quote_argv (argv);
 409             printf ("%s\n", command);
 410             free (command);
 411           }
 412 
 413         err = executer ("jview", "jview", argv, private_data);
 414 
 415         /* Reset CLASSPATH.  */
 416         reset_classpath (old_classpath);
 417 
 418         freea (argv);
 419 
 420         goto done2;
 421       }
 422   }
 423 #endif
 424 
 425   if (!quiet)
 426     error (0, 0, _("Java virtual machine not found, try installing gij or set $JAVA"));
 427   err = true;
 428 
 429  done2:
 430   if (old_JAVA_HOME != NULL)
 431     {
 432       xsetenv ("JAVA_HOME", old_JAVA_HOME, 1);
 433       free (old_JAVA_HOME);
 434     }
 435 
 436  done1:
 437   return err;
 438 }

/* [previous][next][first][last][top][bottom][index][help] */