xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/gnulib-lib/javaexec.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
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 
73 bool
execute_java_class(const char * class_name,const char * const * classpaths,unsigned int classpaths_count,bool use_minimal_classpath,const char * exe_dir,const char * const * args,bool verbose,bool quiet,execute_fn * executer,void * private_data)74 execute_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