elog_main.c

来自「OTP是开放电信平台的简称」· C语言 代码 · 共 504 行

C
504
字号
/* ``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 via the world wide web 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. *  * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' *  *     $Id$ *//* * 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;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?