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
;
278 ULONG ulMaxSize
, ulRetention
;
281 DPRINT("LoadLogFile: %S\n", LogName
);
283 RegQueryInfoKey(hKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
284 NULL
, NULL
, &MaxValueLen
, NULL
, NULL
);
286 Buf
= HeapAlloc(MyHeap
, 0, MaxValueLen
);
289 DPRINT1("Can't allocate heap!\n");
293 ValueLen
= MaxValueLen
;
295 Result
= RegQueryValueEx(hKey
,
301 if (Result
!= ERROR_SUCCESS
)
303 DPRINT1("RegQueryValueEx failed: %lu\n", GetLastError());
304 HeapFree(MyHeap
, 0, Buf
);
308 if (Type
!= REG_EXPAND_SZ
&& Type
!= REG_SZ
)
310 DPRINT1("%S\\File - value of wrong type %x.\n", LogName
, Type
);
311 HeapFree(MyHeap
, 0, Buf
);
315 ExpandedLen
= ExpandEnvironmentStrings(Buf
, NULL
, 0);
316 Expanded
= HeapAlloc(MyHeap
, 0, ExpandedLen
* sizeof(WCHAR
));
319 DPRINT1("Can't allocate heap!\n");
320 HeapFree(MyHeap
, 0, Buf
);
324 ExpandEnvironmentStrings(Buf
, Expanded
, ExpandedLen
);
326 if (!RtlDosPathNameToNtPathName_U(Expanded
, &FileName
,
329 DPRINT1("Can't convert path!\n");
330 HeapFree(MyHeap
, 0, Expanded
);
331 HeapFree(MyHeap
, 0, Buf
);
335 DPRINT("%S -> %S\n", Buf
, Expanded
);
337 ValueLen
= sizeof(ULONG
);
338 Result
= RegQueryValueEx(hKey
,
344 if (Result
!= ERROR_SUCCESS
)
345 ulMaxSize
= 512 * 1024; /* 512 kBytes */
347 ValueLen
= sizeof(ULONG
);
348 Result
= RegQueryValueEx(hKey
,
352 (LPBYTE
)&ulRetention
,
354 if (Result
!= ERROR_SUCCESS
)
357 Status
= LogfCreate(&pLogf
, LogName
, &FileName
, ulMaxSize
, ulRetention
, TRUE
, FALSE
);
358 if (!NT_SUCCESS(Status
))
360 DPRINT1("Failed to create %S! (Status %08lx)\n", Expanded
, Status
);
363 HeapFree(MyHeap
, 0, Buf
);
364 HeapFree(MyHeap
, 0, Expanded
);
368 BOOL
LoadLogFiles(HKEY eventlogKey
)
371 DWORD MaxLognameLen
, LognameLen
;
376 RegQueryInfoKey(eventlogKey
,
377 NULL
, NULL
, NULL
, NULL
,
379 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
383 Buf
= HeapAlloc(MyHeap
, 0, MaxLognameLen
* sizeof(WCHAR
));
387 DPRINT1("Error: can't allocate heap!\n");
392 LognameLen
= MaxLognameLen
;
394 while (RegEnumKeyEx(eventlogKey
,
398 NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
404 result
= RegOpenKeyEx(eventlogKey
, Buf
, 0, KEY_ALL_ACCESS
, &SubKey
);
405 if (result
!= ERROR_SUCCESS
)
407 DPRINT1("Failed to open %S key.\n", Buf
);
408 HeapFree(MyHeap
, 0, Buf
);
412 pLogFile
= LoadLogFile(SubKey
, Buf
);
413 if (pLogFile
!= NULL
)
415 DPRINT("Loaded %S\n", Buf
);
416 LoadEventSources(SubKey
, pLogFile
);
420 DPRINT1("Failed to load %S\n", Buf
);
424 LognameLen
= MaxLognameLen
;
428 HeapFree(MyHeap
, 0, Buf
);
434 WCHAR LogPath
[MAX_PATH
];
439 LogfListInitialize();
440 InitEventSourceList();
442 MyHeap
= HeapCreate(0, 1024 * 256, 0);
446 DPRINT1("FATAL ERROR, can't create heap.\n");
451 GetWindowsDirectory(LogPath
, MAX_PATH
);
453 if (GetDriveType(LogPath
) == DRIVE_CDROM
)
455 DPRINT("LiveCD detected\n");
460 result
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
461 L
"SYSTEM\\CurrentControlSet\\Services\\EventLog",
466 if (result
!= ERROR_SUCCESS
)
468 DPRINT1("Fatal error: can't open eventlog registry key.\n");
473 LoadLogFiles(elogKey
);
476 StartServiceCtrlDispatcher(ServiceTable
);
487 VOID
EventTimeToSystemTime(DWORD EventTime
, SYSTEMTIME
* pSystemTime
)
489 SYSTEMTIME st1970
= { 1970, 1, 0, 1, 0, 0, 0, 0 };
497 uUCT
.ft
.dwHighDateTime
= 0;
498 uUCT
.ft
.dwLowDateTime
= EventTime
;
499 SystemTimeToFileTime(&st1970
, &u1970
.ft
);
500 uUCT
.ll
= uUCT
.ll
* 10000000 + u1970
.ll
;
501 FileTimeToLocalFileTime(&uUCT
.ft
, &ftLocal
);
502 FileTimeToSystemTime(&ftLocal
, pSystemTime
);
505 VOID
SystemTimeToEventTime(SYSTEMTIME
* pSystemTime
, DWORD
* pEventTime
)
507 SYSTEMTIME st1970
= { 1970, 1, 0, 1, 0, 0, 0, 0 };
514 SystemTimeToFileTime(pSystemTime
, &Time
.ft
);
515 SystemTimeToFileTime(&st1970
, &u1970
.ft
);
516 *pEventTime
= (DWORD
)((Time
.ll
- u1970
.ll
) / 10000000ull);
519 VOID
PRINT_HEADER(PEVENTLOGHEADER header
)
521 DPRINT("HeaderSize = %lu\n", header
->HeaderSize
);
522 DPRINT("Signature = 0x%x\n", header
->Signature
);
523 DPRINT("MajorVersion = %lu\n", header
->MajorVersion
);
524 DPRINT("MinorVersion = %lu\n", header
->MinorVersion
);
525 DPRINT("StartOffset = %lu\n", header
->StartOffset
);
526 DPRINT("EndOffset = 0x%x\n", header
->EndOffset
);
527 DPRINT("CurrentRecordNumber = %lu\n", header
->CurrentRecordNumber
);
528 DPRINT("OldestRecordNumber = %lu\n", header
->OldestRecordNumber
);
529 DPRINT("MaxSize = 0x%x\n", header
->MaxSize
);
530 DPRINT("Retention = 0x%x\n", header
->Retention
);
531 DPRINT("EndHeaderSize = %lu\n", header
->EndHeaderSize
);
533 if (header
->Flags
& ELF_LOGFILE_HEADER_DIRTY
) DPRINT("ELF_LOGFILE_HEADER_DIRTY");
534 if (header
->Flags
& ELF_LOGFILE_HEADER_WRAP
) DPRINT("| ELF_LOGFILE_HEADER_WRAP ");
535 if (header
->Flags
& ELF_LOGFILE_LOGFULL_WRITTEN
) DPRINT("| ELF_LOGFILE_LOGFULL_WRITTEN ");
536 if (header
->Flags
& ELF_LOGFILE_ARCHIVE_SET
) DPRINT("| ELF_LOGFILE_ARCHIVE_SET ");
540 VOID
PRINT_RECORD(PEVENTLOGRECORD pRec
)
546 DPRINT("Length = %lu\n", pRec
->Length
);
547 DPRINT("Reserved = 0x%x\n", pRec
->Reserved
);
548 DPRINT("RecordNumber = %lu\n", pRec
->RecordNumber
);
550 EventTimeToSystemTime(pRec
->TimeGenerated
, &time
);
551 DPRINT("TimeGenerated = %hu.%hu.%hu %hu:%hu:%hu\n",
552 time
.wDay
, time
.wMonth
, time
.wYear
,
553 time
.wHour
, time
.wMinute
, time
.wSecond
);
555 EventTimeToSystemTime(pRec
->TimeWritten
, &time
);
556 DPRINT("TimeWritten = %hu.%hu.%hu %hu:%hu:%hu\n",
557 time
.wDay
, time
.wMonth
, time
.wYear
,
558 time
.wHour
, time
.wMinute
, time
.wSecond
);
560 DPRINT("EventID = %lu\n", pRec
->EventID
);
562 switch (pRec
->EventType
)
564 case EVENTLOG_ERROR_TYPE
:
565 DPRINT("EventType = EVENTLOG_ERROR_TYPE\n");
567 case EVENTLOG_WARNING_TYPE
:
568 DPRINT("EventType = EVENTLOG_WARNING_TYPE\n");
570 case EVENTLOG_INFORMATION_TYPE
:
571 DPRINT("EventType = EVENTLOG_INFORMATION_TYPE\n");
573 case EVENTLOG_AUDIT_SUCCESS
:
574 DPRINT("EventType = EVENTLOG_AUDIT_SUCCESS\n");
576 case EVENTLOG_AUDIT_FAILURE
:
577 DPRINT("EventType = EVENTLOG_AUDIT_FAILURE\n");
580 DPRINT("EventType = %hu\n", pRec
->EventType
);
583 DPRINT("NumStrings = %hu\n", pRec
->NumStrings
);
584 DPRINT("EventCategory = %hu\n", pRec
->EventCategory
);
585 DPRINT("ReservedFlags = 0x%x\n", pRec
->ReservedFlags
);
586 DPRINT("ClosingRecordNumber = %lu\n", pRec
->ClosingRecordNumber
);
587 DPRINT("StringOffset = %lu\n", pRec
->StringOffset
);
588 DPRINT("UserSidLength = %lu\n", pRec
->UserSidLength
);
589 DPRINT("UserSidOffset = %lu\n", pRec
->UserSidOffset
);
590 DPRINT("DataLength = %lu\n", pRec
->DataLength
);
591 DPRINT("DataOffset = %lu\n", pRec
->DataOffset
);
593 DPRINT("SourceName: %S\n", (WCHAR
*) (((PBYTE
) pRec
) + sizeof(EVENTLOGRECORD
)));
595 i
= (lstrlenW((WCHAR
*) (((PBYTE
) pRec
) + sizeof(EVENTLOGRECORD
))) + 1) *
598 DPRINT("ComputerName: %S\n", (WCHAR
*) (((PBYTE
) pRec
) + sizeof(EVENTLOGRECORD
) + i
));
600 if (pRec
->StringOffset
< pRec
->Length
&& pRec
->NumStrings
)
602 DPRINT("Strings:\n");
603 str
= (WCHAR
*) (((PBYTE
) pRec
) + pRec
->StringOffset
);
604 for (i
= 0; i
< pRec
->NumStrings
; i
++)
606 DPRINT("[%u] %S\n", i
, str
);
607 str
= str
+ lstrlenW(str
) + 1;
611 DPRINT("Length2 = %lu\n", *(PDWORD
) (((PBYTE
) pRec
) + pRec
->Length
- 4));