#include #include "sigar.h" #include "sigar_fileinfo.h" #include "sigar_log.h" #include #ifdef WIN32 #include #else #include #include #include #endif #include "javasigar_generated.h" #define JENV (*env) #define SIGAR_PACKAGE "net/hyperic/sigar/" #define SIGAR_JNI(m) JNICALL Java_net_hyperic_sigar_##m #define SIGAR_FIND_CLASS(name) \ JENV->FindClass(env, SIGAR_PACKAGE name) #define SIGAR_CLASS_SIG(name) \ "L" SIGAR_PACKAGE name ";" typedef struct { jclass classref; jfieldID *ids; } jsigar_field_cache_t; typedef struct { JNIEnv *env; jobject logger; sigar_t *sigar; jsigar_field_cache_t *fields[JSIGAR_FIELDS_MAX]; int open_status; jthrowable not_impl; } jni_sigar_t; #define dSIGAR_GET \ jni_sigar_t *jsigar = sigar_get_pointer(env, sigar_obj); \ sigar_t *sigar #define dSIGAR_VOID \ dSIGAR_GET; \ if (!jsigar) return; \ sigar = jsigar->sigar #define dSIGAR(val) \ dSIGAR_GET; \ if (!jsigar) return val; \ sigar = jsigar->sigar static void sigar_throw_exception(JNIEnv *env, char *msg) { jclass errorClass = SIGAR_FIND_CLASS("SigarException"); JENV->ThrowNew(env, errorClass, msg); } #define SIGAR_NOTIMPL_EX "SigarNotImplementedException" static void sigar_throw_notimpl(JNIEnv *env, char *msg) { jclass errorClass = SIGAR_FIND_CLASS(SIGAR_NOTIMPL_EX); JENV->ThrowNew(env, errorClass, msg); } #ifdef WIN32 # define SIGAR_ENOENT ERROR_FILE_NOT_FOUND #else # define SIGAR_ENOENT ENOENT #endif #ifdef WIN32 # define SIGAR_EACCES ERROR_ACCESS_DENIED #else # define SIGAR_EACCES EACCES #endif static void sigar_throw_error(JNIEnv *env, jni_sigar_t *jsigar, int err) { jclass errorClass; switch (err) { case SIGAR_ENOENT: errorClass = SIGAR_FIND_CLASS("SigarFileNotFoundException"); break; case SIGAR_EACCES: errorClass = SIGAR_FIND_CLASS("SigarPermissionDeniedException"); break; case SIGAR_ENOTIMPL: if (jsigar->not_impl == NULL) { jfieldID id; jthrowable not_impl; errorClass = SIGAR_FIND_CLASS(SIGAR_NOTIMPL_EX); id = JENV->GetStaticFieldID(env, errorClass, "INSTANCE", SIGAR_CLASS_SIG(SIGAR_NOTIMPL_EX)); not_impl = JENV->GetStaticObjectField(env, errorClass, id); jsigar->not_impl = JENV->NewGlobalRef(env, not_impl); } JENV->Throw(env, jsigar->not_impl); return; default: errorClass = SIGAR_FIND_CLASS("SigarException"); break; } JENV->ThrowNew(env, errorClass, sigar_strerror(jsigar->sigar, err)); } static jni_sigar_t *sigar_get_pointer(JNIEnv *env, jobject obj) { jfieldID pointer_field; jni_sigar_t *jsigar; jclass cls; cls = JENV->GetObjectClass(env, obj); pointer_field = JENV->GetFieldID(env, cls, "sigarWrapper", "J"); jsigar = (jni_sigar_t *) JENV->GetLongField(env, obj, pointer_field); if (!jsigar) { sigar_throw_exception(env, "sigar has been closed"); return NULL; } if (jsigar->open_status != SIGAR_OK) { sigar_throw_error(env, jsigar, jsigar->open_status); return NULL; } return jsigar; } static void sigar_set_pointer(JNIEnv *env, jobject obj, const void *ptr) { jfieldID pointer_field; jclass cls = JENV->GetObjectClass(env, obj); pointer_field = JENV->GetFieldID(env, cls, "sigarWrapper", "J"); JENV->SetLongField(env, obj, pointer_field, (jlong)ptr); } JNIEXPORT jstring SIGAR_JNI(Sigar_formatSize) (JNIEnv *env, jclass cls, jlong size) { char buf[56]; sigar_format_size(size, buf); return JENV->NewStringUTF(env, buf); } JNIEXPORT void SIGAR_JNI(Sigar_open) (JNIEnv *env, jobject obj) { jni_sigar_t *jsigar = malloc(sizeof(*jsigar)); memset(jsigar, '\0', sizeof(*jsigar)); sigar_set_pointer(env, obj, jsigar); /* this method is called by the constructor. * if != SIGAR_OK save status and throw exception * when methods are invoked (see sigar_get_pointer). */ if ((jsigar->open_status = sigar_open(&jsigar->sigar)) != SIGAR_OK) { sigar_throw_error(env, jsigar, jsigar->open_status); return; } } JNIEXPORT jint SIGAR_JNI(Sigar_nativeClose) (JNIEnv *env, jobject sigar_obj) { jint status; int i; dSIGAR(0); /* only place it is possible this would be something other than * SIGAR_OK is on win32 if RegCloseKey fails, which i don't think * is possible either. */ status = sigar_close(sigar); if (jsigar->logger != NULL) { JENV->DeleteGlobalRef(env, jsigar->logger); } if (jsigar->not_impl != NULL) { JENV->DeleteGlobalRef(env, jsigar->not_impl); } for (i=0; ifields[i]) { JENV->DeleteGlobalRef(env, jsigar->fields[i]->classref); free(jsigar->fields[i]->ids); free(jsigar->fields[i]); } } free(jsigar); sigar_set_pointer(env, sigar_obj, NULL); return status; } JNIEXPORT jlong SIGAR_JNI(Sigar_getPid) (JNIEnv *env, jobject sigar_obj) { dSIGAR(0); return sigar_pid_get(sigar); } JNIEXPORT void SIGAR_JNI(Sigar_kill) (JNIEnv *env, jobject sigar_obj, jlong pid, jint signum) { int status; dSIGAR_VOID; if ((status = sigar_proc_kill(pid, signum)) != SIGAR_OK) { sigar_throw_error(env, jsigar, status); } } #define SetStringField(env, obj, fieldID, val) \ SetObjectField(env, obj, fieldID, JENV->NewStringUTF(env, val)) static jstring jinet_ntoa(JNIEnv *env, sigar_t *sigar, sigar_uint64_t val) { char addr_str[SIGAR_INET_ADDR_LEN]; sigar_inet_ntoa(sigar, val, addr_str); return JENV->NewStringUTF(env, addr_str); } #define SetNetAddrField(env, obj, fieldID, val) \ SetObjectField(env, obj, fieldID, jinet_ntoa(env, sigar, val)) #include "javasigar_generated.c" #define SIGAR_ALLOC_OBJECT(name) \ JENV->AllocObject(env, SIGAR_FIND_CLASS(name)) enum { FS_FIELD_DIRNAME, FS_FIELD_DEVNAME, FS_FIELD_SYS_TYPENAME, FS_FIELD_TYPE, FS_FIELD_TYPENAME, FS_FIELD_MAX }; #define STRING_SIG "Ljava/lang/String;" JNIEXPORT jobjectArray SIGAR_JNI(Sigar_getFileSystemList) (JNIEnv *env, jobject sigar_obj) { int status; unsigned int i; sigar_file_system_list_t fslist; jobjectArray fsarray; jfieldID ids[FS_FIELD_MAX]; jclass cls = SIGAR_FIND_CLASS("FileSystem"); dSIGAR(NULL); if ((status = sigar_file_system_list_get(sigar, &fslist)) != SIGAR_OK) { sigar_throw_error(env, jsigar, status); return NULL; } ids[FS_FIELD_DIRNAME] = JENV->GetFieldID(env, cls, "dirName", STRING_SIG); ids[FS_FIELD_DEVNAME] = JENV->GetFieldID(env, cls, "devName", STRING_SIG); ids[FS_FIELD_TYPENAME] = JENV->GetFieldID(env, cls, "typeName", STRING_SIG); ids[FS_FIELD_SYS_TYPENAME] = JENV->GetFieldID(env, cls, "sysTypeName", STRING_SIG); ids[FS_FIELD_TYPE] = JENV->GetFieldID(env, cls, "type", "I"); fsarray = JENV->NewObjectArray(env, fslist.number, cls, 0); for (i=0; iAllocObject(env, cls); JENV->SetStringField(env, fsobj, ids[FS_FIELD_DIRNAME], fs->dir_name); JENV->SetStringField(env, fsobj, ids[FS_FIELD_DEVNAME], fs->dev_name); JENV->SetStringField(env, fsobj, ids[FS_FIELD_SYS_TYPENAME], fs->sys_type_name); JENV->SetStringField(env, fsobj, ids[FS_FIELD_TYPENAME], fs->type_name); JENV->SetIntField(env, fsobj, ids[FS_FIELD_TYPE], fs->type); JENV->SetObjectArrayElement(env, fsarray, i, fsobj); } sigar_file_system_list_destroy(sigar, &fslist); return fsarray; } JNIEXPORT jobjectArray SIGAR_JNI(Sigar_getCpuInfoList) (JNIEnv *env, jobject sigar_obj) { int status; unsigned int i; sigar_cpu_info_list_t cpu_infos; jobjectArray cpuarray; jclass cls = SIGAR_FIND_CLASS("CpuInfo"); dSIGAR(NULL); if ((status = sigar_cpu_info_list_get(sigar, &cpu_infos)) != SIGAR_OK) { sigar_throw_error(env, jsigar, status); return NULL; } JAVA_SIGAR_INIT_FIELDS_CPUINFO(cls); cpuarray = JENV->NewObjectArray(env, cpu_infos.number, cls, 0); for (i=0; iAllocObject(env, cls); JAVA_SIGAR_SET_FIELDS_CPUINFO(cls, info_obj, cpu_infos.data[i]); JENV->SetObjectArrayElement(env, cpuarray, i, info_obj); } sigar_cpu_info_list_destroy(sigar, &cpu_infos); return cpuarray; } JNIEXPORT jobjectArray SIGAR_JNI(Sigar_getCpuListNative) (JNIEnv *env, jobject sigar_obj) { int status; unsigned int i; sigar_cpu_list_t cpulist; jobjectArray cpuarray; jclass cls = SIGAR_FIND_CLASS("Cpu"); dSIGAR(NULL); if ((status = sigar_cpu_list_get(sigar, &cpulist)) != SIGAR_OK) { sigar_throw_error(env, jsigar, status); return NULL; } JAVA_SIGAR_INIT_FIELDS_CPU(cls); cpuarray = JENV->NewObjectArray(env, cpulist.number, cls, 0); for (i=0; iAllocObject(env, cls); JAVA_SIGAR_SET_FIELDS_CPU(cls, info_obj, cpulist.data[i]); JENV->SetObjectArrayElement(env, cpuarray, i, info_obj); } sigar_cpu_list_destroy(sigar, &cpulist); return cpuarray; } JNIEXPORT jlongArray SIGAR_JNI(Sigar_getProcList) (JNIEnv *env, jobject sigar_obj) { int status; jlongArray procarray; sigar_proc_list_t proclist; jlong *pids = NULL; dSIGAR(NULL); if ((status = sigar_proc_list_get(sigar, &proclist)) != SIGAR_OK) { sigar_throw_error(env, jsigar, status); return NULL; } procarray = JENV->NewLongArray(env, proclist.number); if (sizeof(jlong) == sizeof(sigar_pid_t)) { pids = (jlong *)proclist.data; } else { unsigned int i; pids = (jlong *)malloc(sizeof(jlong) * proclist.number); for (i=0; iSetLongArrayRegion(env, procarray, 0, proclist.number, pids); if (pids != (jlong *)proclist.data) { free(pids); } sigar_proc_list_destroy(sigar, &proclist); return procarray; } JNIEXPORT jobjectArray SIGAR_JNI(Sigar_getProcArgs) (JNIEnv *env, jobject sigar_obj, jlong pid) { int status; unsigned int i; sigar_proc_args_t procargs; jobjectArray argsarray; jclass stringclass = JENV->FindClass(env, "java/lang/String"); dSIGAR(NULL); if ((status = sigar_proc_args_get(sigar, pid, &procargs)) != SIGAR_OK) { sigar_throw_error(env, jsigar, status); return NULL; } argsarray = JENV->NewObjectArray(env, procargs.number, stringclass, 0); for (i=0; iNewStringUTF(env, procargs.data[i]); JENV->SetObjectArrayElement(env, argsarray, i, s); } sigar_proc_args_destroy(sigar, &procargs); return argsarray; } typedef struct { JNIEnv *env; jobject map; jmethodID id; } jni_env_put_t; static int jni_env_getall(void *data, const char *key, int klen, char *val, int vlen) { jni_env_put_t *put = (jni_env_put_t *)data; JNIEnv *env = put->env; JENV->CallObjectMethod(env, put->map, put->id, JENV->NewStringUTF(env, key), JENV->NewStringUTF(env, val)); return SIGAR_OK; } JNIEXPORT jobject SIGAR_JNI(ProcEnv_getAll) (JNIEnv *env, jobject cls, jobject sigar_obj, jlong pid) { int status; sigar_proc_env_t procenv; jobject hashmap; jni_env_put_t put; jclass mapclass = JENV->FindClass(env, "java/util/HashMap"); jmethodID mapid = JENV->GetMethodID(env, mapclass, "", "()V"); jmethodID putid = JENV->GetMethodID(env, mapclass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)" "Ljava/lang/Object;"); dSIGAR(NULL); hashmap = JENV->NewObject(env, mapclass, mapid); put.env = env; put.id = putid; put.map = hashmap; procenv.type = SIGAR_PROC_ENV_ALL; procenv.env_getter = jni_env_getall; procenv.data = &put; if ((status = sigar_proc_env_get(sigar, pid, &procenv)) != SIGAR_OK) { JENV->DeleteLocalRef(env, hashmap); sigar_throw_error(env, jsigar, status); return NULL; } return hashmap; } typedef struct { JNIEnv *env; const char *key; int klen; jstring val; } jni_env_get_t; static int jni_env_getvalue(void *data, const char *key, int klen, char *val, int vlen) { jni_env_get_t *get = (jni_env_get_t *)data; JNIEnv *env = get->env; if ((get->klen == klen) && (strcmp(get->key, key) == 0)) { get->val = JENV->NewStringUTF(env, val); return !SIGAR_OK; /* foundit; stop iterating */ } return SIGAR_OK; } JNIEXPORT jstring SIGAR_JNI(ProcEnv_getValue) (JNIEnv *env, jobject cls, jobject sigar_obj, jlong pid, jstring key) { int status; sigar_proc_env_t procenv; jni_env_get_t get; dSIGAR(NULL); get.env = env; get.key = JENV->GetStringUTFChars(env, key, 0); get.klen = JENV->GetStringUTFLength(env, key); get.val = NULL; procenv.type = SIGAR_PROC_ENV_KEY; procenv.key = get.key; procenv.klen = get.klen; procenv.env_getter = jni_env_getvalue; procenv.data = &get; if ((status = sigar_proc_env_get(sigar, pid, &procenv)) != SIGAR_OK) { JENV->ReleaseStringUTFChars(env, key, get.key); sigar_throw_error(env, jsigar, status); return NULL; } JENV->ReleaseStringUTFChars(env, key, get.key); return get.val; } typedef struct { JNIEnv *env; jobject listobj; jmethodID id; } jni_proc_module_t; static int jni_proc_module_get(void *data, char *name, int len) { jni_proc_module_t *module = (jni_proc_module_t *)data; JNIEnv *env = module->env; JENV->CallBooleanMethod(env, module->listobj, module->id, JENV->NewStringUTF(env, name)); return SIGAR_OK; } JNIEXPORT jobject SIGAR_JNI(Sigar_getProcModulesNative) (JNIEnv *env, jobject sigar_obj, jlong pid) { int status; sigar_proc_modules_t procmods; jobject listobj; jni_proc_module_t module; jclass listclass = JENV->FindClass(env, "java/util/ArrayList"); jmethodID listid = JENV->GetMethodID(env, listclass, "", "()V"); jmethodID addid = JENV->GetMethodID(env, listclass, "add", "(Ljava/lang/Object;)" "Z"); dSIGAR(NULL); listobj = JENV->NewObject(env, listclass, listid); module.env = env; module.id = addid; module.listobj = listobj; procmods.module_getter = jni_proc_module_get; procmods.data = &module; if ((status = sigar_proc_modules_get(sigar, pid, &procmods)) != SIGAR_OK) { JENV->DeleteLocalRef(env, listobj); sigar_throw_error(env, jsigar, status); return NULL; } return listobj; } JNIEXPORT jdoubleArray SIGAR_JNI(Sigar_getLoadAverage) (JNIEnv *env, jobject sigar_obj) { int status; jlongArray avgarray; sigar_loadavg_t loadavg; dSIGAR(NULL); if ((status = sigar_loadavg_get(sigar, &loadavg)) != SIGAR_OK) { sigar_throw_error(env, jsigar, status); return NULL; } avgarray = JENV->NewDoubleArray(env, 3); JENV->SetDoubleArrayRegion(env, avgarray, 0, 3, loadavg.loadavg); return avgarray; } JNIEXPORT jobjectArray SIGAR_JNI(Sigar_getNetRouteList) (JNIEnv *env, jobject sigar_obj) { int status; unsigned int i; jarray routearray; jclass cls = SIGAR_FIND_CLASS("NetRoute"); sigar_net_route_list_t routelist; dSIGAR(NULL); if ((status = sigar_net_route_list_get(sigar, &routelist)) != SIGAR_OK) { sigar_throw_error(env, jsigar, status); return NULL; } JAVA_SIGAR_INIT_FIELDS_NETROUTE(cls); routearray = JENV->NewObjectArray(env, routelist.number, cls, 0); for (i=0; iAllocObject(env, cls); JAVA_SIGAR_SET_FIELDS_NETROUTE(cls, obj, routelist.data[i]); JENV->SetObjectArrayElement(env, routearray, i, obj); } sigar_net_route_list_destroy(sigar, &routelist); return routearray; } JNIEXPORT jobjectArray SIGAR_JNI(Sigar_getNetConnectionList) (JNIEnv *env, jobject sigar_obj, jint flags) { int status; unsigned int i; jarray connarray; jclass cls = SIGAR_FIND_CLASS("NetConnection"); sigar_net_connection_list_t connlist; dSIGAR(NULL); status = sigar_net_connection_list_get(sigar, &connlist, flags); if (status != SIGAR_OK) { sigar_throw_error(env, jsigar, status); return NULL; } JAVA_SIGAR_INIT_FIELDS_NETCONNECTION(cls); connarray = JENV->NewObjectArray(env, connlist.number, cls, 0); for (i=0; iAllocObject(env, cls); JAVA_SIGAR_SET_FIELDS_NETCONNECTION(cls, obj, connlist.data[i]); JENV->SetObjectArrayElement(env, connarray, i, obj); } sigar_net_connection_list_destroy(sigar, &connlist); return connarray; } JNIEXPORT jstring SIGAR_JNI(NetConnection_getTypeString) (JNIEnv *env, jobject obj) { jclass cls = JENV->GetObjectClass(env, obj); jfieldID field = JENV->GetFieldID(env, cls, "type", "I"); jint type = JENV->GetIntField(env, obj, field); return JENV->NewStringUTF(env, sigar_net_connection_type_get(type)); } /* XXX perhaps it would be better to duplicate these strings * in java land as static final so we dont create a new String * everytime. */ JNIEXPORT jstring SIGAR_JNI(FileInfo_getTypeString) (JNIEnv *env, jclass cls, jint type) { return JENV->NewStringUTF(env, sigar_file_attrs_type_string_get(type)); } JNIEXPORT jstring SIGAR_JNI(FileInfo_getPermissionsString) (JNIEnv *env, jclass cls, jlong perms) { char str[24]; return JENV->NewStringUTF(env, sigar_file_attrs_permissions_string_get(perms, str)); } JNIEXPORT jint SIGAR_JNI(FileInfo_getMode) (JNIEnv *env, jclass cls, jlong perms) { return sigar_file_attrs_mode_get(perms); } /* * copy of the generated FileAttrs_nativeGet function * but we call the lstat wrapper instead. */ JNIEXPORT void SIGAR_JNI(FileInfo_nativeGetLink) (JNIEnv *env, jobject obj, jobject sigar_obj, jstring name) { sigar_file_attrs_t s; int status; jclass cls = JENV->GetObjectClass(env, obj); const char *utf; dSIGAR_VOID; utf = JENV->GetStringUTFChars(env, name, 0); status = sigar_link_attrs_get(sigar, utf, &s); JENV->ReleaseStringUTFChars(env, name, utf); if (status != SIGAR_OK) { sigar_throw_error(env, jsigar, status); return; } JAVA_SIGAR_INIT_FIELDS_FILEATTRS(cls); JAVA_SIGAR_SET_FIELDS_FILEATTRS(cls, obj, s); } JNIEXPORT jlong SIGAR_JNI(Sigar_getProcPort) (JNIEnv *env, jobject sigar_obj, jlong port) { int status; sigar_pid_t pid; dSIGAR(0); #if defined(__linux__) || defined(WIN32) /* just thinking about implementing this on other platforms hurts */ if ((status = sigar_proc_port_get(sigar, (unsigned long)port, &pid)) != SIGAR_OK) { sigar_throw_error(env, jsigar, status); } #else status = SIGAR_ENOTIMPL; pid = -1; sigar_throw_error(env, jsigar, status); #endif return pid; } JNIEXPORT jobjectArray SIGAR_JNI(Sigar_getNetInterfaceList) (JNIEnv *env, jobject sigar_obj) { int status; unsigned int i; sigar_net_interface_list_t iflist; jobjectArray ifarray; jclass stringclass = JENV->FindClass(env, "java/lang/String"); dSIGAR(NULL); if ((status = sigar_net_interface_list_get(sigar, &iflist)) != SIGAR_OK) { sigar_throw_error(env, jsigar, status); return NULL; } ifarray = JENV->NewObjectArray(env, iflist.number, stringclass, 0); for (i=0; iNewStringUTF(env, iflist.data[i]); JENV->SetObjectArrayElement(env, ifarray, i, s); } sigar_net_interface_list_destroy(sigar, &iflist); return ifarray; } JNIEXPORT jstring SIGAR_JNI(Sigar_getPasswordNative) (JNIEnv *env, jclass classinstance, jstring prompt) { const char *prompt_str; char *password; if (getenv("NO_NATIVE_GETPASS")) { sigar_throw_notimpl(env, "disabled with $NO_NATIVE_GETPASS"); return NULL; } prompt_str = JENV->GetStringUTFChars(env, prompt, 0); password = sigar_password_get(prompt_str); JENV->ReleaseStringUTFChars(env, prompt, prompt_str); return JENV->NewStringUTF(env, password); } JNIEXPORT jstring SIGAR_JNI(Sigar_getFQDN) (JNIEnv *env, jobject sigar_obj) { char fqdn[SIGAR_FQDN_LEN]; int status; dSIGAR(NULL); if ((status = sigar_fqdn_get(sigar, fqdn, sizeof(fqdn))) != SIGAR_OK) { sigar_throw_error(env, jsigar, status); return NULL; } return JENV->NewStringUTF(env, fqdn); } #include "sigar_getline.h" JNIEXPORT jstring SIGAR_JNI(util_Getline_getline) (JNIEnv *env, jobject sigar_obj, jstring prompt) { const char *prompt_str; char *line; jboolean is_copy; prompt_str = JENV->GetStringUTFChars(env, prompt, &is_copy); line = sigar_getline((char *)prompt_str); if (is_copy) { JENV->ReleaseStringUTFChars(env, prompt, prompt_str); } if ((line == NULL) || sigar_getline_eof()) { jclass eof_ex = JENV->FindClass(env, "java/io/EOFException"); JENV->ThrowNew(env, eof_ex, ""); return NULL; } return JENV->NewStringUTF(env, line); } JNIEXPORT void SIGAR_JNI(util_Getline_histadd) (JNIEnv *env, jobject sigar_obj, jstring hist) { const char *hist_str; jboolean is_copy; hist_str = JENV->GetStringUTFChars(env, hist, &is_copy); sigar_getline_histadd((char *)hist_str); if (is_copy) { JENV->ReleaseStringUTFChars(env, hist, hist_str); } } JNIEXPORT void SIGAR_JNI(util_Getline_histinit) (JNIEnv *env, jobject sigar_obj, jstring hist) { const char *hist_str; jboolean is_copy; hist_str = JENV->GetStringUTFChars(env, hist, &is_copy); sigar_getline_histinit((char *)hist_str); if (is_copy) { JENV->ReleaseStringUTFChars(env, hist, hist_str); } } static struct { JNIEnv *env; jobject obj; jmethodID id; jclass clazz; } jsigar_completer; static int jsigar_getline_completer(char *buffer, int offset, int *pos) { JNIEnv *env = jsigar_completer.env; jstring jbuffer; jstring completion; const char *line; int len, cur; jboolean is_copy; jbuffer = JENV->NewStringUTF(env, buffer); completion = JENV->CallObjectMethod(env, jsigar_completer.obj, jsigar_completer.id, jbuffer); if (JENV->ExceptionOccurred(env)) { JENV->ExceptionDescribe(env); return 0; } if (!completion) { return 0; } line = JENV->GetStringUTFChars(env, completion, &is_copy); len = JENV->GetStringUTFLength(env, completion); cur = *pos; if (len != cur) { strcpy(buffer, line); *pos = len; } if (is_copy) { JENV->ReleaseStringUTFChars(env, completion, line); } return cur; } JNIEXPORT void SIGAR_JNI(util_Getline_setCompleter) (JNIEnv *env, jclass classinstance, jobject completer) { if (completer == NULL) { sigar_getline_completer_set(NULL); return; } jsigar_completer.env = env; jsigar_completer.obj = completer; jsigar_completer.clazz = JENV->GetObjectClass(env, completer); jsigar_completer.id = JENV->GetMethodID(env, jsigar_completer.clazz, "complete", "(Ljava/lang/String;)Ljava/lang/String;"); sigar_getline_completer_set(jsigar_getline_completer); } JNIEXPORT void SIGAR_JNI(util_Getline_redraw) (JNIEnv *env, jobject obj) { sigar_getline_redraw(); } JNIEXPORT void SIGAR_JNI(util_Getline_reset) (JNIEnv *env, jobject obj) { sigar_getline_reset(); } static const char *log_methods[] = { "fatal", /* SIGAR_LOG_FATAL */ "error", /* SIGAR_LOG_ERROR */ "warn", /* SIGAR_LOG_WARN */ "info", /* SIGAR_LOG_INFO */ "debug", /* SIGAR_LOG_DEBUG */ /* XXX trace is only in commons-logging??? */ "debug", /* SIGAR_LOG_TRACE */ }; static void jsigar_log_impl(sigar_t *sigar, void *data, int level, char *message) { jni_sigar_t *jsigar = (jni_sigar_t *)data; JNIEnv *env = jsigar->env; jobject logger = jsigar->logger; jobject message_obj; /* XXX should cache method id lookups */ jmethodID id = JENV->GetMethodID(env, JENV->GetObjectClass(env, logger), log_methods[level], "(Ljava/lang/Object;)V"); if (JENV->ExceptionOccurred(env)) { JENV->ExceptionDescribe(env); return; } message_obj = (jobject)JENV->NewStringUTF(env, message); JENV->CallVoidMethod(env, logger, id, message_obj); } JNIEXPORT void SIGAR_JNI(SigarLog_setLogger) (JNIEnv *env, jclass classinstance, jobject sigar_obj, jobject logger) { dSIGAR_VOID; jsigar->env = env; if (jsigar->logger != NULL) { JENV->DeleteGlobalRef(env, jsigar->logger); jsigar->logger = NULL; } if (logger) { jsigar->logger = JENV->NewGlobalRef(env, logger); sigar_log_impl_set(sigar, jsigar, jsigar_log_impl); } else { sigar_log_impl_set(sigar, NULL, NULL); } } JNIEXPORT void SIGAR_JNI(SigarLog_setLevel) (JNIEnv *env, jclass classinstance, jobject sigar_obj, jint level) { dSIGAR_VOID; sigar_log_level_set(sigar, level); } /* * XXX temporary function for ptql to map windows service to pid. * in the future would better to integrate win32bindings w/ sigar. */ #ifdef WIN32 typedef struct _SERVICE_STATUS_PROCESS { DWORD dwServiceType; DWORD dwCurrentState; DWORD dwControlsAccepted; DWORD dwWin32ExitCode; DWORD dwServiceSpecificExitCode; DWORD dwCheckPoint; DWORD dwWaitHint; DWORD dwProcessId; DWORD dwServiceFlags; } SERVICE_STATUS_PROCESS; typedef enum { SC_STATUS_PROCESS_INFO = 0 } SC_STATUS_TYPE; typedef BOOL (CALLBACK *QueryServiceStatusExFunc)(SC_HANDLE, SC_STATUS_TYPE, LPBYTE, DWORD, LPDWORD); #endif JNIEXPORT jlong SIGAR_JNI(Sigar_getServicePid) (JNIEnv *env, jobject sigar_obj, jstring jname) { #ifdef WIN32 const char *name; jboolean is_copy; jlong pid = 0; DWORD err = ERROR_SUCCESS; SC_HANDLE mgr; dSIGAR(0); name = JENV->GetStringUTFChars(env, jname, &is_copy); mgr = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS); if (mgr) { HANDLE svc = OpenService(mgr, name, SERVICE_ALL_ACCESS); if (svc) { SERVICE_STATUS_PROCESS status; DWORD bytes; HANDLE lib; if ((lib = LoadLibrary("advapi32.dll"))) { QueryServiceStatusExFunc status_query; status_query = (QueryServiceStatusExFunc) GetProcAddress(lib, "QueryServiceStatusEx"); if (!status_query) { err = SIGAR_ENOTIMPL; } else if (status_query(svc, SC_STATUS_PROCESS_INFO, (LPBYTE)&status, sizeof(status), &bytes)) { pid = status.dwProcessId; } else { err = GetLastError(); } FreeLibrary(lib); } else { err = GetLastError(); } CloseServiceHandle(svc); } else { err = GetLastError(); } CloseServiceHandle(mgr); } else { err = GetLastError(); } if (is_copy) { JENV->ReleaseStringUTFChars(env, jname, name); } if (err != ERROR_SUCCESS) { sigar_throw_error(env, jsigar, err); } return pid; #else dSIGAR(0); sigar_throw_error(env, jsigar, SIGAR_ENOTIMPL); return 0; #endif }