2 * PROJECT: ReactOS kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: services/eventlog/eventlog.c
5 * PURPOSE: Event logging service
6 * COPYRIGHT: Copyright 2002 Eric Kohl
7 * Copyright 2005 Saveliy Tretiakov
10 /* INCLUDES *****************************************************************/
14 /* GLOBALS ******************************************************************/
16 static VOID CALLBACK
ServiceMain(DWORD
, LPWSTR
*);
17 static WCHAR ServiceName
[] = L
"EventLog";
18 static SERVICE_TABLE_ENTRYW ServiceTable
[2] =
20 { ServiceName
, ServiceMain
},
24 SERVICE_STATUS ServiceStatus
;
25 SERVICE_STATUS_HANDLE ServiceStatusHandle
;
27 BOOL onLiveCD
= FALSE
; // On livecd events will go to debug output only
30 /* FUNCTIONS ****************************************************************/
33 UpdateServiceStatus(DWORD dwState
)
35 ServiceStatus
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
36 ServiceStatus
.dwCurrentState
= dwState
;
37 ServiceStatus
.dwControlsAccepted
= 0;
38 ServiceStatus
.dwWin32ExitCode
= 0;
39 ServiceStatus
.dwServiceSpecificExitCode
= 0;
40 ServiceStatus
.dwCheckPoint
= 0;
42 if (dwState
== SERVICE_START_PENDING
||
43 dwState
== SERVICE_STOP_PENDING
||
44 dwState
== SERVICE_PAUSE_PENDING
||
45 dwState
== SERVICE_CONTINUE_PENDING
)
46 ServiceStatus
.dwWaitHint
= 10000;
48 ServiceStatus
.dwWaitHint
= 0;
50 SetServiceStatus(ServiceStatusHandle
,
55 ServiceControlHandler(DWORD dwControl
,
60 DPRINT("ServiceControlHandler() called\n");
64 case SERVICE_CONTROL_STOP
:
65 DPRINT(" SERVICE_CONTROL_STOP received\n");
67 LogfReportEvent(EVENTLOG_INFORMATION_TYPE
,
69 EVENT_EventlogStopped
, 0, NULL
, 0, NULL
);
72 /* Stop listening to incoming RPC messages */
73 RpcMgmtStopServerListening(NULL
);
74 UpdateServiceStatus(SERVICE_STOPPED
);
77 case SERVICE_CONTROL_PAUSE
:
78 DPRINT(" SERVICE_CONTROL_PAUSE received\n");
79 UpdateServiceStatus(SERVICE_PAUSED
);
82 case SERVICE_CONTROL_CONTINUE
:
83 DPRINT(" SERVICE_CONTROL_CONTINUE received\n");
84 UpdateServiceStatus(SERVICE_RUNNING
);
87 case SERVICE_CONTROL_INTERROGATE
:
88 DPRINT(" SERVICE_CONTROL_INTERROGATE received\n");
89 SetServiceStatus(ServiceStatusHandle
,
93 case SERVICE_CONTROL_SHUTDOWN
:
94 DPRINT(" SERVICE_CONTROL_SHUTDOWN received\n");
96 LogfReportEvent(EVENTLOG_INFORMATION_TYPE
,
98 EVENT_EventlogStopped
, 0, NULL
, 0, NULL
);
100 UpdateServiceStatus(SERVICE_STOPPED
);
101 return ERROR_SUCCESS
;
104 DPRINT1(" Control %lu received\n", dwControl
);
105 return ERROR_CALL_NOT_IMPLEMENTED
;
115 hThread
= CreateThread(NULL
,
117 (LPTHREAD_START_ROUTINE
)
125 DPRINT("Can't create PortThread\n");
126 return GetLastError();
129 CloseHandle(hThread
);
131 hThread
= CreateThread(NULL
,
133 (LPTHREAD_START_ROUTINE
)
141 DPRINT("Can't create RpcThread\n");
142 return GetLastError();
145 CloseHandle(hThread
);
147 return ERROR_SUCCESS
;
152 ReportProductInfoEvent(VOID
)
154 OSVERSIONINFOW versionInfo
;
160 LONG lResult
= ERROR_SUCCESS
;
162 ZeroMemory(&versionInfo
, sizeof(OSVERSIONINFO
));
163 versionInfo
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
165 /* Get version information */
166 if (!GetVersionExW(&versionInfo
))
169 ZeroMemory(szBuffer
, 512 * sizeof(WCHAR
));
171 /* Write version into the buffer */
172 dwLength
= swprintf(szBuffer
,
174 versionInfo
.dwMajorVersion
,
175 versionInfo
.dwMinorVersion
) + 1;
177 /* Write build number into the buffer */
178 dwLength
+= swprintf(&szBuffer
[dwLength
],
180 versionInfo
.dwBuildNumber
) + 1;
182 /* Write service pack info into the buffer */
183 wcscpy(&szBuffer
[dwLength
], versionInfo
.szCSDVersion
);
184 dwLength
+= wcslen(versionInfo
.szCSDVersion
) + 1;
186 /* Read 'CurrentType' from the registry and write it into the buffer */
187 lResult
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
188 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
192 if (lResult
== ERROR_SUCCESS
)
194 dwValueLength
= 512 - dwLength
;
195 lResult
= RegQueryValueEx(hKey
,
199 (LPBYTE
)&szBuffer
[dwLength
],
205 /* Log the product information */
206 LogfReportEvent(EVENTLOG_INFORMATION_TYPE
,
208 EVENT_EventLogProductInfo
,
217 ServiceMain(DWORD argc
,
222 UNREFERENCED_PARAMETER(argc
);
223 UNREFERENCED_PARAMETER(argv
);
225 DPRINT("ServiceMain() called\n");
227 ServiceStatusHandle
= RegisterServiceCtrlHandlerExW(ServiceName
,
228 ServiceControlHandler
,
230 if (!ServiceStatusHandle
)
232 dwError
= GetLastError();
233 DPRINT1("RegisterServiceCtrlHandlerW() failed! (Error %lu)\n", dwError
);
237 UpdateServiceStatus(SERVICE_START_PENDING
);
239 dwError
= ServiceInit();
240 if (dwError
!= ERROR_SUCCESS
)
242 DPRINT("Service stopped (dwError: %lu\n", dwError
);
243 UpdateServiceStatus(SERVICE_START_PENDING
);
247 DPRINT("Service started\n");
248 UpdateServiceStatus(SERVICE_RUNNING
);
250 ReportProductInfoEvent();
252 LogfReportEvent(EVENTLOG_INFORMATION_TYPE
,
254 EVENT_EventlogStarted
,
261 DPRINT("ServiceMain() done\n");
265 PLOGFILE
LoadLogFile(HKEY hKey
, WCHAR
* LogName
)
267 DWORD MaxValueLen
, ValueLen
, Type
, ExpandedLen
;
268 WCHAR
*Buf
= NULL
, *Expanded
= NULL
;
270 PLOGFILE pLogf
= NULL
;
271 UNICODE_STRING FileName
;
274 DPRINT("LoadLogFile: %S\n", LogName
);
276 RegQueryInfoKey(hKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
277 NULL
, NULL
, &MaxValueLen
, NULL
, NULL
);
279 Buf
= HeapAlloc(MyHeap
, 0, MaxValueLen
);
282 DPRINT1("Can't allocate heap!\n");
286 ValueLen
= MaxValueLen
;
288 Result
= RegQueryValueEx(hKey
,
294 if (Result
!= ERROR_SUCCESS
)
296 DPRINT1("RegQueryValueEx failed: %lu\n", GetLastError());
297 HeapFree(MyHeap
, 0, Buf
);
301 if (Type
!= REG_EXPAND_SZ
&& Type
!= REG_SZ
)
303 DPRINT1("%S\\File - value of wrong type %x.\n", LogName
, Type
);
304 HeapFree(MyHeap
, 0, Buf
);
308 ExpandedLen
= ExpandEnvironmentStrings(Buf
, NULL
, 0);
309 Expanded
= HeapAlloc(MyHeap
, 0, ExpandedLen
* sizeof(WCHAR
));
312 DPRINT1("Can't allocate heap!\n");
313 HeapFree(MyHeap
, 0, Buf
);
317 ExpandEnvironmentStrings(Buf
, Expanded
, ExpandedLen
);
319 if (!RtlDosPathNameToNtPathName_U(Expanded
, &FileName
,
322 DPRINT1("Can't convert path!\n");
323 HeapFree(MyHeap
, 0, Expanded
);
324 HeapFree(MyHeap
, 0, Buf
);
328 DPRINT("%S -> %S\n", Buf
, Expanded
);
330 Status
= LogfCreate(&pLogf
, LogName
, &FileName
, TRUE
, FALSE
);
331 if (!NT_SUCCESS(Status
))
333 DPRINT1("Failed to create %S! (Status %08lx)\n", Expanded
, Status
);
336 HeapFree(MyHeap
, 0, Buf
);
337 HeapFree(MyHeap
, 0, Expanded
);
341 BOOL
LoadLogFiles(HKEY eventlogKey
)
344 DWORD MaxLognameLen
, LognameLen
;
349 RegQueryInfoKey(eventlogKey
,
350 NULL
, NULL
, NULL
, NULL
,
352 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
356 Buf
= HeapAlloc(MyHeap
, 0, MaxLognameLen
* sizeof(WCHAR
));
360 DPRINT1("Error: can't allocate heap!\n");
365 LognameLen
= MaxLognameLen
;
367 while (RegEnumKeyEx(eventlogKey
,
371 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
377 result
= RegOpenKeyEx(eventlogKey
, Buf
, 0, KEY_ALL_ACCESS
, &SubKey
);
378 if (result
!= ERROR_SUCCESS
)
380 DPRINT1("Failed to open %S key.\n", Buf
);
381 HeapFree(MyHeap
, 0, Buf
);
385 pLogFile
= LoadLogFile(SubKey
, Buf
);
386 if (pLogFile
!= NULL
)
388 DPRINT("Loaded %S\n", Buf
);
389 LoadEventSources(SubKey
, pLogFile
);
393 DPRINT1("Failed to load %S\n", Buf
);
397 LognameLen
= MaxLognameLen
;
401 HeapFree(MyHeap
, 0, Buf
);
407 WCHAR LogPath
[MAX_PATH
];
412 LogfListInitialize();
413 InitEventSourceList();
415 MyHeap
= HeapCreate(0, 1024 * 256, 0);
419 DPRINT1("FATAL ERROR, can't create heap.\n");
424 GetWindowsDirectory(LogPath
, MAX_PATH
);
426 if (GetDriveType(LogPath
) == DRIVE_CDROM
)
428 DPRINT("LiveCD detected\n");
433 result
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
434 L
"SYSTEM\\CurrentControlSet\\Services\\EventLog",
439 if (result
!= ERROR_SUCCESS
)
441 DPRINT1("Fatal error: can't open eventlog registry key.\n");
446 LoadLogFiles(elogKey
);
449 StartServiceCtrlDispatcher(ServiceTable
);
460 VOID
EventTimeToSystemTime(DWORD EventTime
, SYSTEMTIME
* pSystemTime
)
462 SYSTEMTIME st1970
= { 1970, 1, 0, 1, 0, 0, 0, 0 };
470 uUCT
.ft
.dwHighDateTime
= 0;
471 uUCT
.ft
.dwLowDateTime
= EventTime
;
472 SystemTimeToFileTime(&st1970
, &u1970
.ft
);
473 uUCT
.ll
= uUCT
.ll
* 10000000 + u1970
.ll
;
474 FileTimeToLocalFileTime(&uUCT
.ft
, &ftLocal
);
475 FileTimeToSystemTime(&ftLocal
, pSystemTime
);
478 VOID
SystemTimeToEventTime(SYSTEMTIME
* pSystemTime
, DWORD
* pEventTime
)
480 SYSTEMTIME st1970
= { 1970, 1, 0, 1, 0, 0, 0, 0 };
487 SystemTimeToFileTime(pSystemTime
, &Time
.ft
);
488 SystemTimeToFileTime(&st1970
, &u1970
.ft
);
489 *pEventTime
= (DWORD
)((Time
.ll
- u1970
.ll
) / 10000000ull);
492 VOID
PRINT_HEADER(PEVENTLOGHEADER header
)
494 DPRINT("HeaderSize = %lu\n", header
->HeaderSize
);
495 DPRINT("Signature = 0x%x\n", header
->Signature
);
496 DPRINT("MajorVersion = %lu\n", header
->MajorVersion
);
497 DPRINT("MinorVersion = %lu\n", header
->MinorVersion
);
498 DPRINT("StartOffset = %lu\n", header
->StartOffset
);
499 DPRINT("EndOffset = 0x%x\n", header
->EndOffset
);
500 DPRINT("CurrentRecordNumber = %lu\n", header
->CurrentRecordNumber
);
501 DPRINT("OldestRecordNumber = %lu\n", header
->OldestRecordNumber
);
502 DPRINT("MaxSize = 0x%x\n", header
->MaxSize
);
503 DPRINT("Retention = 0x%x\n", header
->Retention
);
504 DPRINT("EndHeaderSize = %lu\n", header
->EndHeaderSize
);
506 if (header
->Flags
& ELF_LOGFILE_HEADER_DIRTY
) DPRINT("ELF_LOGFILE_HEADER_DIRTY");
507 if (header
->Flags
& ELF_LOGFILE_HEADER_WRAP
) DPRINT("| ELF_LOGFILE_HEADER_WRAP ");
508 if (header
->Flags
& ELF_LOGFILE_LOGFULL_WRITTEN
) DPRINT("| ELF_LOGFILE_LOGFULL_WRITTEN ");
509 if (header
->Flags
& ELF_LOGFILE_ARCHIVE_SET
) DPRINT("| ELF_LOGFILE_ARCHIVE_SET ");
513 VOID
PRINT_RECORD(PEVENTLOGRECORD pRec
)
519 DPRINT("Length = %lu\n", pRec
->Length
);
520 DPRINT("Reserved = 0x%x\n", pRec
->Reserved
);
521 DPRINT("RecordNumber = %lu\n", pRec
->RecordNumber
);
523 EventTimeToSystemTime(pRec
->TimeGenerated
, &time
);
524 DPRINT("TimeGenerated = %hu.%hu.%hu %hu:%hu:%hu\n",
525 time
.wDay
, time
.wMonth
, time
.wYear
,
526 time
.wHour
, time
.wMinute
, time
.wSecond
);
528 EventTimeToSystemTime(pRec
->TimeWritten
, &time
);
529 DPRINT("TimeWritten = %hu.%hu.%hu %hu:%hu:%hu\n",
530 time
.wDay
, time
.wMonth
, time
.wYear
,
531 time
.wHour
, time
.wMinute
, time
.wSecond
);
533 DPRINT("EventID = %lu\n", pRec
->EventID
);
535 switch (pRec
->EventType
)
537 case EVENTLOG_ERROR_TYPE
:
538 DPRINT("EventType = EVENTLOG_ERROR_TYPE\n");
540 case EVENTLOG_WARNING_TYPE
:
541 DPRINT("EventType = EVENTLOG_WARNING_TYPE\n");
543 case EVENTLOG_INFORMATION_TYPE
:
544 DPRINT("EventType = EVENTLOG_INFORMATION_TYPE\n");
546 case EVENTLOG_AUDIT_SUCCESS
:
547 DPRINT("EventType = EVENTLOG_AUDIT_SUCCESS\n");
549 case EVENTLOG_AUDIT_FAILURE
:
550 DPRINT("EventType = EVENTLOG_AUDIT_FAILURE\n");
553 DPRINT("EventType = %hu\n", pRec
->EventType
);
556 DPRINT("NumStrings = %hu\n", pRec
->NumStrings
);
557 DPRINT("EventCategory = %hu\n", pRec
->EventCategory
);
558 DPRINT("ReservedFlags = 0x%x\n", pRec
->ReservedFlags
);
559 DPRINT("ClosingRecordNumber = %lu\n", pRec
->ClosingRecordNumber
);
560 DPRINT("StringOffset = %lu\n", pRec
->StringOffset
);
561 DPRINT("UserSidLength = %lu\n", pRec
->UserSidLength
);
562 DPRINT("UserSidOffset = %lu\n", pRec
->UserSidOffset
);
563 DPRINT("DataLength = %lu\n", pRec
->DataLength
);
564 DPRINT("DataOffset = %lu\n", pRec
->DataOffset
);
566 DPRINT("SourceName: %S\n", (WCHAR
*) (((PBYTE
) pRec
) + sizeof(EVENTLOGRECORD
)));
568 i
= (lstrlenW((WCHAR
*) (((PBYTE
) pRec
) + sizeof(EVENTLOGRECORD
))) + 1) *
571 DPRINT("ComputerName: %S\n", (WCHAR
*) (((PBYTE
) pRec
) + sizeof(EVENTLOGRECORD
) + i
));
573 if (pRec
->StringOffset
< pRec
->Length
&& pRec
->NumStrings
)
575 DPRINT("Strings:\n");
576 str
= (WCHAR
*) (((PBYTE
) pRec
) + pRec
->StringOffset
);
577 for (i
= 0; i
< pRec
->NumStrings
; i
++)
579 DPRINT("[%u] %S\n", i
, str
);
580 str
= str
+ lstrlenW(str
) + 1;
584 DPRINT("Length2 = %lu\n", *(PDWORD
) (((PBYTE
) pRec
) + pRec
->Length
- 4));