b2276f35c96fb21a6c11713a7931b7433375907c
[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    $Id: properties.c 8403 2007-08-22 19:59:32Z twisti $
26
27 */
28
29
30 #include "config.h"
31
32 #include <errno.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <time.h>
36 #include <unistd.h>
37 #include <sys/utsname.h>
38
39 #if defined(WITH_JRE_LAYOUT)
40 # include <libgen.h>
41 #endif
42
43 #include "vm/types.h"
44
45 #include "mm/memory.h"
46
47 #include "native/jni.h"
48
49 #include "vm/global.h"                      /* required by java_lang_String.h */
50 #include "native/include/java_lang_String.h"
51
52 #include "toolbox/list.h"
53 #include "toolbox/util.h"
54
55 #include "vm/properties.h"
56 #include "vm/stringlocal.h"
57 #include "vm/vm.h"
58
59 #include "vm/jit/asmpart.h"
60
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(path) + 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(cacao_prefix) + 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 #  if defined(WITH_STATIC_CLASSPATH)
419         properties_add("gnu.classpath.boot.library.path", ".");
420         properties_add("java.library.path" , ".");
421 #  else
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 #  endif
433
434         properties_add("java.io.tmpdir", "/tmp");
435
436 #  if defined(ENABLE_INTRP)
437         if (opt_intrp) {
438                 properties_add("gnu.java.compiler.name", "cacao.intrp");
439         }
440         else
441 #  endif
442         {
443                 properties_add("gnu.java.compiler.name", "cacao.jit");
444         }
445
446         /* set the java.ext.dirs property */
447
448         len = strlen(java_home) + strlen("/jre/lib/ext") + strlen("0");
449
450         extdirs = MNEW(char, len);
451
452         strcpy(extdirs, java_home);
453         strcat(extdirs, "/jre/lib/ext");
454
455         properties_add("java.ext.dirs", extdirs);
456
457         properties_add("java.endorsed.dirs", ""CACAO_PREFIX"/jre/lib/endorsed");
458
459 #  if defined(DISABLE_GC)
460         /* When we disable the GC, we mmap the whole heap to a specific
461            address, so we can compare call traces. For this reason we have
462            to add the same properties on different machines, otherwise
463            more memory may be allocated (e.g. strlen("i386")
464            vs. strlen("alpha"). */
465
466         properties_add("os.arch", "unknown");
467         properties_add("os.name", "unknown");
468         properties_add("os.version", "unknown");
469 #  else
470         properties_add("os.arch", JAVA_ARCH);
471         properties_add("os.name", utsnamebuf->sysname);
472         properties_add("os.version", utsnamebuf->release);
473 #  endif
474
475 #  if defined(WITH_STATIC_CLASSPATH)
476         /* This is just for debugging purposes and can cause troubles in
477        GNU Classpath. */
478
479         properties_add("gnu.cpu.endian", "unknown");
480 #  else
481 #   if WORDS_BIGENDIAN == 1
482         properties_add("gnu.cpu.endian", "big");
483 #   else
484         properties_add("gnu.cpu.endian", "little");
485 #   endif
486 #  endif
487
488         properties_add("file.separator", "/");
489         properties_add("path.separator", ":");
490         properties_add("line.separator", "\n");
491
492         properties_add("user.name", env_user ? env_user : "null");
493         properties_add("user.home", env_home ? env_home : "null");
494         properties_add("user.dir", cwd ? cwd : "null");
495
496         /* get locale */
497
498         if (env_lang != NULL) {
499                 /* get the local stuff from the environment */
500
501                 if (strlen(env_lang) <= 2) {
502                         properties_add("user.language", env_lang);
503                 }
504                 else {
505                         if ((env_lang[2] == '_') && (strlen(env_lang) >= 5)) {
506                                 lang = MNEW(char, 3);
507                                 strncpy(lang, (char *) &env_lang[0], 2);
508                                 lang[2] = '\0';
509
510                                 country = MNEW(char, 3);
511                                 strncpy(country, (char *) &env_lang[3], 2);
512                                 country[2] = '\0';
513
514                                 properties_add("user.language", lang);
515                                 properties_add("user.country", country);
516                         }
517                 }
518         }
519         else {
520                 /* if no default locale was specified, use `en_US' */
521
522                 properties_add("user.language", "en");
523                 properties_add("user.country", "US");
524         }
525
526 # elif defined(WITH_CLASSPATH_SUN)
527
528         /* Actually this property is set by OpenJDK, but we need it in
529            nativevm_preinit(). */
530
531         properties_add("sun.boot.library.path", boot_library_path);
532
533 # else
534
535 #  error unknown classpath configuration
536
537 # endif
538
539 #elif defined(ENABLE_JAVAME_CLDC1_1)
540
541     properties_add("microedition.configuration", "CLDC-1.1");
542     properties_add("microedition.platform", "generic");
543     properties_add("microedition.encoding", "ISO8859_1");
544     properties_add("microedition.profiles", "");
545
546 #else
547
548 # error unknown Java configuration
549
550 #endif
551 }
552
553
554 /* properties_add **************************************************************
555
556    Adds a property entry to the internal property list.  If there's
557    already an entry with the same key, replace it.
558
559 *******************************************************************************/
560
561 void properties_add(char *key, char *value)
562 {
563         list_properties_entry_t *pe;
564
565         /* search for the entry */
566
567         for (pe = list_first_unsynced(list_properties); pe != NULL;
568                  pe = list_next_unsynced(list_properties, pe)) {
569                 if (strcmp(pe->key, key) == 0) {
570                         /* entry was found, replace the value */
571
572                         pe->value = value;
573
574                         return;
575                 }
576         }
577
578         /* entry was not found, insert a new one */
579
580         pe = NEW(list_properties_entry_t);
581
582         pe->key   = key;
583         pe->value = value;
584
585         list_add_last_unsynced(list_properties, pe);
586 }
587
588
589 /* properties_get **************************************************************
590
591    Get a property entry from the internal property list.
592
593 *******************************************************************************/
594
595 char *properties_get(char *key)
596 {
597         list_properties_entry_t *pe;
598
599         for (pe = list_first_unsynced(list_properties); pe != NULL;
600                  pe = list_next_unsynced(list_properties, pe)) {
601                 if (strcmp(pe->key, key) == 0)
602                         return pe->value;
603         }
604
605         return NULL;
606 }
607
608
609 /* properties_system_add *******************************************************
610
611    Adds a given property to the Java system properties.
612
613 *******************************************************************************/
614
615 void properties_system_add(java_handle_t *p, char *key, char *value)
616 {
617         methodinfo    *m;
618         java_handle_t *k;
619         java_handle_t *v;
620
621         /* search for method to add properties */
622
623         m = class_resolveclassmethod(p->vftbl->class,
624                                                                  utf_put,
625                                                                  utf_new_char("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"),
626                                                                  NULL,
627                                                                  true);
628
629         if (m == NULL)
630                 return;
631
632         /* add to the Java system properties */
633
634         k = javastring_new_from_utf_string(key);
635         v = javastring_new_from_utf_string(value);
636
637         (void) vm_call_method(m, p, k, v);
638 }
639
640
641 /* properties_system_add_all ***************************************************
642
643    Adds all properties from the properties list to the Java system
644    properties.
645
646    ARGUMENTS:
647        p.... is actually a java_util_Properties structure
648
649 *******************************************************************************/
650
651 #if defined(ENABLE_JAVASE)
652 void properties_system_add_all(java_handle_t *p)
653 {
654         list_properties_entry_t *pe;
655         methodinfo              *m;
656         java_handle_t           *key;
657         java_handle_t           *value;
658
659         /* search for method to add properties */
660
661         m = class_resolveclassmethod(p->vftbl->class,
662                                                                  utf_put,
663                                                                  utf_new_char("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"),
664                                                                  NULL,
665                                                                  true);
666
667         if (m == NULL)
668                 return;
669
670         /* process all properties stored in the internal table */
671
672         for (pe = list_first(list_properties); pe != NULL;
673                  pe = list_next(list_properties, pe)) {
674                 /* add to the Java system properties */
675
676                 key   = javastring_new_from_utf_string(pe->key);
677                 value = javastring_new_from_utf_string(pe->value);
678
679                 (void) vm_call_method(m, (java_handle_t *) p, key, value);
680         }
681 }
682 #endif /* defined(ENABLE_JAVASE) */
683
684
685 /*
686  * These are local overrides for various environment variables in Emacs.
687  * Please do not remove this and leave it at the end of the file, where
688  * Emacs will automagically detect them.
689  * ---------------------------------------------------------------------
690  * Local variables:
691  * mode: c
692  * indent-tabs-mode: t
693  * c-basic-offset: 4
694  * tab-width: 4
695  * End:
696  */