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