sigar/bindings/java/src/jni/win32/eventlog.c
2009-11-09 16:27:22 -08:00

415 lines
11 KiB
C

/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program is distributed
* in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
#ifdef WIN32
#define UNICODE
#define _UNICODE
#include "javasigar.h"
#include "win32bindings.h"
#define MAX_MSG_LENGTH 8192
#define MAX_ERROR_LENGTH 1024
#define REG_MSGFILE_ROOT L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\"
#define FILESEP L";"
#define STRING_SIG "Ljava/lang/String;"
#define UNICODE_SetStringField(field, str) \
id = JENV->GetFieldID(env, cls, field, STRING_SIG); \
value = JENV->NewString(env, (const jchar *)str, wcslen(str)); \
JENV->SetObjectField(env, obj, id, value)
#define ARRLEN(arr) (sizeof(arr) / sizeof(arr[0]))
static void win32_set_pointer(JNIEnv *env, jobject obj, const void *ptr)
{
jfieldID pointer_field;
int pointer_int;
jclass cls;
cls = JENV->GetObjectClass(env, obj);
pointer_field = JENV->GetFieldID(env, cls, "eventLogHandle", "I");
pointer_int = (int)ptr;
JENV->SetIntField(env, obj, pointer_field, pointer_int);
}
static HANDLE win32_get_pointer(JNIEnv *env, jobject obj)
{
jfieldID pointer_field;
HANDLE h;
jclass cls;
cls = JENV->GetObjectClass(env, obj);
pointer_field = JENV->GetFieldID(env, cls, "eventLogHandle", "I");
h = (HANDLE)JENV->GetIntField(env, obj, pointer_field);
if (!h) {
win32_throw_exception(env, "Event log not opened");
}
return h;
}
static int get_messagefile_dll(LPWSTR app, LPWSTR source, LPWSTR entry, LPWSTR dllfile)
{
HKEY hk;
WCHAR buf[MAX_MSG_LENGTH];
DWORD type, data = sizeof(buf);
LONG rc;
wcscpy(buf, REG_MSGFILE_ROOT);
wcscat(buf, app);
wcscat(buf, L"\\");
wcscat(buf, source);
rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf,
0, KEY_READ, &hk);
if (rc) {
return rc;
}
rc = RegQueryValueEx(hk, entry, NULL, &type,
(LPBYTE)buf, &data);
if (rc) {
RegCloseKey(hk);
return rc;
}
wcsncpy(dllfile, buf, MAX_MSG_LENGTH);
dllfile[MAX_MSG_LENGTH-1] = '\0';
RegCloseKey(hk);
return ERROR_SUCCESS;
}
static int get_formatted_message(EVENTLOGRECORD *pevlr,
DWORD id,
LPWSTR dllfile,
LPWSTR msg)
{
LPVOID msgbuf = NULL;
WCHAR msgdll[MAX_MSG_LENGTH];
LPWSTR insert_strs[56], ptr;
int i, max = ARRLEN(insert_strs);
const DWORD flags =
FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_ARGUMENT_ARRAY |
FORMAT_MESSAGE_MAX_WIDTH_MASK;
if (!ExpandEnvironmentStrings(dllfile, msgdll, ARRLEN(msgdll))) {
return GetLastError();
}
memset(insert_strs, '\0', sizeof(insert_strs));
if (pevlr) {
ptr = (LPWSTR)((LPBYTE)pevlr + pevlr->StringOffset);
for (i = 0; i < pevlr->NumStrings && i < max; i++) {
insert_strs[i] = ptr;
ptr += wcslen(ptr) + 1;
}
}
ptr = wcstok(msgdll, FILESEP);
while (ptr) {
HINSTANCE hlib;
hlib = LoadLibraryEx(ptr, NULL,
LOAD_LIBRARY_AS_DATAFILE);
if (hlib) {
FormatMessage(flags,
hlib,
id,
MAKELANGID(LANG_NEUTRAL, SUBLANG_ENGLISH_US),
(LPWSTR) &msgbuf,
sizeof(msgbuf), //min bytes w/ FORMAT_MESSAGE_ALLOCATE_BUFFER
(va_list *)insert_strs);
FreeLibrary(hlib);
if (msgbuf) {
break;
}
}
ptr = wcstok(NULL, FILESEP);
}
if (msgbuf) {
wcsncpy(msg, msgbuf, MAX_MSG_LENGTH);
msg[MAX_MSG_LENGTH-1] = '\0';
LocalFree(msgbuf);
return ERROR_SUCCESS;
}
else {
return !ERROR_SUCCESS;
}
}
static int get_formatted_event_message(EVENTLOGRECORD *pevlr, LPWSTR name, LPWSTR source, LPWSTR msg)
{
WCHAR dllfile[MAX_MSG_LENGTH];
if (get_messagefile_dll(name, source, L"EventMessageFile", dllfile) != ERROR_SUCCESS) {
return !ERROR_SUCCESS;
}
return get_formatted_message(pevlr, pevlr->EventID, dllfile, msg);
}
static int get_formatted_event_category(EVENTLOGRECORD *pevlr, LPWSTR name, LPWSTR source, LPWSTR msg)
{
WCHAR dllfile[MAX_MSG_LENGTH];
if (get_messagefile_dll(name, source, L"CategoryMessageFile", dllfile) != ERROR_SUCCESS) {
return !ERROR_SUCCESS;
}
return get_formatted_message(NULL, pevlr->EventCategory, dllfile, msg);
}
JNIEXPORT void SIGAR_JNI(win32_EventLog_openlog)
(JNIEnv *env, jobject obj, jstring lpSourceName)
{
HANDLE h;
LPWSTR name;
name = (LPWSTR)JENV->GetStringChars(env, lpSourceName, NULL);
h = OpenEventLog(NULL, name);
if (h == NULL) {
char buf[MAX_ERROR_LENGTH];
DWORD lastError = GetLastError();
sprintf(buf, "Unable to open event log: %d", lastError);
JENV->ReleaseStringChars(env, lpSourceName, name);
win32_throw_exception(env, buf);
return;
}
JENV->ReleaseStringChars(env, lpSourceName, name);
/* Save the handle for later use */
win32_set_pointer(env, obj, h);
}
JNIEXPORT void SIGAR_JNI(win32_EventLog_close)
(JNIEnv *env, jobject obj)
{
HANDLE h = win32_get_pointer(env, obj);
CloseEventLog(h);
win32_set_pointer(env, obj, NULL);
}
JNIEXPORT jint SIGAR_JNI(win32_EventLog_getNumberOfRecords)
(JNIEnv *env, jobject obj)
{
DWORD records;
HANDLE h = win32_get_pointer(env, obj);
if (!GetNumberOfEventLogRecords(h, &records)) {
win32_throw_last_error(env);
return 0;
}
return records;
}
JNIEXPORT jint SIGAR_JNI(win32_EventLog_getOldestRecord)
(JNIEnv *env, jobject obj)
{
DWORD oldest;
HANDLE h = win32_get_pointer(env, obj);
if (!GetOldestEventLogRecord(h, &oldest)) {
win32_throw_last_error(env);
return 0;
}
return oldest;
}
JNIEXPORT jobject SIGAR_JNI(win32_EventLog_readlog)
(JNIEnv *env, jobject obj, jstring jname, jint recordOffset)
{
EVENTLOGRECORD *pevlr;
BYTE buffer[8192];
WCHAR msg[MAX_MSG_LENGTH];
DWORD dwRead, dwNeeded;
LPWSTR source, machineName;
HANDLE h;
BOOL rv;
jclass cls = WIN32_FIND_CLASS("EventLogRecord");
jfieldID id;
jstring value;
LPWSTR name;
BOOL has_category = FALSE; /* 1.6.x compat */
h = win32_get_pointer(env, obj);
pevlr = (EVENTLOGRECORD *)&buffer;
rv = ReadEventLog(h,
EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ,
recordOffset,
pevlr,
sizeof(buffer),
&dwRead,
&dwNeeded);
if (!rv) {
char buf[MAX_ERROR_LENGTH];
DWORD lastError = GetLastError();
if (lastError == ERROR_INSUFFICIENT_BUFFER) {
/* XXX need to handle this */
sprintf(buf, "Buffer size (%d) too small (%d needed)",
sizeof(buffer), dwNeeded);
}
else {
sprintf(buf, "Error reading from the event log: %d", lastError);
}
win32_throw_exception(env, buf);
return NULL;
}
obj = JENV->AllocObject(env, cls);
id = JENV->GetFieldID(env, cls, "recordNumber", "J");
JENV->SetLongField(env, obj, id, pevlr->RecordNumber);
id = JENV->GetFieldID(env, cls, "timeGenerated", "J");
JENV->SetLongField(env, obj, id, pevlr->TimeGenerated);
id = JENV->GetFieldID(env, cls, "timeWritten", "J");
JENV->SetLongField(env, obj, id, pevlr->TimeWritten);
id = JENV->GetFieldID(env, cls, "eventId", "J");
JENV->SetLongField(env, obj, id, pevlr->EventID);
id = JENV->GetFieldID(env, cls, "eventType", "S");
JENV->SetShortField(env, obj, id, pevlr->EventType);
if (!JENV->ExceptionOccurred(env)) { /* careful not to clear any existing exception */
id = JENV->GetFieldID(env, cls, "category", "S");
if (JENV->ExceptionOccurred(env)) {
/* older version of sigar.jar being used with sigar.dll */
JENV->ExceptionClear(env);
}
else {
has_category = TRUE;
JENV->SetShortField(env, obj, id, pevlr->EventCategory);
}
}
/* Extract string data from the end of the structure. Lame. */
source = (LPWSTR)((LPBYTE)pevlr + sizeof(EVENTLOGRECORD));
UNICODE_SetStringField("source", source);
name = (LPWSTR)JENV->GetStringChars(env, jname, NULL);
/* Get the formatted message */
if ((pevlr->NumStrings > 0) &&
(get_formatted_event_message(pevlr, name, source, msg) == ERROR_SUCCESS))
{
UNICODE_SetStringField("message", msg);
}
else if (pevlr->NumStrings > 0) {
LPWSTR tmp = (LPWSTR)((LPBYTE)pevlr + pevlr->StringOffset);
UNICODE_SetStringField("message", tmp);
}
/* Get the formatted category */
if (has_category &&
(get_formatted_event_category(pevlr, name, source, msg) == ERROR_SUCCESS))
{
UNICODE_SetStringField("categoryString", msg);
}
JENV->ReleaseStringChars(env, jname, name);
/* Increment up to the machine name. */
machineName = (LPWSTR)((LPBYTE)pevlr + sizeof(EVENTLOGRECORD) +
(wcslen(source) + 1) * sizeof(WCHAR));
UNICODE_SetStringField("computerName", machineName);
/* Get user id info */
if (pevlr->UserSidLength > 0) {
WCHAR name[256];
WCHAR domain[256];
DWORD namelen = ARRLEN(name);
DWORD domainlen = ARRLEN(domain);
DWORD len;
SID_NAME_USE snu;
PSID sid;
sid = (PSID)((LPBYTE)pevlr + pevlr->UserSidOffset);
if (LookupAccountSid(NULL, sid, name, &namelen, domain,
&domainlen, &snu)) {
UNICODE_SetStringField("user", name);
}
}
return obj;
}
JNIEXPORT void SIGAR_JNI(win32_EventLog_waitForChange)
(JNIEnv *env, jobject obj, jint timeout)
{
HANDLE h, hEvent;
DWORD millis;
h = win32_get_pointer(env, obj);
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (hEvent == NULL) {
win32_throw_exception(env, "Unable to create event");
return;
}
if (timeout == -1)
millis = INFINITE;
else
millis = timeout;
if(!(NotifyChangeEventLog(h, hEvent))) {
char buf[MAX_ERROR_LENGTH];
sprintf(buf, "Error registering for event log to change: %d",
GetLastError());
win32_throw_exception(env, buf);
return;
}
if (WaitForSingleObject(hEvent, millis) == WAIT_FAILED)
{
char buf[MAX_ERROR_LENGTH];
sprintf(buf, "Error waiting for event log change: %d",
GetLastError());
win32_throw_exception(env, buf);
}
return;
}
#endif /* WIN32 */