aboutsummaryrefslogtreecommitdiffstats
path: root/lib/os_mon/c_src/nteventlog
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/os_mon/c_src/nteventlog
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/os_mon/c_src/nteventlog')
-rw-r--r--lib/os_mon/c_src/nteventlog/elog_format.c173
-rw-r--r--lib/os_mon/c_src/nteventlog/elog_format.h40
-rw-r--r--lib/os_mon/c_src/nteventlog/elog_global.h57
-rw-r--r--lib/os_mon/c_src/nteventlog/elog_main.c504
-rw-r--r--lib/os_mon/c_src/nteventlog/elog_pipe_stdin.c151
-rw-r--r--lib/os_mon/c_src/nteventlog/elog_pipe_stdin.h90
-rw-r--r--lib/os_mon/c_src/nteventlog/elog_registry.c295
-rw-r--r--lib/os_mon/c_src/nteventlog/elog_registry.h67
-rw-r--r--lib/os_mon/c_src/nteventlog/elog_util.c73
-rw-r--r--lib/os_mon/c_src/nteventlog/elog_util.h79
10 files changed, 1529 insertions, 0 deletions
diff --git a/lib/os_mon/c_src/nteventlog/elog_format.c b/lib/os_mon/c_src/nteventlog/elog_format.c
new file mode 100644
index 0000000000..c9fb6b7e1a
--- /dev/null
+++ b/lib/os_mon/c_src/nteventlog/elog_format.c
@@ -0,0 +1,173 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#include "elog_global.h"
+#include "elog_format.h"
+
+/*
+ * The Newline treatment bits of FormatMessage
+ * This value should suppress all other than hardcoded newlines
+ */
+#define NL_TREATMENT FORMAT_MESSAGE_MAX_WIDTH_MASK
+
+/*
+ * Expands %%NNN formats in strings with strings from a
+ * ParameterMessageFile (open).
+ * A return of NULL means there's nothing to expand
+ * or that the buffer is to small, which probably means the
+ * same thing to the caller, that is use the
+ * original string as it is.
+ */
+static char *expand_message(char *toexpand,
+ HINSTANCE paramlib,
+ char *buff, int bufflen){
+ char *oldpos;
+ int buffpos = 0;
+ char *pos = toexpand;
+ char *end;
+ unsigned long num;
+ char *replbuff = malloc(bufflen);
+ char *repl;
+ int replaced = 0;
+
+ while((oldpos = pos, pos = strstr(pos,"%%"))){
+ num = strtoul(pos + 2, &end, 0);
+ replaced = 1;
+ if(end == pos + 2 || num == 0){
+ repl = "%%";
+ } else {
+ if(!FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |
+ FORMAT_MESSAGE_IGNORE_INSERTS |
+ NL_TREATMENT,
+ (LPCVOID) paramlib,
+ (DWORD) num,
+ DEFAULT_LANGID,
+ replbuff,
+ (DWORD) bufflen,
+ NULL)){
+ repl = ""; /* this is how the event logger treats it... */
+ } else {
+ repl = replbuff;
+ }
+ }
+ if((int)(buffpos + strlen(repl) + (pos - oldpos) + 1) > bufflen){
+ free(replbuff);
+ return NULL;
+ }
+ strncpy(&(buff[buffpos]),oldpos, pos - oldpos);
+ buffpos += pos - oldpos;
+ strcpy(&(buff[buffpos]), repl);
+ buffpos += strlen(repl);
+ pos = end;
+ }
+ free(replbuff);
+ if(!replaced)
+ return NULL;
+ if((int) (buffpos + strlen(oldpos) + 1) > bufflen)
+ return NULL;
+ strcpy(&(buff[buffpos]),oldpos);
+ return buff;
+}
+
+/*
+ * A lot to free when returning from format_message, lets make it easier
+ */
+static char *fm_free_up(char **argv, char *tmpbuff,
+ char * tmpbuff2,
+ HINSTANCE elibrary,
+ HINSTANCE plibrary){
+ if(plibrary != NULL){
+ FreeLibrary(plibrary);
+ while(*argv)
+ free(*argv++);
+ }
+ free(tmpbuff);
+ free(tmpbuff2);
+ if(elibrary != NULL)
+ FreeLibrary(elibrary);
+ return NULL;
+}
+
+#define FM_RETURN(X) \
+return (fm_free_up(argv, tmpbuff, tmpbuff2, elibrary, plibrary), (X))
+
+/*
+ * Formats an eventlog message into a string buffer.
+ * Returns NULL if message could not be formatted (buffer to small or
+ * library error).
+ */
+char *format_message(MessageFiles mf, DWORD id,
+ char *strings, int numstrings,
+ char *buff, int bufflen){
+ char *argv[MAX_PARAM_STRINGS];
+ int argc,i;
+ HINSTANCE elibrary = NULL;
+ HINSTANCE plibrary = NULL;
+ char *tmpbuff = malloc(bufflen);
+ char *tmpbuff2 = malloc(bufflen);
+
+ for(argc=0;argc < numstrings && argc < MAX_PARAM_STRINGS - 1; ++argc)
+ argv[argc] =
+ (argc) ? argv[argc - 1] + strlen(argv[argc - 1]) + 1 : strings;
+
+ argv[argc] = NULL;
+
+ if((elibrary = LoadLibraryEx(mf.event, NULL, DONT_RESOLVE_DLL_REFERENCES))
+ == NULL)
+ FM_RETURN(NULL);
+
+ if(!FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |
+ FORMAT_MESSAGE_IGNORE_INSERTS | NL_TREATMENT,
+ (LPCVOID) elibrary,
+ id,
+ DEFAULT_LANGID,
+ tmpbuff2,
+ (DWORD) bufflen,
+ NULL)){
+ FM_RETURN(NULL);
+ }
+
+ if(mf.param != NULL)
+ plibrary = LoadLibraryEx(mf.param, NULL, DONT_RESOLVE_DLL_REFERENCES);
+
+ if(plibrary){
+ for(i=0;argv[i];++i)
+ if(expand_message(argv[i], plibrary, tmpbuff, bufflen) != NULL)
+ argv[i] = strdup(tmpbuff);
+ else
+ argv[i] = strdup(argv[i]); /* All gets malloced, so I don't have to
+ bother what to free... */
+ if(expand_message(tmpbuff2, plibrary, tmpbuff, bufflen) != NULL)
+ strcpy(tmpbuff2,tmpbuff);
+ }
+
+ if(!FormatMessage(FORMAT_MESSAGE_FROM_STRING |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY | NL_TREATMENT,
+ (LPCVOID) tmpbuff2,
+ id,
+ DEFAULT_LANGID,
+ buff,
+ (DWORD) bufflen,
+ argv)){
+ FM_RETURN(NULL);
+ }
+
+ FM_RETURN(buff);
+
+}
+#undef FM_RETURN
diff --git a/lib/os_mon/c_src/nteventlog/elog_format.h b/lib/os_mon/c_src/nteventlog/elog_format.h
new file mode 100644
index 0000000000..3fb19367ab
--- /dev/null
+++ b/lib/os_mon/c_src/nteventlog/elog_format.h
@@ -0,0 +1,40 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef _ELOG_FORMAT_H
+#define _ELOG_FORMAT_H
+/*
+ * Module: elog_format
+ * Purpouse: Format messages in the eventlog.
+ * ToDo: Maximum buffersize is used...
+ */
+
+#include "elog_global.h"
+
+char *format_message(MessageFiles mf, DWORD id,
+ char *strings, int numstrings,
+ char *buff, int bufflen);
+/*
+ * Formats an eventlog message with the messagefiles
+ * in mf, the ID id, the stringarray strings,
+ * containing numstrings strings into buff.
+ * if bufflen is to small or anything else failes,
+ * the return value is NULL.
+ */
+
+#endif /* _ELOG_FORMAT_H */
diff --git a/lib/os_mon/c_src/nteventlog/elog_global.h b/lib/os_mon/c_src/nteventlog/elog_global.h
new file mode 100644
index 0000000000..f992b7184f
--- /dev/null
+++ b/lib/os_mon/c_src/nteventlog/elog_global.h
@@ -0,0 +1,57 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef _ELOG_GLOBAL_H
+#define _ELOG_GLOBAL_H
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <process.h>
+
+#define STRICT
+#define WIN32_LEAN_AND_MEAN
+#include "windows.h"
+
+#ifdef _DEBUG
+/*#define HARDDEBUG*/
+#define DEBUG
+#endif
+
+/*
+ * Compile time limits
+ */
+#define SMALLBUFSIZ 512
+#define BIGBUFSIZ 2048
+#define MAX_PARAM_STRINGS 200
+#define MAX_FACILITY_NAME 100
+
+/*
+ * Structure containing message file names
+ */
+typedef struct _message_files {
+ char *event;
+ char *param;
+} MessageFiles;
+
+/*
+ * How to get the default language
+ */
+#define DEFAULT_LANGID MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)
+
+#endif /* _ELOG_GLOBAL_H */
diff --git a/lib/os_mon/c_src/nteventlog/elog_main.c b/lib/os_mon/c_src/nteventlog/elog_main.c
new file mode 100644
index 0000000000..f79f32c8ef
--- /dev/null
+++ b/lib/os_mon/c_src/nteventlog/elog_main.c
@@ -0,0 +1,504 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/*
+ * Module: elog_main
+ * Purpouse: Main program and logic in the nteventlog program
+ * which waits for logging events and sends them to erlang.
+ * At startup, the registry keys for the identifier given on the
+ * command line are read to see what log record was the last
+ * displayed for this identifier. All "new" records are then
+ * displayed. After that the program waits for new events to arrive
+ * and displays them (sends them to erlang). If stdin is a pipe
+ * (not a console) an ACK is requested for every entry displayed.
+ * when the ACK is received, the registry entries for the identifier
+ * is updated, so that next time the program starts, only the new
+ * entries are displayed.
+ */
+#include "elog_global.h"
+#include "elog_util.h"
+#include "elog_pipe_stdin.h"
+#include "elog_format.h"
+#include "elog_registry.h"
+
+/*
+ * A race condition in the event log notification and the
+ * event log reading results in us having to retry reading the
+ * eventlog after some time. One second seems to do it...
+ */
+#define RETRY_TIMEOUT 1000
+
+/*
+ * Constants for the logging formats.
+ */
+#define LOG_FORMAT "%s [%s] %s, %s: %s\n"
+#define PIPE_LOG_FORMAT "%dH%s%dH%s%dH%s%dH%s%dH%s"
+#define PIPE_LOG_ACK "A"
+#define PIPE_LOG_EXTRA (5*10) /* 5 int */
+#define ACK_MAX 100
+#define TIME_FORMAT "%d-%b-%Y %H:%M:%S GMT"
+/* 2 3 4 2 2 2 */
+#define TIME_BUFSIZ 25
+#define CANT_FORMAT_MESSAGE "[EventLogReader unable to format message text]"
+
+/* the default registry identification */
+#define DEFAULT_IDENT "DefaultIdent"
+
+/*#define HARDDEBUG*/
+
+/* Flag set if eventlog is purged and need reopening.*/
+static int reopen_event_log = 0;
+
+/*
+ * Calculates the needed buffersize for a record in the eventlog.
+ * if recordnum == 0, looks at next record, otherwise looks
+ * at the record with the given number.
+ */
+static DWORD needed(HANDLE elog, DWORD recordnum){
+ EVENTLOGRECORD dummy;
+ DWORD red, need;
+ DWORD last_error;
+ DWORD flags =
+ EVENTLOG_FORWARDS_READ |
+ ((recordnum) ? EVENTLOG_SEEK_READ : EVENTLOG_SEQUENTIAL_READ);
+#ifdef HARDDEBUG
+ fprintf(stderr,"Calculating need when recordnum = %lu\n",recordnum);
+#endif
+ if(!ReadEventLog(elog,
+ flags,
+ recordnum,
+ &dummy,
+ (DWORD) sizeof(EVENTLOGRECORD),
+ &red,
+ &need) &&
+ (last_error = GetLastError()) == ERROR_INSUFFICIENT_BUFFER){
+ return need;
+ } else if(last_error == ERROR_EVENTLOG_FILE_CHANGED){
+ reopen_event_log = 1;
+ return (DWORD) 0;
+ } else {
+#ifdef HARDDEBUG
+ output_error(last_error,"needed() failed to read eventlog");
+#endif
+ return (DWORD) 0;
+ }
+}
+
+
+/*
+ * Checks (any type of) stdin for end of file.
+ * Expects data present on stdin.
+ */
+BOOL eof_on_stdin(void){
+ HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
+ char x[1];
+ DWORD y;
+ INPUT_RECORD input;
+ DWORD red;
+ static int state = 1; /* Return pressed = 1, ^Z after that = 2 */
+
+ if(!console_stdin()){
+ return peek_pipe_stdin_eof();
+ }
+ /* Console input, may be just about every type of event, look for
+ ^Z pressed... */
+ if(!ReadConsoleInput(in,&input,1,&red))
+ return FALSE;
+ if(input.EventType != KEY_EVENT)
+ return FALSE;
+ if(input.Event.KeyEvent.bKeyDown){
+ switch(input.Event.KeyEvent.uChar.AsciiChar){
+ case 0:
+ break;
+ case 13:
+ x[0] = '\r';
+ WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),"\r\n",2,&y,NULL);
+ if(state == 2)
+ return TRUE;
+ else
+ state = 1;
+ break;
+ case 26:
+ if(state == 1)
+ state = 2;
+ WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),"^Z",2,&y,NULL);
+ break;
+ default:
+ if(((unsigned char) input.Event.KeyEvent.uChar.AsciiChar) < ' '){
+ WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),"^",1,&y,NULL);
+ x[0] = input.Event.KeyEvent.uChar.AsciiChar + '@';
+ } else
+ x[0] = input.Event.KeyEvent.uChar.AsciiChar;
+ WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),x,1,&y,NULL);
+ state = 0;
+ break;
+ }
+ return FALSE;
+ }
+ return FALSE;
+}
+
+/*
+ * Writes eventlog entries to erlang and requires ACK for
+ * each record.
+ */
+BOOL data_to_pipe(char *string, char *answer, int answer_siz){
+ unsigned char len[2];
+ unsigned char *ptr;
+ int siz = strlen(string);
+ HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
+ HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
+ DWORD written, red;
+ DWORD left;
+
+ len[0] = (siz >> 8) & 0xFF;
+ len[1] = siz & 0xFF;
+ if(!WriteFile(out, len, 2,
+ &written, NULL) || written != 2)
+ return FALSE;
+ if(!WriteFile(out, string, siz, &written, NULL) ||
+ written != (DWORD) siz)
+ return FALSE;
+ /* Read ACK from erlang */
+ left = 2;
+ ptr = len;
+ for(;;){
+ if(!(red = read_pipe_stdin(ptr, left)))
+ return FALSE;
+ else if(red < left){
+ ptr += red;
+ left -= red;
+ } else {
+ break;
+ }
+ }
+ siz = len[0] << 8 | len[1];
+
+ if(siz >= answer_siz - 1)
+ return FALSE;
+
+ left = siz;
+ ptr = (unsigned char *) answer;
+ for(;;){
+ if(!(red = read_pipe_stdin(ptr, left))){
+ return FALSE;
+ } else if(red < left){
+ ptr += red;
+ left -= red;
+ } else {
+ break;
+ }
+ }
+ answer[siz] = '\0';
+ return TRUE;
+}
+
+/*
+ * The actual writing of records.
+ * Behaves differently if stdout is a pipe (erlang)
+ * or a console (test run).
+ */
+
+BOOL output_record(char *category, EVENTLOGRECORD *event){
+ char *strbeg, *fac, *sev;
+ char eventfilename[MAX_PATH];
+ char paramfilename[MAX_PATH];
+ char bigbuff[BIGBUFSIZ];
+ MessageFiles mf;
+ char tbuff[TIME_BUFSIZ];
+ BOOL ret;
+ DWORD written;
+ char *buff;
+ char ackbuff[ACK_MAX];
+
+ mf = get_messagefiles(category,((char *)event)+sizeof(EVENTLOGRECORD),
+ eventfilename, MAX_PATH,
+ paramfilename, MAX_PATH);
+ if(!mf.event){
+ strcpy(bigbuff, CANT_FORMAT_MESSAGE);
+ } else {
+ strbeg = (char *) event;
+ strbeg += event->StringOffset;
+ if(!format_message(mf, event->EventID,
+ strbeg, event->NumStrings, bigbuff, BIGBUFSIZ)){
+ strcpy(bigbuff, CANT_FORMAT_MESSAGE);
+ }
+ }
+ fac = ((char *)event)+sizeof(EVENTLOGRECORD);
+ sev = lookup_severity(event->EventType);
+ if(console_stdin()){
+ *tbuff = '\0';
+ strftime(tbuff, (size_t) TIME_BUFSIZ, TIME_FORMAT,
+ gmtime((time_t *)&(event->TimeGenerated)));
+ buff =
+ malloc(strlen(bigbuff) + TIME_BUFSIZ /* date-time */ +
+ strlen(category) +
+ strlen(fac) /* facility */ +
+ strlen(sev) /*severity */+
+ strlen(LOG_FORMAT) /* More than actually needed */ + 1);
+ sprintf(buff, LOG_FORMAT, tbuff, fac, category, sev, bigbuff);
+ ret = WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buff, strlen(buff),
+ &written, NULL); /* Overlapped structure for stdout? */
+ free(buff);
+ } else { /* pipe */
+ sprintf(tbuff,"%lu", event->TimeGenerated);
+ buff = malloc(strlen(bigbuff) +
+ strlen(tbuff) +
+ strlen(category) +
+ strlen(fac) +
+ strlen(sev) +
+ strlen(PIPE_LOG_FORMAT) +
+ PIPE_LOG_EXTRA);
+ sprintf(buff,PIPE_LOG_FORMAT,
+ strlen(tbuff),tbuff,
+ strlen(category), category,
+ strlen(fac), fac,
+ strlen(sev), sev,
+ strlen(bigbuff), bigbuff);
+ ret = data_to_pipe(buff,ackbuff, ACK_MAX);
+ if(ret && strcmp(ackbuff,PIPE_LOG_ACK))
+ ret = FALSE;
+ free(buff);
+ }
+ return ret;
+}
+
+
+/*
+ * Read eventlog entries FOLLOWING the given record
+ * number and timestamp, and sends them to
+ * stdout. If timestamp does
+ * not correspond with record number, the
+ * log is concidered wrapped around
+ * and is reread from the beginning.
+ * time is ignored if 0.
+ * If record_number is 0, the whole log is read (if there is one).
+ * If the function is unsuccessful, the global variable
+ * reopen_event_log may be set to TRUE, which means
+ * that the eventlog has changed and has to be reopened.
+ * It's the callers responsibility to set reopen_event_log to
+ * 0 before calling.
+ */
+static int read_from(DWORD *record_number, DWORD *time,
+ HANDLE elog, char *category){
+ DWORD dummy;
+ static EVENTLOGRECORD *event = NULL;
+ static DWORD eventsiz = 0;
+ DWORD red, need;
+ /* Always begin reading from record 1, record 0 never exists */
+ DWORD tmp = (*record_number) ? *record_number : 1;
+ DWORD ttmp = *time;
+ int skip = !!(*record_number); /* Dont skip if record_number == 0 */
+ int maybe_done = 0;
+ int i;
+
+ /* First try seeking to the correct place in the eventlog */
+ /* the variable skip tells us that we are rereading the */
+ /* last read eventlog record and the variable */
+ /* maybe_done tells us that we have read the last eventlog */
+ /* and an EOF is OK. */
+ for(;;){
+ if(!(need = needed(elog, tmp))){
+ if(maybe_done) /* Has read one correct record
+ and are satisfied with that. */
+ return 0;
+ /* Hmm, could not find the record? Try the oldest... */
+ if(!GetOldestEventLogRecord(elog, &tmp) ||
+ !(need = needed(elog, tmp))){
+ /* Something's terribly wrong. */
+#ifdef HARDDEBUG
+ fprintf(stderr,"Could not get oldest eventlog record!\n",
+ need);
+#endif
+ return -1;
+ }
+ skip = 0;
+ }
+ /* need == number of bytes for this record,
+ tmp == this recordnumber */
+ if(!event)
+ event = malloc(eventsiz = need);
+ else if(eventsiz < need)
+ event = realloc(event, eventsiz = need);
+ if(!ReadEventLog(elog,
+ (DWORD) (EVENTLOG_FORWARDS_READ |
+ EVENTLOG_SEEK_READ),
+ tmp,
+ event,
+ need,
+ &red,
+ &dummy)){
+ if(GetLastError() == ERROR_EVENTLOG_FILE_CHANGED){
+ reopen_event_log = 1;
+ }
+#ifdef HARDDEBUG
+ output_error(GetLastError(),
+ "Failed first eventlog read in read_from\n");
+#endif
+ return -1;
+ }
+ if(skip){
+ if(ttmp && event->TimeWritten != ttmp){
+ /* Wrapped around eventlog */
+ tmp = 1;
+ } else {
+ maybe_done = 1;
+ ++tmp;
+ }
+ skip = 0;
+ } else
+ break;
+ }
+ /* Got the first record in buffer, display and continue reading */
+ /* sequentially from here. */
+ for(i=1;;++i){
+ if(!output_record(category, event))
+ return -1;
+ *record_number = event->RecordNumber;
+ *time = event->TimeWritten;
+ if(!(need = needed(elog,(DWORD) 0)))
+ break; /* End of log */
+ if(eventsiz < need)
+ event = realloc(event, eventsiz = need);
+ if(!ReadEventLog(elog,
+ (DWORD) EVENTLOG_FORWARDS_READ |
+ EVENTLOG_SEQUENTIAL_READ,
+ (DWORD) 0,
+ event,
+ need,
+ &red,
+ &dummy)){
+ if(GetLastError() == ERROR_EVENTLOG_FILE_CHANGED){
+ reopen_event_log = 1;
+ }
+ return -1;
+ }
+ }
+ return i;
+}
+
+/*
+ * Read unread events and wait for new to arrive.
+ */
+int main(int argc, char **argv){
+ HANDLE elog[NUM_CATEGORIES];
+ HANDLE events[NUM_CATEGORIES + 1]; /* The stdin handle goes
+ in here to */
+ int eventlen;
+ char *ident;
+ DWORD record = 0, time = 0;
+ RegKeys rk[NUM_CATEGORIES];
+ int rklen = NUM_CATEGORIES;
+ int i;
+ int ret;
+ int x = 0;
+ int retry = 0;
+
+ if(argc < 2){
+ ident = DEFAULT_IDENT;
+ } else {
+ ident = argv[1];
+ }
+
+ if(!setup_pipe_stdin()){
+ fprintf(stderr,"%s: Stdin could not be initialized.\n",argv[0]);
+ return 1;
+ }
+ if(get_regkeys(ident, rk, &rklen) != 0){
+ fprintf(stderr,
+ "%s: Could not get/create registry parameters.\n", argv[0]);
+ return 1;
+ }
+ for(;;){
+ for(i=0; i<rklen; ++i){
+ elog[i] = OpenEventLog(NULL, rk[i].facility_name);
+
+ if(elog[i] == NULL){
+ fprintf(stderr,
+ "%s: Could not open \"%s\" eventlog.\n",
+ argv[0], rk[i].facility_name);
+ return 1;
+ }
+ if((events[i] = CreateEvent(NULL,FALSE,FALSE,NULL))
+ == NULL){
+ fprintf(stderr,"%s: Could not create event object.\n", argv[0]);
+ return 1;
+ }
+ if(!NotifyChangeEventLog(elog[i],events[i])){
+ fprintf(stderr,"%s: Could not get eventlog notification.\n", argv[0]);
+ return 1;
+ }
+ if(read_from(&(rk[i].latest_record),
+ &(rk[i].latest_time),
+ elog[i],
+ rk[i].facility_name) > 0)
+ set_regkeys(ident, rk + i, 1);
+ }
+ eventlen = rklen;
+ events[eventlen] = get_stdin_event();
+ ++eventlen;
+
+ for(;;){
+#ifdef HARDDEBUG
+ fprintf(stderr,"Entering Wait...\n");
+#endif
+ reopen_event_log = 0;
+ ret = WaitForMultipleObjects(eventlen,
+ events,
+ FALSE,
+ (retry) ?
+ RETRY_TIMEOUT :
+ INFINITE);
+#ifdef HARDDEBUG
+ fprintf(stderr,"Wait returned!\n");
+#endif
+ if(ret == WAIT_TIMEOUT){
+ if(!retry){
+ fprintf(stderr,"%s: Timeout when no such possible!\n",
+ argv[0]);
+ return 1;
+ }
+ retry = 0;
+ } else {
+ if(((int) (ret - WAIT_OBJECT_0)) >= rklen && eof_on_stdin())
+ goto done;
+ retry = 1;
+ }
+ for(i=0;i<rklen;++i){
+ if(read_from(&(rk[i].latest_record),
+ &(rk[i].latest_time),
+ elog[i],
+ rk[i].facility_name) > 0)
+ set_regkeys(ident, rk + i, 1);
+ }
+ if(reopen_event_log)
+ break;
+ }
+ for(i=0; i < rklen; ++i){
+ CloseEventLog(elog[i]);
+ CloseHandle(events[i]);
+ }
+ }
+done:
+#ifdef DEBUG
+ fprintf(stderr,"%s: EOF\n", argv[0]);
+#endif
+ for(i=0; i < rklen; ++i)
+ CloseEventLog(elog[i]);
+ return 0;
+}
diff --git a/lib/os_mon/c_src/nteventlog/elog_pipe_stdin.c b/lib/os_mon/c_src/nteventlog/elog_pipe_stdin.c
new file mode 100644
index 0000000000..c333c455a3
--- /dev/null
+++ b/lib/os_mon/c_src/nteventlog/elog_pipe_stdin.c
@@ -0,0 +1,151 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#include "elog_global.h"
+#include "elog_pipe_stdin.h"
+
+/*
+ * Data for the handling of a pipe stdin,
+ * data is read in a separate thread, so locking and
+ * event signaling needs to be done.
+ */
+
+static CRITICAL_SECTION io_crit;
+static char *stdin_buff = NULL;
+static int stdin_siz = 0;
+static int stdin_len = 0;
+static int stdin_eof = 0;
+/* end syncronized objects */
+static int stdin_is_console = 0;
+static HANDLE stdin_event;
+
+DWORD WINAPI stdin_thread(LPVOID ptr){
+ HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
+ char buff[1];
+ DWORD red;
+ for(;;){
+ if(!ReadFile(in, buff, (DWORD) 1, &red, NULL)){
+ if(GetLastError() == ERROR_BROKEN_PIPE){
+ EnterCriticalSection(&io_crit);
+ stdin_eof = 1;
+ SetEvent(stdin_event);
+ LeaveCriticalSection(&io_crit);
+ return 0;
+ }
+ return 1;
+ }else if(red == 0){
+ EnterCriticalSection(&io_crit);
+ stdin_eof = 1;
+ SetEvent(stdin_event);
+ LeaveCriticalSection(&io_crit);
+ return 0;
+ }
+#ifdef HARDDEBUG
+ fprintf(stderr,"stdin_thread go data (%d)\n",(int)*buff);
+#endif
+ EnterCriticalSection(&io_crit);
+ if(stdin_len + 1 >= stdin_siz){
+ if(!stdin_siz)
+ stdin_buff = malloc(stdin_siz = 100);
+ else
+ stdin_buff = realloc(stdin_buff, stdin_siz +=100);
+ }
+ stdin_buff[stdin_len++] = *buff;
+ SetEvent(stdin_event);
+ LeaveCriticalSection(&io_crit);
+ }
+ return 0;
+}
+
+BOOL peek_pipe_stdin_eof(void){
+ BOOL ret;
+ EnterCriticalSection(&io_crit);
+ if((ret = !!stdin_eof))
+ ResetEvent(stdin_event); /* Now we "unsignal" */
+ LeaveCriticalSection(&io_crit);
+ return ret;
+}
+
+int read_pipe_stdin(char *buff, int max){
+ int ret;
+ EnterCriticalSection(&io_crit);
+ if(stdin_len == 0){
+ if(!stdin_eof){
+ LeaveCriticalSection(&io_crit);
+ WaitForSingleObject(stdin_event,INFINITE);
+ EnterCriticalSection(&io_crit);
+ if(!stdin_len){
+ if(stdin_eof){
+ /* Stay signaled */
+ LeaveCriticalSection(&io_crit);
+ return 0;
+ } else {
+ ResetEvent(stdin_event);
+ LeaveCriticalSection(&io_crit);
+ return -1;
+ }
+ }
+ } else {
+ /* Stay signaled */
+ LeaveCriticalSection(&io_crit);
+ return 0;
+ }
+ }
+#ifdef HARDDEBUG
+ fprintf(stderr,"read_pipe_stdin got data.\n"
+ "max = %d, stdin_len = %d, *stdin_buff = %d\n",
+ max,stdin_len,*stdin_buff);
+#endif
+ /* stdin_len should be something now */
+ if(stdin_len > max){
+ memcpy(buff,stdin_buff,max);
+ memmove(stdin_buff,stdin_buff + max,stdin_len - max);
+ stdin_len -= max;
+ ret = max;
+ } else {
+ memcpy(buff,stdin_buff,stdin_len);
+ ret = stdin_len;
+ stdin_len = 0;
+ }
+ if(!stdin_eof) /* Stay signaled if EOF */
+ ResetEvent(stdin_event);
+ LeaveCriticalSection(&io_crit);
+ return ret;
+}
+
+BOOL setup_pipe_stdin(void){
+ HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
+ DWORD dummy;
+ if(GetConsoleMode(in, &dummy)){
+ stdin_is_console = 1;
+ stdin_event = in;
+ return TRUE;
+ }
+ stdin_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ InitializeCriticalSection(&io_crit);
+ return (_beginthreadex(NULL,0,&stdin_thread,NULL,0,&dummy));
+}
+
+BOOL console_stdin(void){
+ return stdin_is_console;
+}
+
+HANDLE get_stdin_event(void){
+ return stdin_event;
+}
+
diff --git a/lib/os_mon/c_src/nteventlog/elog_pipe_stdin.h b/lib/os_mon/c_src/nteventlog/elog_pipe_stdin.h
new file mode 100644
index 0000000000..a9a91b685f
--- /dev/null
+++ b/lib/os_mon/c_src/nteventlog/elog_pipe_stdin.h
@@ -0,0 +1,90 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef _ELOG_PIPE_STDIN_H
+#define _ELOG_PIPE_STDIN_H
+/*
+ * Module: elog_pipe_stdin
+ * Purpouse: Read data from stdin when stdin is a pipe
+ * and deliver events only when data is really availabel or
+ * end of file is reached.
+ * If we would wait on an ordinary pipe handle, we
+ * would return immediately as it's always "signaled".
+ * some kind of asyncronous I/O in the win32 way is
+ * not possible as it's not supported on anonymous pipes
+ * (besides we have not opened the file ourselves so we
+ * cannot specify that we want async I/O...).
+ * ToDo: The reading is inneficcient, the buffering
+ * goes on forever, which would be dangerous if to much
+ * data was passed into stdin. The handling of
+ * Console stdin should be transparent instead of
+ * forcing the user of the module to check if this is a
+ * console for selecting between ReadFile and
+ * read_pipe_stdin.
+ * The handling of the event object is somewhat strange
+ * because I want to know about EOF before I've read
+ * to it.
+ */
+
+BOOL peek_pipe_stdin_eof(void);
+/*
+ * Returns TRUE if eof is reached, regardless of
+ * if there still is unread data in the buffer.
+ * Should not be called if console_stdin() returns TRUE.
+ * Resets the event object if it returns TRUE.
+ */
+
+int read_pipe_stdin(char *buff, int max);
+/*
+ * Reads from stdin, minimum 1 byte and
+ * maximum max bytes into buff. If EOF
+ * is reached and no bytes were read,
+ * the return value is 0.
+ * Should not be called if console_stdin() returns TRUE.
+ * The event object for stdin will get unsignaled if
+ * end of file is not reached (if peek_pipe_stdin_eof()
+ * would return false).
+ */
+
+BOOL setup_pipe_stdin(void);
+/*
+ * Initializes the module, returns TRUE if OK.
+ * If stdin is a console, no thread is created
+ * and the event objet returned by get_Stdin_event
+ * will be the console handle.
+ * Check if stdin was a console with the console_stdin()
+ * function.
+ */
+
+BOOL console_stdin(void);
+/*
+ * Returns true if stdin was a console, in which case
+ * normal Win32 console I/O functions have to
+ * be used.
+ * get_stdin_event() will return the console handle,
+ * which is signalled whenever an event reaches
+ * the console window (like mouse events etc).
+ */
+
+HANDLE get_stdin_event(void);
+/*
+ * Returns a event handle that can be waited upon with
+ * WaitForSingleObject and friends. It is possibly a console
+ * handle, see console_stdin().
+ */
+#endif /* _ELOG_PIPE_STDIN_H */
diff --git a/lib/os_mon/c_src/nteventlog/elog_registry.c b/lib/os_mon/c_src/nteventlog/elog_registry.c
new file mode 100644
index 0000000000..478db1e56b
--- /dev/null
+++ b/lib/os_mon/c_src/nteventlog/elog_registry.c
@@ -0,0 +1,295 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#include "elog_global.h"
+#include "elog_util.h"
+#include "elog_registry.h"
+
+/*
+ * Constants for get/set_regkeys
+ */
+#define APP_ROOT_KEY "SOFTWARE\\Ericsson\\Erlang"
+#define APP_SUB_KEY "EventLogReader"
+#define APP_VERSION "1.0"
+#define LATEST_RECORD_NAME "LatestRecord"
+#define LATEST_TIME_NAME "LatestTime"
+/*
+ * Constants for get_messagefiles
+ */
+#define LOG_KEY_TMPL "SYSTEM\\CurrentControlSet\\Services\\EventLog\\%s\\%s"
+#define EVENT_MSG_FILE_NAME "EventMessageFile"
+#define PARAM_MSG_FILE_NAME "ParameterMessageFile"
+MessageFiles get_messagefiles(const char *category, const char *facility,
+ char *eventbuff, int eventbufflen,
+ char *parambuff, int parambufflen){
+ char *b1 = malloc(strlen(LOG_KEY_TMPL)+strlen(category)+strlen(facility)+1);
+ HKEY key;
+ char name[1024];
+ char val[MAX_PATH];
+ MessageFiles mf = { NULL, NULL };
+ DWORD namelen, vallen, type, i, ret;
+
+ if(!b1)
+ return mf;
+ sprintf(b1,LOG_KEY_TMPL,category,facility);
+ if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, b1, 0, KEY_QUERY_VALUE, &key) !=
+ ERROR_SUCCESS){
+ free(b1);
+ return mf;
+ }
+ free(b1);
+ for(namelen=1024,vallen=MAX_PATH,i=0;
+ ERROR_SUCCESS == RegEnumValue(key,
+ i,
+ name,
+ &namelen,
+ NULL,
+ &type,
+ (LPBYTE) val,
+ &vallen);
+ namelen=1024,vallen=MAX_PATH,++i){
+ if(!strcmp(name,EVENT_MSG_FILE_NAME)){
+ if(type == REG_EXPAND_SZ){
+ ret = ExpandEnvironmentStrings(val,eventbuff,eventbufflen);
+ if(((int) ret) > eventbufflen || !ret)
+ break;
+ } else {
+ if(((int) strlen(val)) >= eventbufflen)
+ break;
+ else
+ strcpy(eventbuff,val);
+ }
+ mf.event = eventbuff;
+ } else if(!strcmp(name,PARAM_MSG_FILE_NAME)){
+ if(type == REG_EXPAND_SZ){
+ ret = ExpandEnvironmentStrings(val,parambuff,parambufflen);
+ if(((int) ret) > parambufflen || !ret)
+ break;
+ } else {
+ if(((int) strlen(val)) >= parambufflen)
+ break;
+ else
+ strcpy(parambuff,val);
+ }
+ mf.param = parambuff;
+ }
+ }
+ RegCloseKey(key);
+ return mf;
+}
+
+
+int create_regkeys(char *identifier){
+ HKEY key,key2;
+ DWORD dispositions;
+ int i,j;
+ char *values[] = {
+ LATEST_RECORD_NAME,
+ LATEST_TIME_NAME,
+ NULL
+ };
+
+ DWORD zero = 0;
+
+ if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,
+ APP_ROOT_KEY "\\" APP_SUB_KEY "\\"
+ APP_VERSION,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_CREATE_SUB_KEY,
+ NULL,
+ &key,
+ &dispositions) != ERROR_SUCCESS){
+ return -1;
+ }
+ if(RegCreateKeyEx(key,
+ identifier,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_CREATE_SUB_KEY,
+ NULL,
+ &key2,
+ &dispositions)){
+ RegCloseKey(key);
+ return -1;
+ }
+ RegCloseKey(key);
+ for(i=0; category_tab[i] != NULL; ++i){
+ if(RegCreateKeyEx(key2,
+ category_tab[i],
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_SET_VALUE,
+ NULL,
+ &key,
+ &dispositions) != ERROR_SUCCESS){
+ RegCloseKey(key2);
+ return -1;
+ }
+ for(j=0; values[j] != NULL; ++j){
+ if(RegSetValueEx(key,
+ values[j],
+ 0,
+ REG_DWORD,
+ (BYTE *) &zero,
+ sizeof(DWORD)) != ERROR_SUCCESS){
+ RegCloseKey(key);
+ RegCloseKey(key2);
+ return -1;
+ }
+ }
+ RegCloseKey(key);
+ }
+ RegCloseKey(key2);
+ return 0;
+}
+
+
+int set_regkeys(char *identifier, RegKeys *keys, int num_keys){
+ HKEY key;
+ char knbuff[SMALLBUFSIZ];
+ int i;
+ for(i=0; i<num_keys; ++i){
+ sprintf(knbuff,"%s\\%s\\%s\\%s\\%s",
+ APP_ROOT_KEY,
+ APP_SUB_KEY,
+ APP_VERSION,
+ identifier,
+ keys[i].facility_name);
+ if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ knbuff,
+ 0,
+ KEY_SET_VALUE,
+ &key) != ERROR_SUCCESS){
+ return -1;
+ }
+ if(RegSetValueEx(key,
+ LATEST_RECORD_NAME,
+ 0,
+ REG_DWORD,
+ (BYTE *) &(keys[i].latest_record),
+ sizeof(DWORD)) != ERROR_SUCCESS){
+ RegCloseKey(key);
+ return -1;
+ }
+ if(RegSetValueEx(key,
+ LATEST_TIME_NAME,
+ 0,
+ REG_DWORD,
+ (BYTE *) &(keys[i].latest_time),
+ sizeof(DWORD)) != ERROR_SUCCESS){
+ RegCloseKey(key);
+ return -1;
+ }
+ RegCloseKey(key);
+ }
+ return 0;
+}
+
+
+int get_regkeys(char *identifier, RegKeys *keys, int *num_keys /* in out */){
+ HKEY key,key2;
+ int i;
+ char knbuff[SMALLBUFSIZ];
+ DWORD knlen;
+ char cnbuff[SMALLBUFSIZ];
+ DWORD cnlen;
+ FILETIME ft;
+ DWORD type, data, datasiz;
+
+ sprintf(knbuff,"%s\\%s\\%s\\%s",
+ APP_ROOT_KEY,
+ APP_SUB_KEY,
+ APP_VERSION,
+ identifier);
+ if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ knbuff,
+ 0,
+ KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
+ &key) != ERROR_SUCCESS){
+ if(create_regkeys(identifier)!= 0){
+#ifdef HARDDEBUG
+ fprintf(stderr,"Failed creating regkeys\n");
+#endif
+ return -1;
+ } else {
+ if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ knbuff,
+ 0,
+ KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
+ &key) != ERROR_SUCCESS){
+#ifdef HARDDEBUG
+ fprintf(stderr,"Failed opening regkeys\n");
+#endif
+ return -1;
+ }
+ }
+ }
+ for(i = 0, knlen = SMALLBUFSIZ, cnlen = SMALLBUFSIZ;
+ i < *num_keys &&
+ ERROR_SUCCESS == RegEnumKeyEx(key,
+ i,
+ knbuff,
+ &knlen,
+ NULL,
+ cnbuff,
+ &cnlen,
+ &ft);
+ ++i, knlen = SMALLBUFSIZ, cnlen = SMALLBUFSIZ){
+ if(RegOpenKeyEx(key,
+ knbuff,
+ 0,
+ KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
+ &key2) != ERROR_SUCCESS)
+ continue;
+ strncpy(keys[i].facility_name, knbuff,
+ MAX_FACILITY_NAME);
+ keys[i].facility_name[MAX_FACILITY_NAME - 1] = '\0';
+ datasiz = sizeof(DWORD);
+ if(RegQueryValueEx(key2,
+ LATEST_RECORD_NAME,
+ NULL,
+ &type,
+ (BYTE *) &data,
+ &datasiz) != ERROR_SUCCESS)
+ keys[i].latest_record = 0;
+ else
+ keys[i].latest_record = data;
+ if(RegQueryValueEx(key2,
+ LATEST_TIME_NAME,
+ NULL,
+ &type,
+ (BYTE *) &data,
+ &datasiz) != ERROR_SUCCESS)
+ keys[i].latest_time = 0;
+ else
+ keys[i].latest_time = data;
+ RegCloseKey(key2);
+ }
+ *num_keys = i;
+ if(!*num_keys){
+#ifdef HARDDEBUG
+ fprintf(stderr,"get_regkeys got none!\n");
+#endif
+ return -1;
+ }
+ return 0;
+}
diff --git a/lib/os_mon/c_src/nteventlog/elog_registry.h b/lib/os_mon/c_src/nteventlog/elog_registry.h
new file mode 100644
index 0000000000..32876ae8bf
--- /dev/null
+++ b/lib/os_mon/c_src/nteventlog/elog_registry.h
@@ -0,0 +1,67 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef _ELOG_REGISTRY_H
+#define _ELOG_REGISTRY_H
+/*
+ * Module: elog_registry
+ * Purpouse: Handle the registry reading and writing.
+ */
+
+#include "elog_global.h"
+
+/*
+ * A structure for the registry keys.
+ */
+typedef struct _reg_keys {
+ char facility_name[MAX_FACILITY_NAME];
+ DWORD latest_record;
+ DWORD latest_time;
+} RegKeys;
+
+MessageFiles get_messagefiles(const char *category, const char *facility,
+ char *eventbuff, int eventbufflen,
+ char *parambuff, int parambufflen);
+/*
+ * Return the EventMessageFile and then ParameterMessageFile for
+ * a facility under a category.
+ * The buffers should be at least MAX_PATH long to make
+ * sure the filenames can be stored.
+ * If facility is not found, both fields in the record are NULL,
+ * if the ParameterMessageFile is not found, the param filed of the record
+ * is NULL.
+ */
+
+int create_regkeys(char *identifier);
+/*
+ * Creates registry entries for this log identifier
+ */
+int set_regkeys(char *identifier, RegKeys *keys, int num_keys);
+/*
+ * Updates the registry keys for the identifier. Multiple
+ * categories can be specified in the keys array.
+ */
+int get_regkeys(char *identifier, RegKeys *keys, int *num_keys /* in out */);
+/*
+ * Reads the keys from the registry database for this
+ * identifier, creating them if needed. The values
+ * for the different categories are stored in the
+ * keys array as long as there is place.
+ */
+
+#endif /* _ELOG_REGISTRY_H */
diff --git a/lib/os_mon/c_src/nteventlog/elog_util.c b/lib/os_mon/c_src/nteventlog/elog_util.c
new file mode 100644
index 0000000000..ac14f2f3e4
--- /dev/null
+++ b/lib/os_mon/c_src/nteventlog/elog_util.c
@@ -0,0 +1,73 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#include "elog_global.h"
+#include "elog_util.h"
+
+char *category_tab[] = {
+ SYSTEM,
+ APPLICATION,
+ SECURITY,
+ NULL
+};
+
+SeverityEntry severity_tab[] = {
+ {EVENTLOG_ERROR_TYPE , "Error"},
+ {EVENTLOG_WARNING_TYPE, "Warning"},
+ {EVENTLOG_INFORMATION_TYPE, "Informational"},
+ {EVENTLOG_AUDIT_SUCCESS, "Audit_Success"},
+ {EVENTLOG_AUDIT_FAILURE, "Audit_Faulure"},
+ {0, "Severity_Unknown"}
+};
+
+int severity_tab_len =
+sizeof(severity_tab)/sizeof(SeverityEntry);
+
+char *lookup_severity(WORD severity){
+ int i;
+ for(i=0;i<severity_tab_len-1;++i)
+ if(severity_tab[i].type == severity)
+ return severity_tab[i].desc;
+ return severity_tab[i].desc;
+}
+
+
+void output_error(DWORD error, char *extra){
+ char *msgbuf;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ error,
+ DEFAULT_LANGID,
+ (LPTSTR) &msgbuf,
+ 0,
+ NULL );
+ fprintf(stderr,"%s: %s", extra, msgbuf);
+ LocalFree(msgbuf);
+}
+
+
+#undef malloc
+void *my_malloc(size_t siz){
+ void *x;
+ if((x = malloc(siz)) == NULL){
+ fputs("Out of memory.", stderr);
+ exit(1);
+ }
+ return x;
+}
diff --git a/lib/os_mon/c_src/nteventlog/elog_util.h b/lib/os_mon/c_src/nteventlog/elog_util.h
new file mode 100644
index 0000000000..66f1a2519e
--- /dev/null
+++ b/lib/os_mon/c_src/nteventlog/elog_util.h
@@ -0,0 +1,79 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef _ELOG_UTIL_H
+#define _ELOG_UTIL_H
+/*
+ * Module: elog_util
+ * Purpouse: Utilities for other elog modules.
+ */
+
+#include "elog_global.h"
+
+/*
+ * A table of eventlog categories in an NT system. NOTE that the NUM_CATEGORIES
+ * constant has to be updated if this table is!
+ */
+extern char *category_tab[];
+
+#define NUM_CATEGORIES 3
+
+/*
+ * Table for translation of severity constants o strings
+ */
+typedef struct _severity_tab {
+ WORD type;
+ char *desc;
+} SeverityEntry;
+
+extern SeverityEntry severity_tab[];
+extern int severity_tab_len;
+
+char *lookup_severity(WORD severity);
+/*
+ * Lookup in the above table.
+ */
+
+/*
+ * Safe malloc.
+ */
+void *my_malloc(size_t siz);
+#define malloc(X) my_malloc(X)
+
+/*
+ * Error reporting
+ */
+void output_error(DWORD error, char *extra);
+/*
+ * Formats a GetLastError() errorcode to text,
+ * prepended with 'extra':. Writes to stderr.
+ */
+
+/*
+ * I don't like mistyped strings...
+ */
+#define SYSTEM "System"
+#define APPLICATION "Application"
+#define SECURITY "Security"
+/*
+ * The mask to get the printable message id value
+ */
+#define EVENT_ID_MASK 0x0000FFFF
+
+#endif /* _ELOG_UTIL_H */
+