Goto sanos source index
//
// jinit.h
//
// Java VM launcher
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the project nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#include <os.h>
#include <java/jni.h>
#include <string.h>
#include <inifile.h>
#include <stdlib.h>
struct section *cfg;
char *cfgname;
JavaVM *vm = NULL;
JNIEnv *env = NULL;
JavaVMInitArgs args;
hmodule_t hjvm;
jint (JNICALL *CreateJavaVM)(JavaVM **pvm, void **env, void *args);
jclass load_class(JNIEnv *env, char *name) {
jclass cls;
char clsname[128];
char *s;
char *t;
s = name;
t = clsname;
while (*s) {
*t++ = *s == '.' ? '/' : *s;
s++;
}
*t = 0;
cls = (*env)->FindClass(env, clsname);
return cls;
}
jstring new_string(JNIEnv *env, char *s) {
int len = strlen(s);
jclass cls;
jmethodID mid;
jbyteArray ary;
cls = (*env)->FindClass(env, "java/lang/String");
mid = (*env)->GetMethodID(env, cls, "<init>", "([B)V");
ary = (*env)->NewByteArray(env, len);
if (ary != 0) {
jstring str = 0;
(*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *) s);
if (!(*env)->ExceptionOccurred(env)) {
str = (*env)->NewObject(env, cls, mid, ary);
}
(*env)->DeleteLocalRef(env, ary);
return str;
}
return 0;
}
jobjectArray new_string_array(JNIEnv *env, int strc, char **strv) {
jarray cls;
jarray ary;
int i;
cls = (*env)->FindClass(env, "java/lang/String");
ary = (*env)->NewObjectArray(env, strc, cls, 0);
for (i = 0; i < strc; i++) {
jstring str = new_string(env, *strv++);
(*env)->SetObjectArrayElement(env, ary, i, str);
(*env)->DeleteLocalRef(env, str);
}
return ary;
}
void init_jvm_args() {
JavaVMOption *options;
struct section *optsect;
struct section *propsect;
struct section *cpsect;
int nopts;
int n;
struct property *prop;
char *buf;
char *p;
int len;
int first;
cpsect = find_section(cfg, get_property(cfg, cfgname, "classpaths", "java.classpaths"));
optsect = find_section(cfg, get_property(cfg, cfgname, "options", "java.options"));
propsect = find_section(cfg, get_property(cfg, cfgname, "properties", "java.properties"));
nopts = get_section_size(optsect) + get_section_size(propsect) + (cpsect ? 1 : 0);
options = (JavaVMOption *) malloc(nopts * sizeof(JavaVMOption));
memset(options, 0, nopts * sizeof(JavaVMOption));
n = 0;
if (cpsect) {
len = strlen("-Djava.class.path=") + 1;
prop = cpsect->properties;
while (prop) {
if (prop->name) len += strlen(prop->name) + 1;
if (prop->value) len += strlen(prop->value) + 1;
prop = prop->next;
}
buf = (char *) malloc(len);
strcpy(buf, "-Djava.class.path=");
p = buf + strlen(buf);
first = 1;
prop = cpsect->properties;
while (prop) {
if (!first) *p++ = ';';
first = 0;
if (prop->name) {
len = strlen(prop->name);
memcpy(p, prop->name, len + 1);
p += len;
}
if (prop->value) {
*p++ = ':';
len = strlen(prop->value);
memcpy(p, prop->value, len + 1);
p += len;
}
prop = prop->next;
}
options[n++].optionString = buf;
}
if (optsect) {
prop = optsect->properties;
while (prop) {
if (prop->value) {
len = strlen(prop->name) + 1 + strlen(prop->value);
buf = (char *) malloc(len + 1);
strcpy(buf, prop->name);
strcpy(buf + strlen(buf), ":");
strcpy(buf + strlen(buf), prop->value);
} else {
len = strlen(prop->name);
buf = (char *) malloc(len + 1);
strcpy(buf, prop->name);
}
options[n++].optionString = buf;
prop = prop->next;
}
}
if (propsect) {
prop = propsect->properties;
while (prop) {
if (prop->value) {
len = 2 + strlen(prop->name) + 1 + strlen(prop->value);
} else {
len = 2 + strlen(prop->name);
}
buf = (char *) malloc(len + 1);
strcpy(buf, "-D");
strcpy(buf + strlen(buf), prop->name);
if (prop->value) {
strcpy(buf + strlen(buf), "=");
strcpy(buf + strlen(buf), prop->value);
}
options[n++].optionString = buf;
prop = prop->next;
}
}
memset(&args, 0, sizeof(args));
args.version = JNI_VERSION_1_2;
args.nOptions = nopts;
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
}
int init_jvm() {
jint rc;
// Get JVM options from os.ini
init_jvm_args();
// Load VM
if (hjvm == NULL) {
char *jvmname = get_property(cfg, cfgname, "jvm", "jvm.dll");
hjvm = dlopen(jvmname, 0);
if (hjvm == NULL) {
syslog(LOG_ERR, "Error loading JVM %s", jvmname);
return -1;
}
}
if (!CreateJavaVM) {
CreateJavaVM = (jint (JNICALL *)(JavaVM **pvm, void **env, void *args)) dlsym(hjvm, "JNI_CreateJavaVM");
if (!CreateJavaVM) {
syslog(LOG_ERR, "Unable to find CreateJavaVM");
return -1;
}
}
// Create VM instance
if (!vm) {
rc = CreateJavaVM(&vm, (void **) &env, &args);
if (rc != JNI_OK) {
syslog(LOG_ERR, "Error %d creating java vm", rc);
return -1;
}
} else {
rc = (*vm)->AttachCurrentThread(vm, (void **) &env, &args);
if (rc != JNI_OK) {
syslog(LOG_ERR, "Error %d attaching to vm", rc);
return -1;
}
}
return 0;
}
int parse_args(char *args, char **argv) {
char *p;
int argc;
char *start;
char *end;
char *buf;
int delim;
p = args;
argc = 0;
while (*p) {
while (*p == ' ') p++;
if (!*p) break;
if (*p == '"' || *p == '\'') {
delim = *p++;
start = p;
while (*p && *p != delim) p++;
end = p;
if (*p == delim) p++;
} else {
start = p;
while (*p && *p != ' ') p++;
end = p;
}
if (argv) {
buf = (char *) malloc(end - start + 1);
if (!buf) break;
memcpy(buf, start, end - start);
buf[end - start] = 0;
argv[argc] = buf;
}
argc++;
}
return argc;
}
static void free_args(int argc, char **argv) {
int i;
for (i = 0; i < argc; i++) free(argv[i]);
if (argv) free(argv);
}
int execute_main_method(char *mainclsname, char *mainclsargs) {
int argc;
char **argv;
jclass mainclass;
jmethodID mainid;
jobjectArray mainargs;
// Load main class
mainclass = load_class(env, mainclsname);
if (mainclass == NULL) {
syslog(LOG_ERR, "Unable to find main class %s", mainclsname);
return -1;
}
// Find main method
mainid = (*env)->GetStaticMethodID(env, mainclass, "main", "([Ljava/lang/String;)V");
if (mainid == NULL) {
syslog(LOG_ERR, "Class %s does not have a main method", mainclsname);
return -1;
}
// Create argument array
argc = parse_args(mainclsargs, NULL);
if (argc) {
argv = (char **) malloc(argc * sizeof(char *));
parse_args(mainclsargs, argv);
} else {
argv = NULL;
}
mainargs = new_string_array(env, argc, argv);
if (mainargs == NULL) {
syslog(LOG_ERR, "Error creating command arguments");
return -1;
}
// Invoke main method
(*env)->CallStaticVoidMethod(env, mainclass, mainid, mainargs);
if ((*env)->ExceptionOccurred(env)) {
(*env)->ExceptionDescribe(env);
return -1;
}
free_args(argc, argv);
return 0;
}
int main(int argc, char *argv[]) {
char *mainclsname;
char *mainclsargs;
// Determine configuration
if (argc > 1) {
cfgname = argv[1];
} else {
cfgname = "java";
}
if (argc > 2) {
cfg = read_properties(argv[2]);
if (cfg == NULL) {
syslog(LOG_ERR, "Unable to read JVM configuration from %s", argv[2]);
return 1;
}
} else {
cfg = osconfig();
}
// Initialize Java VM
if (init_jvm() != 0) return 1;
// Get main class and arguments
mainclsname = get_property(cfg, cfgname, "mainclass", "sanos.os.Shell");
mainclsargs = get_property(cfg, cfgname, "mainargs", "");
// Call main method
execute_main_method(mainclsname, mainclsargs);
// Detach main thread from jvm
if ((*vm)->DetachCurrentThread(vm) != 0) {
syslog(LOG_ERR, "Could not detach main thread");
return 1;
}
(*vm)->DestroyJavaVM(vm);
return 0;
}