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