OSDN Git Service

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