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