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 *****************************************************************/
20 /* GLOBALS ******************************************************************/
22 static VOID CALLBACK
ServiceMain(DWORD
, LPWSTR
*);
23 static WCHAR ServiceName
[] = L
"EventLog";
24 static SERVICE_TABLE_ENTRYW ServiceTable
[2] =
26 { ServiceName
, ServiceMain
},
30 SERVICE_STATUS ServiceStatus
;
31 SERVICE_STATUS_HANDLE ServiceStatusHandle
;
33 BOOL onLiveCD
= FALSE
; // On livecd events will go to debug output only
36 /* FUNCTIONS ****************************************************************/
39 UpdateServiceStatus(DWORD dwState
)
41 ServiceStatus
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
42 ServiceStatus
.dwCurrentState
= dwState
;
43 ServiceStatus
.dwControlsAccepted
= 0;
44 ServiceStatus
.dwWin32ExitCode
= 0;
45 ServiceStatus
.dwServiceSpecificExitCode
= 0;
46 ServiceStatus
.dwCheckPoint
= 0;
48 if (dwState
== SERVICE_START_PENDING
||
49 dwState
== SERVICE_STOP_PENDING
||
50 dwState
== SERVICE_PAUSE_PENDING
||
51 dwState
== SERVICE_CONTINUE_PENDING
)
52 ServiceStatus
.dwWaitHint
= 10000;
54 ServiceStatus
.dwWaitHint
= 0;
56 SetServiceStatus(ServiceStatusHandle
,
61 ServiceControlHandler(DWORD dwControl
,
66 DPRINT("ServiceControlHandler() called\n");
70 case SERVICE_CONTROL_STOP
:
71 DPRINT(" SERVICE_CONTROL_STOP received\n");
73 LogfReportEvent(EVENTLOG_INFORMATION_TYPE
,
75 EVENT_EventlogStopped
, 0, NULL
, 0, NULL
);
78 /* Stop listening to incoming RPC messages */
79 RpcMgmtStopServerListening(NULL
);
80 UpdateServiceStatus(SERVICE_STOPPED
);
83 case SERVICE_CONTROL_PAUSE
:
84 DPRINT(" SERVICE_CONTROL_PAUSE received\n");
85 UpdateServiceStatus(SERVICE_PAUSED
);
88 case SERVICE_CONTROL_CONTINUE
:
89 DPRINT(" SERVICE_CONTROL_CONTINUE received\n");
90 UpdateServiceStatus(SERVICE_RUNNING
);
93 case SERVICE_CONTROL_INTERROGATE
:
94 DPRINT(" SERVICE_CONTROL_INTERROGATE received\n");
95 SetServiceStatus(ServiceStatusHandle
,
99 case SERVICE_CONTROL_SHUTDOWN
:
100 DPRINT(" SERVICE_CONTROL_SHUTDOWN received\n");
102 LogfReportEvent(EVENTLOG_INFORMATION_TYPE
,
104 EVENT_EventlogStopped
, 0, NULL
, 0, NULL
);
106 UpdateServiceStatus(SERVICE_STOPPED
);
107 return ERROR_SUCCESS
;
110 DPRINT1(" Control %lu received\n", dwControl
);
111 return ERROR_CALL_NOT_IMPLEMENTED
;
121 hThread
= CreateThread(NULL
,
123 (LPTHREAD_START_ROUTINE
)
131 DPRINT("Can't create PortThread\n");
132 return GetLastError();
135 CloseHandle(hThread
);
137 hThread
= CreateThread(NULL
,
139 (LPTHREAD_START_ROUTINE
)
147 DPRINT("Can't create RpcThread\n");
148 return GetLastError();
151 CloseHandle(hThread
);
153 return ERROR_SUCCESS
;
158 ReportProductInfoEvent(VOID
)
160 OSVERSIONINFOW versionInfo
;
166 LONG lResult
= ERROR_SUCCESS
;
168 ZeroMemory(&versionInfo
, sizeof(OSVERSIONINFO
));
169 versionInfo
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
171 /* Get version information */
172 if (!GetVersionExW(&versionInfo
))
175 ZeroMemory(szBuffer
, 512 * sizeof(WCHAR
));
177 /* Write version into the buffer */
178 dwLength
= swprintf(szBuffer
,
180 versionInfo
.dwMajorVersion
,
181 versionInfo
.dwMinorVersion
) + 1;
183 /* Write build number into the buffer */
184 dwLength
+= swprintf(&szBuffer
[dwLength
],
186 versionInfo
.dwBuildNumber
) + 1;
188 /* Write service pack info into the buffer */
189 wcscpy(&szBuffer
[dwLength
], versionInfo
.szCSDVersion
);
190 dwLength
+= wcslen(versionInfo
.szCSDVersion
) + 1;
192 /* Read 'CurrentType' from the registry and write it into the buffer */
193 lResult
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
194 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
198 if (lResult
== ERROR_SUCCESS
)
200 dwValueLength
= 512 - dwLength
;
201 lResult
= RegQueryValueEx(hKey
,
205 (LPBYTE
)&szBuffer
[dwLength
],
211 /* Log the product information */
212 LogfReportEvent(EVENTLOG_INFORMATION_TYPE
,
214 EVENT_EventLogProductInfo
,
223 ServiceMain(DWORD argc
,
228 UNREFERENCED_PARAMETER(argc
);
229 UNREFERENCED_PARAMETER(argv
);
231 DPRINT("ServiceMain() called\n");
233 ServiceStatusHandle
= RegisterServiceCtrlHandlerExW(ServiceName
,
234 ServiceControlHandler
,
236 if (!ServiceStatusHandle
)
238 dwError
= GetLastError();
239 DPRINT1("RegisterServiceCtrlHandlerW() failed! (Error %lu)\n", dwError
);
243 UpdateServiceStatus(SERVICE_START_PENDING
);
245 dwError
= ServiceInit();
246 if (dwError
!= ERROR_SUCCESS
)
248 DPRINT("Service stopped (dwError: %lu\n", dwError
);
249 UpdateServiceStatus(SERVICE_START_PENDING
);
253 DPRINT("Service started\n");
254 UpdateServiceStatus(SERVICE_RUNNING
);
256 ReportProductInfoEvent();
258 LogfReportEvent(EVENTLOG_INFORMATION_TYPE
,
260 EVENT_EventlogStarted
,
267 DPRINT("ServiceMain() done\n");
271 PLOGFILE
LoadLogFile(HKEY hKey
, WCHAR
* LogName
)
273 DWORD MaxValueLen
, ValueLen
, Type
, ExpandedLen
;
274 WCHAR
*Buf
= NULL
, *Expanded
= NULL
;
276 PLOGFILE pLogf
= NULL
;
277 UNICODE_STRING FileName
;
280 DPRINT("LoadLogFile: %S\n", LogName
);
282 RegQueryInfoKey(hKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
283 NULL
, NULL
, &MaxValueLen
, NULL
, NULL
);
285 Buf
= HeapAlloc(MyHeap
, 0, MaxValueLen
);
288 DPRINT1("Can't allocate heap!\n");
292 ValueLen
= MaxValueLen
;
294 Result
= RegQueryValueEx(hKey
,
300 if (Result
!= ERROR_SUCCESS
)
302 DPRINT1("RegQueryValueEx failed: %lu\n", GetLastError());
303 HeapFree(MyHeap
, 0, Buf
);
307 if (Type
!= REG_EXPAND_SZ
&& Type
!= REG_SZ
)
309 DPRINT1("%S\\File - value of wrong type %x.\n", LogName
, Type
);
310 HeapFree(MyHeap
, 0, Buf
);
314 ExpandedLen
= ExpandEnvironmentStrings(Buf
, NULL
, 0);
315 Expanded
= HeapAlloc(MyHeap
, 0, ExpandedLen
* sizeof(WCHAR
));
318 DPRINT1("Can't allocate heap!\n");
319 HeapFree(MyHeap
, 0, Buf
);
323 ExpandEnvironmentStrings(Buf
, Expanded
, ExpandedLen
);
325 if (!RtlDosPathNameToNtPathName_U(Expanded
, &FileName
,
328 DPRINT1("Can't convert path!\n");
329 HeapFree(MyHeap
, 0, Expanded
);
330 HeapFree(MyHeap
, 0, Buf
);
334 DPRINT("%S -> %S\n", Buf
, Expanded
);
336 Status
= LogfCreate(&pLogf
, LogName
, &FileName
, TRUE
, FALSE
);
337 if (!NT_SUCCESS(Status
))
339 DPRINT1("Failed to create %S! (Status %08lx)\n", Expanded
, Status
);
342 HeapFree(MyHeap
, 0, Buf
);
343 HeapFree(MyHeap
, 0, Expanded
);
347 BOOL
LoadLogFiles(HKEY eventlogKey
)
350 DWORD MaxLognameLen
, LognameLen
;
355 RegQueryInfoKey(eventlogKey
,
356 NULL
, NULL
, NULL
, NULL
,
358 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
362 Buf
= HeapAlloc(MyHeap
, 0, MaxLognameLen
* sizeof(WCHAR
));
366 DPRINT1("Error: can't allocate heap!\n");
371 LognameLen
= MaxLognameLen
;
373 while (RegEnumKeyEx(eventlogKey
,
377 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
383 result
= RegOpenKeyEx(eventlogKey
, Buf
, 0, KEY_ALL_ACCESS
, &SubKey
);
384 if (result
!= ERROR_SUCCESS
)
386 DPRINT1("Failed to open %S key.\n", Buf
);
387 HeapFree(MyHeap
, 0, Buf
);
391 pLogFile
= LoadLogFile(SubKey
, Buf
);
392 if (pLogFile
!= NULL
)
394 DPRINT("Loaded %S\n", Buf
);
395 LoadEventSources(SubKey
, pLogFile
);
399 DPRINT1("Failed to load %S\n", Buf
);
403 LognameLen
= MaxLognameLen
;
407 HeapFree(MyHeap
, 0, Buf
);
413 WCHAR LogPath
[MAX_PATH
];
418 LogfListInitialize();
419 InitEventSourceList();
421 MyHeap
= HeapCreate(0, 1024 * 256, 0);
425 DPRINT1("FATAL ERROR, can't create heap.\n");
430 GetWindowsDirectory(LogPath
, MAX_PATH
);
432 if (GetDriveType(LogPath
) == DRIVE_CDROM
)
434 DPRINT("LiveCD detected\n");
439 result
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
440 L
"SYSTEM\\CurrentControlSet\\Services\\EventLog",
445 if (result
!= ERROR_SUCCESS
)
447 DPRINT1("Fatal error: can't open eventlog registry key.\n");
452 LoadLogFiles(elogKey
);
455 StartServiceCtrlDispatcher(ServiceTable
);
466 VOID
EventTimeToSystemTime(DWORD EventTime
, SYSTEMTIME
* pSystemTime
)
468 SYSTEMTIME st1970
= { 1970, 1, 0, 1, 0, 0, 0, 0 };
476 uUCT
.ft
.dwHighDateTime
= 0;
477 uUCT
.ft
.dwLowDateTime
= EventTime
;
478 SystemTimeToFileTime(&st1970
, &u1970
.ft
);
479 uUCT
.ll
= uUCT
.ll
* 10000000 + u1970
.ll
;
480 FileTimeToLocalFileTime(&uUCT
.ft
, &ftLocal
);
481 FileTimeToSystemTime(&ftLocal
, pSystemTime
);
484 VOID
SystemTimeToEventTime(SYSTEMTIME
* pSystemTime
, DWORD
* pEventTime
)
486 SYSTEMTIME st1970
= { 1970, 1, 0, 1, 0, 0, 0, 0 };
493 SystemTimeToFileTime(pSystemTime
, &Time
.ft
);
494 SystemTimeToFileTime(&st1970
, &u1970
.ft
);
495 *pEventTime
= (DWORD
)((Time
.ll
- u1970
.ll
) / 10000000ull);
498 VOID
PRINT_HEADER(PEVENTLOGHEADER header
)
500 DPRINT("HeaderSize = %lu\n", header
->HeaderSize
);
501 DPRINT("Signature = 0x%x\n", header
->Signature
);
502 DPRINT("MajorVersion = %lu\n", header
->MajorVersion
);
503 DPRINT("MinorVersion = %lu\n", header
->MinorVersion
);
504 DPRINT("StartOffset = %lu\n", header
->StartOffset
);
505 DPRINT("EndOffset = 0x%x\n", header
->EndOffset
);
506 DPRINT("CurrentRecordNumber = %lu\n", header
->CurrentRecordNumber
);
507 DPRINT("OldestRecordNumber = %lu\n", header
->OldestRecordNumber
);
508 DPRINT("MaxSize = 0x%x\n", header
->MaxSize
);
509 DPRINT("Retention = 0x%x\n", header
->Retention
);
510 DPRINT("EndHeaderSize = %lu\n", header
->EndHeaderSize
);
512 if (header
->Flags
& ELF_LOGFILE_HEADER_DIRTY
) DPRINT("ELF_LOGFILE_HEADER_DIRTY");
513 if (header
->Flags
& ELF_LOGFILE_HEADER_WRAP
) DPRINT("| ELF_LOGFILE_HEADER_WRAP ");
514 if (header
->Flags
& ELF_LOGFILE_LOGFULL_WRITTEN
) DPRINT("| ELF_LOGFILE_LOGFULL_WRITTEN ");
515 if (header
->Flags
& ELF_LOGFILE_ARCHIVE_SET
) DPRINT("| ELF_LOGFILE_ARCHIVE_SET ");
519 VOID
PRINT_RECORD(PEVENTLOGRECORD pRec
)
525 DPRINT("Length = %lu\n", pRec
->Length
);
526 DPRINT("Reserved = 0x%x\n", pRec
->Reserved
);
527 DPRINT("RecordNumber = %lu\n", pRec
->RecordNumber
);
529 EventTimeToSystemTime(pRec
->TimeGenerated
, &time
);
530 DPRINT("TimeGenerated = %hu.%hu.%hu %hu:%hu:%hu\n",
531 time
.wDay
, time
.wMonth
, time
.wYear
,
532 time
.wHour
, time
.wMinute
, time
.wSecond
);
534 EventTimeToSystemTime(pRec
->TimeWritten
, &time
);
535 DPRINT("TimeWritten = %hu.%hu.%hu %hu:%hu:%hu\n",
536 time
.wDay
, time
.wMonth
, time
.wYear
,
537 time
.wHour
, time
.wMinute
, time
.wSecond
);
539 DPRINT("EventID = %lu\n", pRec
->EventID
);
541 switch (pRec
->EventType
)
543 case EVENTLOG_ERROR_TYPE
:
544 DPRINT("EventType = EVENTLOG_ERROR_TYPE\n");
546 case EVENTLOG_WARNING_TYPE
:
547 DPRINT("EventType = EVENTLOG_WARNING_TYPE\n");
549 case EVENTLOG_INFORMATION_TYPE
:
550 DPRINT("EventType = EVENTLOG_INFORMATION_TYPE\n");
552 case EVENTLOG_AUDIT_SUCCESS
:
553 DPRINT("EventType = EVENTLOG_AUDIT_SUCCESS\n");
555 case EVENTLOG_AUDIT_FAILURE
:
556 DPRINT("EventType = EVENTLOG_AUDIT_FAILURE\n");
559 DPRINT("EventType = %hu\n", pRec
->EventType
);
562 DPRINT("NumStrings = %hu\n", pRec
->NumStrings
);
563 DPRINT("EventCategory = %hu\n", pRec
->EventCategory
);
564 DPRINT("ReservedFlags = 0x%x\n", pRec
->ReservedFlags
);
565 DPRINT("ClosingRecordNumber = %lu\n", pRec
->ClosingRecordNumber
);
566 DPRINT("StringOffset = %lu\n", pRec
->StringOffset
);
567 DPRINT("UserSidLength = %lu\n", pRec
->UserSidLength
);
568 DPRINT("UserSidOffset = %lu\n", pRec
->UserSidOffset
);
569 DPRINT("DataLength = %lu\n", pRec
->DataLength
);
570 DPRINT("DataOffset = %lu\n", pRec
->DataOffset
);
572 DPRINT("SourceName: %S\n", (WCHAR
*) (((PBYTE
) pRec
) + sizeof(EVENTLOGRECORD
)));
574 i
= (lstrlenW((WCHAR
*) (((PBYTE
) pRec
) + sizeof(EVENTLOGRECORD
))) + 1) *
577 DPRINT("ComputerName: %S\n", (WCHAR
*) (((PBYTE
) pRec
) + sizeof(EVENTLOGRECORD
) + i
));
579 if (pRec
->StringOffset
< pRec
->Length
&& pRec
->NumStrings
)
581 DPRINT("Strings:\n");
582 str
= (WCHAR
*) (((PBYTE
) pRec
) + pRec
->StringOffset
);
583 for (i
= 0; i
< pRec
->NumStrings
; i
++)
585 DPRINT("[%u] %S\n", i
, str
);
586 str
= str
+ lstrlenW(str
) + 1;
590 DPRINT("Length2 = %lu\n", *(PDWORD
) (((PBYTE
) pRec
) + pRec
->Length
- 4));