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