PR123: LD_LIBRARY_PATH and java.library.path
[cacao.git] / src / vm / properties.cpp
1 /* src/vm/properties.cpp - handling commandline properties
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <errno.h>
29 #include <stdint.h>
30 #include <stdlib.h>
31
32 #include <string.h>
33 #include <time.h>
34 #include <unistd.h>
35
36 #include "mm/memory.hpp"
37
38 #include "native/llni.h"
39
40 #include "vm/class.hpp"
41 #include "vm/global.h"
42 #include "vm/method.hpp"
43 #include "vm/options.h"
44 #include "vm/os.hpp"
45 #include "vm/properties.hpp"
46 #include "vm/string.hpp"
47 #include "vm/vm.hpp"
48
49 #include "vm/jit/asmpart.h"
50
51
52 /**
53  * Constructor fills the properties list with default values.
54  */
55 Properties::Properties()
56 {
57         int             len;
58         char           *p;
59
60         char           *boot_class_path;
61
62 #if defined(ENABLE_JAVASE)
63
64 # if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
65         struct utsname *utsnamebuf;
66 # endif
67 #endif
68
69 #if defined(ENABLE_JRE_LAYOUT)
70         /* SUN also uses a buffer of 4096-bytes (strace is your friend). */
71
72         p = MNEW(char, 4096);
73
74         if (os::readlink("/proc/self/exe", p, 4095) == -1)
75                 os::abort_errno("readlink failed");
76
77         /* We have a path like:
78
79            /path/to/executable/bin/java
80
81            or
82            
83            /path/to/executeable/jre/bin/java
84
85            Now let's strip two levels. */
86
87         p = os::dirname(p);
88         p = os::dirname(p);
89
90 # if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
91
92         /* Set java.home. */
93
94         char* java_home = strdup(p);
95
96         /* Set the path to Java core native libraries. */
97
98         len = strlen(java_home) + strlen("/lib/classpath") + strlen("0");
99
100         char* boot_library_path = MNEW(char, len);
101
102         strcpy(boot_library_path, java_home);
103         strcat(boot_library_path, "/lib/classpath");
104
105 # elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
106
107         /* Find correct java.home.  We check if there is a JRE
108            co-located. */
109
110         /* NOTE: We use the server VM here as it should be available on
111            all architectures. */
112
113         len =
114                 strlen(p) +
115                 strlen("/jre/lib/"JAVA_ARCH"/server/libjvm.so") +
116                 strlen("0");
117
118         char* java_home = MNEW(char, len);
119
120         strcpy(java_home, p);
121         strcat(java_home, "/jre/lib/"JAVA_ARCH"/server/libjvm.so");
122
123         // Check if that libjvm.so exists.
124         if (os::access(java_home, F_OK) == 0) {
125                 // Yes, we add /jre to java.home.
126                 strcpy(java_home, p);
127                 strcat(java_home, "/jre");
128         }
129         else {
130                 // No, java.home is parent directory.
131                 strcpy(java_home, p);
132         }
133
134         /* Set the path to Java core native libraries. */
135
136         len = strlen(java_home) + strlen("/lib/"JAVA_ARCH) + strlen("0");
137
138         char* boot_library_path = MNEW(char, len);
139
140         strcpy(boot_library_path, java_home);
141         strcat(boot_library_path, "/lib/"JAVA_ARCH);
142
143 # else
144 #  error unknown classpath configuration
145 # endif
146
147         /* Free path. */
148
149         MFREE(p, char, len);
150
151 #else
152         const char* java_home = CACAO_PREFIX;
153
154 # if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
155
156         const char* boot_library_path = JAVA_RUNTIME_LIBRARY_LIBDIR"/classpath";
157
158 # elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
159
160         const char* boot_library_path = JAVA_RUNTIME_LIBRARY_LIBDIR;
161
162 # elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
163
164         // No boot_library_path required.
165
166 # else
167 #  error unknown classpath configuration
168 # endif
169 #endif
170
171         put("java.home", java_home);
172
173         /* Set the bootclasspath. */
174
175         p = os::getenv("BOOTCLASSPATH");
176
177         if (p != NULL) {
178                 boot_class_path = MNEW(char, strlen(p) + strlen("0"));
179                 strcpy(boot_class_path, p);
180         }
181         else {
182 #if defined(ENABLE_JRE_LAYOUT)
183 # if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
184
185                 len =
186                         strlen(java_home) + strlen("/share/cacao/vm.zip:") +
187                         strlen(java_home) + strlen("/share/classpath/glibj.zip") +
188                         strlen("0");
189
190                 boot_class_path = MNEW(char, len);
191
192                 strcpy(boot_class_path, java_home);
193                 strcat(boot_class_path, "/share/cacao/vm.zip");
194                 strcat(boot_class_path, ":");
195                 strcat(boot_class_path, java_home);
196                 strcat(boot_class_path, "/share/classpath/glibj.zip");
197
198 # elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
199
200                 /* This is the bootclasspath taken from HotSpot (see
201                    hotspot/src/share/vm/runtime/os.cpp
202                    (os::set_boot_path)). */
203
204                 len =
205                         strlen(java_home) + strlen("/lib/resources.jar:") +
206                         strlen(java_home) + strlen("/lib/rt.jar:") +
207                         strlen(java_home) + strlen("/lib/sunrsasign.jar:") +
208                         strlen(java_home) + strlen("/lib/jsse.jar:") +
209                         strlen(java_home) + strlen("/lib/jce.jar:") +
210                         strlen(java_home) + strlen("/lib/charsets.jar:") +
211                         strlen(java_home) + strlen("/classes") +
212                         strlen("0");
213
214                 boot_class_path = MNEW(char, len);
215
216                 strcpy(boot_class_path, java_home);
217                 strcat(boot_class_path, "/lib/resources.jar:");
218                 strcat(boot_class_path, java_home);
219                 strcat(boot_class_path, "/lib/rt.jar:");
220                 strcat(boot_class_path, java_home);
221                 strcat(boot_class_path, "/lib/sunrsasign.jar:");
222                 strcat(boot_class_path, java_home);
223                 strcat(boot_class_path, "/lib/jsse.jar:");
224                 strcat(boot_class_path, java_home);
225                 strcat(boot_class_path, "/lib/jce.jar:");
226                 strcat(boot_class_path, java_home);
227                 strcat(boot_class_path, "/lib/charsets.jar:");
228                 strcat(boot_class_path, java_home);
229                 strcat(boot_class_path, "/classes");
230
231 # else
232 #  error unknown classpath configuration
233 # endif
234 #else
235 # if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
236
237                 len =
238                         strlen(CACAO_VM_ZIP) +
239                         strlen(":") +
240                         strlen(JAVA_RUNTIME_LIBRARY_CLASSES) +
241                         strlen("0");
242
243                 boot_class_path = MNEW(char, len);
244
245                 strcpy(boot_class_path, CACAO_VM_ZIP);
246                 strcat(boot_class_path, ":");
247                 strcat(boot_class_path, JAVA_RUNTIME_LIBRARY_CLASSES);
248
249 # elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
250
251                 /* This is the bootclasspath taken from HotSpot (see
252                    hotspot/src/share/vm/runtime/os.cpp
253                    (os::set_boot_path)). */
254
255                 len =
256                         strlen(JAVA_RUNTIME_LIBRARY_PREFIX"/lib/resources.jar:") +
257                         strlen(JAVA_RUNTIME_LIBRARY_PREFIX"/lib/rt.jar:") +
258                         strlen(JAVA_RUNTIME_LIBRARY_PREFIX"/lib/sunrsasign.jar:") +
259                         strlen(JAVA_RUNTIME_LIBRARY_PREFIX"/lib/jsse.jar:") +
260                         strlen(JAVA_RUNTIME_LIBRARY_PREFIX"/lib/jce.jar:") +
261                         strlen(JAVA_RUNTIME_LIBRARY_PREFIX"/lib/charsets.jar:") +
262                         strlen(JAVA_RUNTIME_LIBRARY_PREFIX"/classes") +
263                         strlen("0");
264
265                 boot_class_path = MNEW(char, len);
266
267                 strcpy(boot_class_path, JAVA_RUNTIME_LIBRARY_PREFIX"/lib/resources.jar:");
268                 strcat(boot_class_path, JAVA_RUNTIME_LIBRARY_PREFIX"/lib/rt.jar:");
269                 strcat(boot_class_path, JAVA_RUNTIME_LIBRARY_PREFIX"/lib/sunrsasign.jar:");
270                 strcat(boot_class_path, JAVA_RUNTIME_LIBRARY_PREFIX"/lib/jsse.jar:");
271                 strcat(boot_class_path, JAVA_RUNTIME_LIBRARY_PREFIX"/lib/jce.jar:");
272                 strcat(boot_class_path, JAVA_RUNTIME_LIBRARY_PREFIX"/lib/charsets.jar:");
273                 strcat(boot_class_path, JAVA_RUNTIME_LIBRARY_PREFIX"/classes");
274
275 # elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
276
277                 len =
278                         strlen(JAVA_RUNTIME_LIBRARY_CLASSES) +
279                         strlen("0");
280
281                 boot_class_path = MNEW(char, len);
282
283                 strcpy(boot_class_path, JAVA_RUNTIME_LIBRARY_CLASSES);
284
285 # else
286 #  error unknown classpath configuration
287 # endif
288 #endif
289         }
290
291         put("sun.boot.class.path", boot_class_path);
292         put("java.boot.class.path", boot_class_path);
293
294 #if defined(ENABLE_JAVASE)
295
296         /* Set the classpath. */
297
298         p = os::getenv("CLASSPATH");
299
300         char* class_path;
301
302         if (p != NULL) {
303                 class_path = MNEW(char, strlen(p) + strlen("0"));
304                 strcpy(class_path, p);
305         }
306         else {
307                 class_path = MNEW(char, strlen(".") + strlen("0"));
308                 strcpy(class_path, ".");
309         }
310
311         put("java.class.path", class_path);
312
313         // Add java.vm properties.
314         put("java.vm.specification.version", "1.0");
315         put("java.vm.specification.vendor", "Sun Microsystems Inc.");
316         put("java.vm.specification.name", "Java Virtual Machine Specification");
317         put("java.vm.version", VERSION_FULL);
318         put("java.vm.vendor", "CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO");
319         put("java.vm.name", "CACAO");
320
321 # if defined(ENABLE_INTRP)
322         if (opt_intrp) {
323                 /* XXX We don't support java.lang.Compiler */
324 /*              put("java.compiler", "cacao.intrp"); */
325                 put("java.vm.info", "interpreted mode");
326         }
327         else
328 # endif
329         {
330                 /* XXX We don't support java.lang.Compiler */
331 /*              put("java.compiler", "cacao.jit"); */
332                 put("java.vm.info", "compiled mode");
333         }
334
335         // Get and set java.library.path.
336         const char* java_library_path = os::getenv("LD_LIBRARY_PATH");
337
338         if (java_library_path == NULL)
339                 java_library_path = "";
340
341         put("java.library.path", java_library_path);
342
343 # if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
344
345         /* Get properties from system. */
346
347         char* cwd      = os::getcwd();
348
349         char* env_user = os::getenv("USER");
350         char* env_home = os::getenv("HOME");
351         char* env_lang = os::getenv("LANG");
352
353         utsnamebuf = NEW(struct utsname);
354
355         uname(utsnamebuf);
356
357         put("java.runtime.version", VERSION_FULL);
358         put("java.runtime.name", "CACAO");
359
360         put("java.specification.version", "1.5");
361         put("java.specification.vendor", "Sun Microsystems Inc.");
362         put("java.specification.name", "Java Platform API Specification");
363
364         put("java.version", JAVA_VERSION);
365         put("java.vendor", "GNU Classpath");
366         put("java.vendor.url", "http://www.gnu.org/software/classpath/");
367
368         put("java.class.version", CLASS_VERSION);
369
370         put("gnu.classpath.boot.library.path", boot_library_path);
371
372         put("java.io.tmpdir", "/tmp");
373
374 #  if defined(ENABLE_INTRP)
375         if (opt_intrp) {
376                 put("gnu.java.compiler.name", "cacao.intrp");
377         }
378         else
379 #  endif
380         {
381                 put("gnu.java.compiler.name", "cacao.jit");
382         }
383
384         /* Set the java.ext.dirs property. */
385
386         len = strlen(java_home) + strlen("/jre/lib/ext") + strlen("0");
387
388         char* extdirs = MNEW(char, len);
389
390         sprintf(extdirs, "%s/jre/lib/ext", java_home);
391
392         put("java.ext.dirs", extdirs);
393
394         /* Set the java.ext.endorsed property. */
395
396         len = strlen(java_home) + strlen("/jre/lib/endorsed") + strlen("0");
397
398         char* endorseddirs = MNEW(char, len);
399
400         sprintf(endorseddirs, "%s/jre/lib/endorsed", java_home);
401
402         put("java.endorsed.dirs", endorseddirs);
403
404 #  if defined(DISABLE_GC)
405         /* When we disable the GC, we mmap the whole heap to a specific
406            address, so we can compare call traces. For this reason we have
407            to add the same properties on different machines, otherwise
408            more memory may be allocated (e.g. strlen("i386")
409            vs. strlen("alpha"). */
410
411         put("os.arch", "unknown");
412         put("os.name", "unknown");
413         put("os.version", "unknown");
414 #  else
415         put("os.arch", JAVA_ARCH);
416         put("os.name", utsnamebuf->sysname);
417         put("os.version", utsnamebuf->release);
418 #  endif
419
420 #  if WORDS_BIGENDIAN == 1
421         put("gnu.cpu.endian", "big");
422 #  else
423         put("gnu.cpu.endian", "little");
424 #  endif
425
426         put("file.separator", "/");
427         put("path.separator", ":");
428         put("line.separator", "\n");
429
430         put("user.name", env_user ? env_user : "null");
431         put("user.home", env_home ? env_home : "null");
432         put("user.dir", cwd ? cwd : "null");
433
434         /* get locale */
435
436         if (env_lang != NULL) {
437                 /* get the local stuff from the environment */
438
439                 if (strlen(env_lang) <= 2) {
440                         put("user.language", env_lang);
441                 }
442                 else {
443                         if ((env_lang[2] == '_') && (strlen(env_lang) >= 5)) {
444                                 char* lang = MNEW(char, 3);
445                                 strncpy(lang, (char*) &env_lang[0], 2);
446                                 lang[2] = '\0';
447
448                                 char* country = MNEW(char, 3);
449                                 strncpy(country, (char*) &env_lang[3], 2);
450                                 country[2] = '\0';
451
452                                 put("user.language", lang);
453                                 put("user.country", country);
454                         }
455                 }
456         }
457         else {
458                 /* if no default locale was specified, use `en_US' */
459
460                 put("user.language", "en");
461                 put("user.country", "US");
462         }
463
464 # elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
465
466         /* Actually this property is set by OpenJDK, but we need it in
467            nativevm_preinit(). */
468
469         put("sun.boot.library.path", boot_library_path);
470
471         // Set the java.ext.dirs property.
472         len =
473                 strlen(java_home) + strlen("/lib/ext") +
474                 strlen(":") +
475                 strlen("/usr/java/packages/lib/ext") +
476                 strlen("0");
477
478         char* extdirs = MNEW(char, len);
479
480         sprintf(extdirs, "%s/lib/ext:/usr/java/packages/lib/ext", java_home);
481
482         put("java.ext.dirs", extdirs);
483
484         // Set the java.ext.endorsed property.
485         len = strlen(java_home) + strlen("/lib/endorsed") + strlen("0");
486
487         char* endorseddirs = MNEW(char, len);
488
489         sprintf(endorseddirs, "%s/lib/endorsed", java_home);
490
491         put("java.endorsed.dirs", endorseddirs);
492
493 # else
494
495 #  error unknown classpath configuration
496
497 # endif
498
499 #elif defined(ENABLE_JAVAME_CLDC1_1)
500
501     put("microedition.configuration", "CLDC-1.1");
502     put("microedition.platform", "generic");
503     put("microedition.encoding", "ISO8859_1");
504     put("microedition.profiles", "");
505
506 #else
507
508 # error unknown Java configuration
509
510 #endif
511 }
512
513
514 /**
515  * Add the given property to the given Java system properties.
516  *
517  * @param p     Java properties object.
518  * @param key   Key.
519  * @param value Value.
520  */
521 void Properties::put(java_handle_t* p, const char* key, const char* value)
522 {
523         // Get Properties.put() method to add properties.
524         classinfo* c;
525         LLNI_class_get(p, c);
526
527         methodinfo* m = class_resolveclassmethod(c,
528                                                                                          utf_put,
529                                                                                          utf_new_char("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"),
530                                                                                          NULL,
531                                                                                          true);
532
533         if (m == NULL)
534                 return;
535
536         // Add to the Java system properties.
537         java_handle_t* k = javastring_new_from_utf_string(key);
538         java_handle_t* v = javastring_new_from_utf_string(value);
539
540         (void) vm_call_method(m, p, k, v);
541 }
542
543
544 /**
545  * Put the given property into the internal property map.  If there's
546  * already an entry with the same key, replace it.
547  *
548  * @param key   Key.
549  * @param value Value.
550  */
551 void Properties::put(const char* key, const char* value)
552 {
553         // Try to find the key.
554         std::map<const char*, const char*>::iterator it = _properties.find(key);
555
556         // The key is already in the map.
557         if (it != _properties.end()) {
558 #if !defined(NDEBUG)
559                 if (opt_DebugProperties) {
560                         printf("[Properties::put: key=%s, old value=%s, new value=%s]\n",
561                                    key, it->second, value);
562                 }
563 #endif
564
565                 // Replace the value in the current entry.
566                 it->second = value;
567
568                 return;
569         }
570
571         // The key was not found, insert the pair.
572 #if !defined(NDEBUG)
573         if (opt_DebugProperties) {
574                 printf("[Properties::put: key=%s, value=%s]\n", key, value);
575         }
576 #endif
577
578         _properties.insert(std::make_pair(key, value));
579 }
580
581
582 /**
583  * Get a property entry from the internal property map.
584  *
585  * @param key Key.
586  *
587  * @return Value associated with the key or NULL when not found.
588  */
589 const char* Properties::get(const char* key)
590 {
591         // Try to find the key.
592         std::map<const char*, const char*>::iterator it = _properties.find(key);
593
594         // The key is not in the map.
595         if (it == _properties.end())
596                 return NULL;
597
598         // Return the value.
599         return it->second;
600 }
601
602
603 /**
604  * Fill the given Java system properties with all properties from the
605  * internal properties map.
606  *
607  * @param p Java Properties object.
608  */
609 #if defined(ENABLE_JAVASE)
610 void Properties::fill(java_handle_t* p)
611 {
612         // Get Properties.put() method to add properties.
613         classinfo* c;
614         LLNI_class_get(p, c);
615
616         methodinfo* m = class_resolveclassmethod(c,
617                                                                                          utf_put,
618                                                                                          utf_new_char("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"),
619                                                                                          NULL,
620                                                                                          true);
621
622         if (m == NULL)
623                 return;
624
625         // Iterator over all properties.
626         for (std::map<const char*, const char*>::iterator it = _properties.begin(); it != _properties.end(); it++) {
627                 // Put into the Java system properties.
628                 java_handle_t* key   = javastring_new_from_utf_string(it->first);
629                 java_handle_t* value = javastring_new_from_utf_string(it->second);
630
631                 (void) vm_call_method(m, p, key, value);
632         }
633 }
634 #endif
635
636
637 /**
638  * Dump all property entries.
639  */
640 #if !defined(NDEBUG)
641 void Properties::dump()
642 {
643         for (std::map<const char*, const char*>::iterator it = _properties.begin(); it != _properties.end(); it++) {
644                 log_println("[Properties::dump: key=%s, value=%s]", it->first, it->second);
645         }
646 }
647 #endif
648
649
650 /*
651  * These are local overrides for various environment variables in Emacs.
652  * Please do not remove this and leave it at the end of the file, where
653  * Emacs will automagically detect them.
654  * ---------------------------------------------------------------------
655  * Local variables:
656  * mode: c++
657  * indent-tabs-mode: t
658  * c-basic-offset: 4
659  * tab-width: 4
660  * End:
661  * vim:noexpandtab:sw=4:ts=4:
662  */