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