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