OSDN Git Service

* java/lang/natRuntime.cc (insertSystemProperties): Set
[pf3gnuchains/gcc-fork.git] / libjava / java / lang / natRuntime.cc
1 // natRuntime.cc - Implementation of native side of Runtime class.
2
3 /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation
4
5    This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9 details.  */
10
11 #include <config.h>
12 #include <platform.h>
13
14 #include <stdlib.h>
15
16 #include <gcj/cni.h>
17 #include <jvm.h>
18 #include <java-props.h>
19 #include <java/lang/Long.h>
20 #include <java/lang/Runtime.h>
21 #include <java/lang/UnknownError.h>
22 #include <java/lang/UnsatisfiedLinkError.h>
23 #include <gnu/gcj/runtime/FileDeleter.h>
24 #include <gnu/gcj/runtime/FinalizerThread.h>
25 #include <java/io/File.h>
26 #include <java/util/Properties.h>
27 #include <java/util/TimeZone.h>
28 #include <java/lang/StringBuffer.h>
29 #include <java/lang/Process.h>
30 #include <java/lang/ConcreteProcess.h>
31 #include <java/lang/ClassLoader.h>
32 #include <gnu/gcj/runtime/StackTrace.h>
33 #include <java/lang/ArrayIndexOutOfBoundsException.h>
34
35 #include <jni.h>
36
37 #ifdef HAVE_PWD_H
38 #include <pwd.h>
39 #endif
40 #include <errno.h>
41
42 #ifdef HAVE_UNAME
43 #include <sys/utsname.h>
44 #endif
45
46 #ifdef HAVE_LOCALE_H
47 #include <locale.h>
48 #endif
49
50 #ifdef HAVE_LANGINFO_H
51 #include <langinfo.h>
52 #endif
53
54 \f
55
56 #ifdef USE_LTDL
57 #include <ltdl.h>
58
59 /* FIXME: we don't always need this.  The next libtool will let us use
60    AC_LTDL_PREOPEN to see if we do.  */
61 extern const lt_dlsymlist lt_preloaded_symbols[1] = { { 0, 0 } };
62
63 struct lookup_data
64 {
65   const char *symname;
66   void *result;
67 };
68
69 static int
70 find_symbol (lt_dlhandle handle, lt_ptr data)
71 {
72   lookup_data *ld = (lookup_data *) data;
73   ld->result = lt_dlsym (handle, ld->symname);
74   return ld->result != NULL;
75 }
76
77 void *
78 _Jv_FindSymbolInExecutable (const char *symname)
79 {
80   lookup_data data;
81   data.symname = symname;
82   data.result = NULL;
83   lt_dlforeach (find_symbol, (lt_ptr) &data);
84   return data.result;
85 }
86
87 void
88 _Jv_SetDLLSearchPath (const char *path)
89 {
90   lt_dlsetsearchpath (path);
91 }
92
93 #else
94
95 void *
96 _Jv_FindSymbolInExecutable (const char *)
97 {
98   return NULL;
99 }
100
101 void
102 _Jv_SetDLLSearchPath (const char *)
103 {
104   // Nothing.
105 }
106
107 #endif /* USE_LTDL */
108
109 \f
110
111 void
112 java::lang::Runtime::exitInternal (jint status)
113 {
114   // Make status right for Unix.  This is perhaps strange.
115   if (status < 0 || status > 255)
116     status = 255;
117
118   if (finalizeOnExit)
119     _Jv_RunAllFinalizers ();
120
121   // Delete all files registered with File.deleteOnExit()
122   gnu::gcj::runtime::FileDeleter::deleteOnExitNow ();
123
124   ::exit (status);
125 }
126
127 jlong
128 java::lang::Runtime::freeMemory (void)
129 {
130   return _Jv_GCFreeMemory ();
131 }
132
133 void
134 java::lang::Runtime::gc (void)
135 {
136   _Jv_RunGC ();
137 }
138
139 #ifdef USE_LTDL
140 // List of names for JNI_OnLoad.
141 static const char *onload_names[] = _Jv_platform_onload_names;
142 #endif
143
144 void
145 java::lang::Runtime::_load (jstring path, jboolean do_search)
146 {
147   JvSynchronize sync (this);
148   using namespace java::lang;
149 #ifdef USE_LTDL
150   jint len = _Jv_GetStringUTFLength (path);
151   char buf[len + 1 + strlen (_Jv_platform_solib_prefix)
152            + strlen (_Jv_platform_solib_suffix)];
153   int offset = 0;
154   if (do_search)
155     {
156       strcpy (buf, _Jv_platform_solib_prefix);
157       offset = strlen (_Jv_platform_solib_prefix);
158     }
159   jsize total = JvGetStringUTFRegion (path, 0, path->length(), &buf[offset]);
160   buf[offset + total] = '\0';
161
162   char *lib_name = buf;
163
164   if (do_search)
165     {
166       ClassLoader *sys = ClassLoader::getSystemClassLoader();
167       ClassLoader *look = NULL;
168       gnu::gcj::runtime::StackTrace *t = new gnu::gcj::runtime::StackTrace(10);
169       try
170         {
171           for (int i = 0; i < 10; ++i)
172             {
173               jclass klass = t->classAt(i);
174               if (klass != NULL)
175                 {
176                   ClassLoader *loader = klass->getClassLoaderInternal();
177                   if (loader != NULL && loader != sys)
178                     {
179                       look = loader;
180                       break;
181                     }
182                 }
183             }
184         }
185       catch (::java::lang::ArrayIndexOutOfBoundsException *e)
186         {
187         }
188
189       if (look != NULL)
190         {
191           // Don't include solib prefix in string passed to
192           // findLibrary.
193           jstring name = look->findLibrary(JvNewStringUTF(&buf[offset]));
194           if (name != NULL)
195             {
196               len = _Jv_GetStringUTFLength (name);
197               lib_name = (char *) _Jv_AllocBytes(len + 1);
198               total = JvGetStringUTFRegion (name, 0,
199                                             name->length(), lib_name);
200               lib_name[total] = '\0';
201               // Don't append suffixes any more; we have the full file
202               // name.
203               do_search = false;
204             }
205         }
206     }
207
208   lt_dlhandle h;
209   // FIXME: make sure path is absolute.
210   {
211     // Synchronize on java.lang.Class. This is to protect the class chain from
212     // concurrent modification by class registration calls which may be run
213     // during the dlopen().
214     JvSynchronize sync (&java::lang::Class::class$);
215     h = do_search ? lt_dlopenext (lib_name) : lt_dlopen (lib_name);
216   }
217   if (h == NULL)
218     {
219       const char *msg = lt_dlerror ();
220       jstring str = JvNewStringLatin1 (lib_name);
221       str = str->concat (JvNewStringLatin1 (": "));
222       str = str->concat (JvNewStringLatin1 (msg));
223       throw new UnsatisfiedLinkError (str);
224     }
225
226   // Search for JNI_OnLoad function.
227   void *onload = NULL;
228   const char **name = onload_names;
229   while (*name != NULL)
230     {
231       onload = lt_dlsym (h, *name);
232       if (onload != NULL)
233         break;
234       ++name;
235     }
236
237   if (onload != NULL)
238     {
239       JavaVM *vm = _Jv_GetJavaVM ();
240       if (vm == NULL)
241         {
242           // FIXME: what?
243           return;
244         }
245       jint vers = ((jint (JNICALL *) (JavaVM *, void *)) onload) (vm, NULL);
246       if (vers != JNI_VERSION_1_1 && vers != JNI_VERSION_1_2
247           && vers != JNI_VERSION_1_4)
248         {
249           // FIXME: unload the library.
250           throw new UnsatisfiedLinkError (JvNewStringLatin1 ("unrecognized version from JNI_OnLoad"));
251         }
252     }
253 #else
254   throw new UnknownError
255     (JvNewStringLatin1 (do_search
256                         ? "Runtime.loadLibrary not implemented"
257                         : "Runtime.load not implemented"));
258 #endif /* USE_LTDL */
259 }
260
261 jboolean
262 java::lang::Runtime::loadLibraryInternal (jstring lib)
263 {
264   JvSynchronize sync (this);
265   using namespace java::lang;
266 #ifdef USE_LTDL
267   jint len = _Jv_GetStringUTFLength (lib);
268   char buf[len + 1];
269   jsize total = JvGetStringUTFRegion (lib, 0, lib->length(), buf);
270   buf[total] = '\0';
271   // FIXME: make sure path is absolute.
272   lt_dlhandle h = lt_dlopenext (buf);
273   return h != NULL;
274 #else
275   return false;
276 #endif /* USE_LTDL */
277 }
278
279 void
280 java::lang::Runtime::init (void)
281 {
282 #ifdef USE_LTDL
283   lt_dlinit ();
284   // Make sure self is opened.
285   lt_dlopen (NULL);
286 #endif
287 }
288
289 void
290 java::lang::Runtime::runFinalization (void)
291 {
292   gnu::gcj::runtime::FinalizerThread::finalizerReady ();
293 }
294
295 jlong
296 java::lang::Runtime::totalMemory (void)
297 {
298   return _Jv_GCTotalMemory ();
299 }
300
301 jlong
302 java::lang::Runtime::maxMemory (void)
303 {
304   // We don't have a maximum.  FIXME: we might if we ask the GC for
305   // one.
306   return Long::MAX_VALUE;
307 }
308
309 void
310 java::lang::Runtime::traceInstructions (jboolean)
311 {
312   // Do nothing.
313 }
314
315 void
316 java::lang::Runtime::traceMethodCalls (jboolean)
317 {
318   // Do nothing.
319 }
320
321 #if ! defined (DEFAULT_FILE_ENCODING) && defined (HAVE_ICONV) \
322     && defined (HAVE_NL_LANGINFO)
323
324 static char *
325 file_encoding ()
326 {
327   setlocale (LC_CTYPE, "");
328   char *e = nl_langinfo (CODESET);
329   if (e == NULL || *e == '\0')
330     e = "8859_1";
331   return e;
332 }
333
334 #define DEFAULT_FILE_ENCODING file_encoding ()
335
336 #endif
337
338 #ifndef DEFAULT_FILE_ENCODING
339 #define DEFAULT_FILE_ENCODING "8859_1"
340 #endif
341
342 static char *default_file_encoding = DEFAULT_FILE_ENCODING;
343
344 #if HAVE_GETPWUID_R
345 /* Use overload resolution to find out the signature of getpwuid_r.  */
346
347   /* This is Posix getpwuid_r.  */
348 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
349 static inline int
350 getpwuid_adaptor(int (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
351                                    T_buf *buf_r, T_len len_r,
352                                    T_passwd **pwd_entry_ptr),
353                  uid_t user_id, struct passwd *pwd_r,
354                  char *buf_r, size_t len_r, struct passwd **pwd_entry)
355 {
356   return getpwuid_r (user_id, pwd_r, buf_r, len_r, pwd_entry);
357 }
358
359 /* This is used on HPUX 10.20 */
360 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
361 static inline int
362 getpwuid_adaptor(int (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
363                                    T_buf *buf_r, T_len len_r),
364                  uid_t user_id, struct passwd *pwd_r,
365                  char *buf_r, size_t len_r, struct passwd **pwd_entry)
366 {
367   return getpwuid_r (user_id, pwd_r, buf_r, len_r);
368 }
369
370 /* This is used on IRIX 5.2.  */
371 template <typename T_uid, typename T_passwd, typename T_buf, typename T_len>
372 static inline int
373 getpwuid_adaptor(T_passwd * (*getpwuid_r)(T_uid user_id, T_passwd *pwd_r,
374                                           T_buf *buf_r, T_len len_r),
375                  uid_t user_id, struct passwd *pwd_r,
376                  char *buf_r, size_t len_r, struct passwd **pwd_entry)
377 {
378   *pwd_entry = getpwuid_r (user_id, pwd_r, buf_r, len_r);
379   return (*pwd_entry == NULL) ? errno : 0;
380 }
381 #endif
382
383 void
384 java::lang::Runtime::insertSystemProperties (java::util::Properties *newprops)
385 {
386   // A convenience define.
387 #define SET(Prop,Val) \
388         newprops->put(JvNewStringLatin1 (Prop), JvNewStringLatin1 (Val))
389
390   // A mixture of the Java Product Versioning Specification
391   // (introduced in 1.2), and earlier versioning properties.  Some
392   // programs rely on seeing values that they expect, so we claim to
393   // be a 1.4-ish VM for their sake.
394   SET ("java.version", "1.4.2");
395   SET ("java.runtime.version", "1.4.2");
396   SET ("java.vendor", "Free Software Foundation, Inc.");
397   SET ("java.vendor.url", "http://gcc.gnu.org/java/");
398   SET ("java.class.version", "46.0");
399   SET ("java.vm.specification.version", "1.0");
400   SET ("java.vm.specification.name", "Java(tm) Virtual Machine Specification");
401   SET ("java.vm.specification.vendor", "Sun Microsystems Inc.");
402   SET ("java.vm.version", __VERSION__);
403   SET ("java.vm.vendor", "Free Software Foundation, Inc.");
404   SET ("java.vm.name", "GNU libgcj");
405   SET ("java.specification.version", "1.4");
406   SET ("java.specification.name", "Java(tm) Platform API Specification");
407   SET ("java.specification.vendor", "Sun Microsystems Inc.");
408
409   char value[100];
410 #define NAME "GNU libgcj "
411   strcpy (value, NAME);
412   strncpy (value + sizeof (NAME) - 1, __VERSION__,
413            sizeof(value) - sizeof(NAME));
414   value[sizeof (value) - 1] = '\0';
415   jstring version = JvNewStringLatin1 (value);
416   newprops->put (JvNewStringLatin1 ("java.fullversion"), version);
417   newprops->put (JvNewStringLatin1 ("java.vm.info"), version);
418
419   // This definition is rather arbitrary: we choose $(prefix).  In
420   // part we do this because most people specify only --prefix and
421   // nothing else when installing gcj.  Plus, people are free to
422   // redefine `java.home' with `-D' if necessary.
423   SET ("java.home", PREFIX);
424   SET ("gnu.classpath.home", PREFIX);
425   // This is set to $(libdir) because we use this to find .security
426   // files at runtime.
427   char val2[sizeof ("file://") + sizeof (LIBDIR) + 1];
428   strcpy (val2, "file://");
429   strcat (val2, LIBDIR);
430   SET ("gnu.classpath.home.url", val2);
431
432   SET ("file.encoding", default_file_encoding);
433
434 #ifdef HAVE_UNAME
435   struct utsname u;
436   if (! uname (&u))
437     {
438       SET ("os.name", u.sysname);
439       SET ("os.arch", u.machine);
440       SET ("os.version", u.release);
441     }
442   else
443     {
444       SET ("os.name", "unknown");
445       SET ("os.arch", "unknown");
446       SET ("os.version", "unknown");
447     }
448 #endif /* HAVE_UNAME */
449
450 #ifndef NO_GETUID
451 #ifdef HAVE_PWD_H
452   uid_t user_id = getuid ();
453   struct passwd *pwd_entry;
454
455 #ifdef HAVE_GETPWUID_R
456   struct passwd pwd_r;
457   size_t len_r = 200;
458   char *buf_r = (char *) _Jv_AllocBytes (len_r);
459
460   while (buf_r != NULL)
461     {
462       int r = getpwuid_adaptor (getpwuid_r, user_id, &pwd_r,
463                                 buf_r, len_r, &pwd_entry);
464       if (r == 0)
465         break;
466       else if (r != ERANGE)
467         {
468           pwd_entry = NULL;
469           break;
470         }
471       len_r *= 2;
472       buf_r = (char *) _Jv_AllocBytes (len_r);
473     }
474 #else
475   pwd_entry = getpwuid (user_id);
476 #endif /* HAVE_GETPWUID_R */
477
478   if (pwd_entry != NULL)
479     {
480       SET ("user.name", pwd_entry->pw_name);
481       SET ("user.home", pwd_entry->pw_dir);
482     }
483 #endif /* HAVE_PWD_H */
484 #endif /* NO_GETUID */
485
486 #ifdef HAVE_GETCWD
487 #ifdef HAVE_UNISTD_H
488   /* Use getcwd to set "user.dir". */
489   int buflen = 250;
490   char *buffer = (char *) malloc (buflen);
491   while (buffer != NULL)
492     {
493       if (getcwd (buffer, buflen) != NULL)
494         {
495           SET ("user.dir", buffer);
496           break;
497         }
498       if (errno != ERANGE)
499         break;
500       buflen = 2 * buflen;
501       buffer = (char *) realloc (buffer, buflen);
502     }
503   if (buffer != NULL)
504     free (buffer);
505 #endif /* HAVE_UNISTD_H */
506 #endif /* HAVE_GETCWD */
507
508   // Set user locale properties based on setlocale()
509 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
510   // We let the user choose the locale.  However, since Java differs
511   // from POSIX, we arbitrarily pick LC_MESSAGES as determining the
512   // Java locale.  We can't use LC_ALL because it might return a full
513   // list of all the settings.  If we don't have LC_MESSAGES then we
514   // just default to `en_US'.
515   setlocale (LC_ALL, "");
516   char *locale = setlocale (LC_MESSAGES, "");
517   if (locale && strlen (locale) >= 2)
518     {
519       char buf[3];
520       buf[2] = '\0';
521       // copy the first two chars to user.language
522       strncpy (buf, locale, 2);
523       SET ("user.language", buf);
524       // if the next char is a '_', copy the two after that to user.region
525       locale += 2;
526       if (locale[0] == '_')
527         {
528           locale++;
529           strncpy (buf, locale, 2);
530           SET ("user.region", buf);
531         }
532     }
533   else
534 #endif /* HAVE_SETLOCALE and HAVE_LC_MESSAGES */
535     {
536       SET ("user.language", "en");
537       SET ("user.region", "US");
538     }  
539
540   // The java extensions directory.
541   SET ("java.ext.dirs", JAVA_EXT_DIRS);
542
543   // The path to libgcj's boot classes
544   SET ("sun.boot.class.path", BOOT_CLASS_PATH);
545
546   // Set some properties according to whatever was compiled in with
547   // `-D'.  Important: after this point, the only properties that
548   // should be set are those which either the user cannot meaningfully
549   // override, or which augment whatever value the user has provided.
550   for (int i = 0; _Jv_Compiler_Properties[i]; ++i)
551     {
552       const char *s, *p;
553       // Find the `='.
554       for (s = p = _Jv_Compiler_Properties[i]; *s && *s != '='; ++s)
555         ;
556       jstring name = JvNewStringLatin1 (p, s - p);
557       jstring val = JvNewStringLatin1 (*s == '=' ? s + 1 : s);
558       newprops->put (name, val);
559     }
560
561   // Set the system properties from the user's environment.
562 #ifndef DISABLE_GETENV_PROPERTIES
563   if (_Jv_Environment_Properties)
564     {
565       size_t i = 0;
566
567       while (_Jv_Environment_Properties[i].key)
568         {
569           SET (_Jv_Environment_Properties[i].key, 
570                _Jv_Environment_Properties[i].value);
571           i++;
572         }
573     }
574 #endif
575
576   if (_Jv_Jar_Class_Path)
577     newprops->put(JvNewStringLatin1 ("java.class.path"),
578                   JvNewStringLatin1 (_Jv_Jar_Class_Path));
579   else
580     {
581       // FIXME: find libgcj.zip and append its path?
582       char *classpath = ::getenv("CLASSPATH");
583       jstring cp = newprops->getProperty (JvNewStringLatin1("java.class.path"));
584       java::lang::StringBuffer *sb = new java::lang::StringBuffer ();
585       
586       if (classpath)
587         {
588           sb->append (JvNewStringLatin1 (classpath));
589           sb->append (_Jv_platform_path_separator);
590         }
591       if (cp != NULL)
592         sb->append (cp);
593       else
594         sb->append ((jchar) '.');
595       
596       newprops->put(JvNewStringLatin1 ("java.class.path"),
597                       sb->toString ());
598     }
599
600   // The name used to invoke this process (argv[0] in C).
601   SET ("gnu.gcj.progname", _Jv_GetSafeArg (0));
602
603   // Allow platform specific settings and overrides.
604   _Jv_platform_initProperties (newprops);
605
606   // If java.library.path is set, tell libltdl so we search the new
607   // directories as well.  FIXME: does this work properly on Windows?
608   String *path = newprops->getProperty(JvNewStringLatin1("java.library.path"));
609   if (path)
610     {
611       char *val = (char *) _Jv_Malloc (JvGetStringUTFLength (path) + 1);
612       jsize total = JvGetStringUTFRegion (path, 0, path->length(), val);
613       val[total] = '\0';
614       _Jv_SetDLLSearchPath (val);
615       _Jv_Free (val);
616     }
617   else
618     {
619       // Set a value for user code to see.
620       // FIXME: JDK sets this to the actual path used, including
621       // LD_LIBRARY_PATH, etc.
622       SET ("java.library.path", "");
623     }
624 }
625
626 java::lang::Process *
627 java::lang::Runtime::execInternal (jstringArray cmd,
628                                    jstringArray env,
629                                    java::io::File *dir)
630 {
631   return new java::lang::ConcreteProcess (cmd, env, dir);
632 }
633
634 jint
635 java::lang::Runtime::availableProcessors (void)
636 {
637   // FIXME: find the real value.
638   return 1;
639 }
640
641 jstring
642 java::lang::Runtime::nativeGetLibname (jstring pathname, jstring libname)
643 {
644   java::lang::StringBuffer *sb = new java::lang::StringBuffer ();
645   sb->append(pathname);
646   if (pathname->length() > 0)
647     sb->append (_Jv_platform_file_separator);
648
649   sb->append (JvNewStringLatin1 (_Jv_platform_solib_prefix));
650   sb->append(libname);
651   sb->append (JvNewStringLatin1 (_Jv_platform_solib_suffix));
652
653   return sb->toString();
654 }