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