Sync with trunk head.
[reactos.git] / base / services / eventlog / eventlog.c
1 /*
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
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "eventlog.h"
13
14 /* GLOBALS ******************************************************************/
15
16 static VOID CALLBACK ServiceMain(DWORD, LPWSTR *);
17 static WCHAR ServiceName[] = L"EventLog";
18 static SERVICE_TABLE_ENTRYW ServiceTable[2] =
19 {
20 { ServiceName, ServiceMain },
21 { NULL, NULL }
22 };
23
24 SERVICE_STATUS ServiceStatus;
25 SERVICE_STATUS_HANDLE ServiceStatusHandle;
26
27 BOOL onLiveCD = FALSE; // On livecd events will go to debug output only
28 HANDLE MyHeap = NULL;
29
30 /* FUNCTIONS ****************************************************************/
31
32 static VOID
33 UpdateServiceStatus(DWORD dwState)
34 {
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;
41
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;
47 else
48 ServiceStatus.dwWaitHint = 0;
49
50 SetServiceStatus(ServiceStatusHandle,
51 &ServiceStatus);
52 }
53
54 static DWORD WINAPI
55 ServiceControlHandler(DWORD dwControl,
56 DWORD dwEventType,
57 LPVOID lpEventData,
58 LPVOID lpContext)
59 {
60 DPRINT("ServiceControlHandler() called\n");
61
62 switch (dwControl)
63 {
64 case SERVICE_CONTROL_STOP:
65 DPRINT(" SERVICE_CONTROL_STOP received\n");
66 UpdateServiceStatus(SERVICE_STOPPED);
67 return ERROR_SUCCESS;
68
69 case SERVICE_CONTROL_PAUSE:
70 DPRINT(" SERVICE_CONTROL_PAUSE received\n");
71 UpdateServiceStatus(SERVICE_PAUSED);
72 return ERROR_SUCCESS;
73
74 case SERVICE_CONTROL_CONTINUE:
75 DPRINT(" SERVICE_CONTROL_CONTINUE received\n");
76 UpdateServiceStatus(SERVICE_RUNNING);
77 return ERROR_SUCCESS;
78
79 case SERVICE_CONTROL_INTERROGATE:
80 DPRINT(" SERVICE_CONTROL_INTERROGATE received\n");
81 SetServiceStatus(ServiceStatusHandle,
82 &ServiceStatus);
83 return ERROR_SUCCESS;
84
85 case SERVICE_CONTROL_SHUTDOWN:
86 DPRINT(" SERVICE_CONTROL_SHUTDOWN received\n");
87 UpdateServiceStatus(SERVICE_STOPPED);
88 return ERROR_SUCCESS;
89
90 default :
91 DPRINT1(" Control %lu received\n");
92 return ERROR_CALL_NOT_IMPLEMENTED;
93 }
94 }
95
96
97 static DWORD
98 ServiceInit(VOID)
99 {
100 HANDLE hThread;
101
102 hThread = CreateThread(NULL,
103 0,
104 (LPTHREAD_START_ROUTINE)
105 PortThreadRoutine,
106 NULL,
107 0,
108 NULL);
109
110 if (!hThread)
111 {
112 DPRINT("Can't create PortThread\n");
113 return GetLastError();
114 }
115 else
116 CloseHandle(hThread);
117
118 hThread = CreateThread(NULL,
119 0,
120 (LPTHREAD_START_ROUTINE)
121 RpcThreadRoutine,
122 NULL,
123 0,
124 NULL);
125
126 if (!hThread)
127 {
128 DPRINT("Can't create RpcThread\n");
129 return GetLastError();
130 }
131 else
132 CloseHandle(hThread);
133
134 return ERROR_SUCCESS;
135 }
136
137
138 static VOID CALLBACK
139 ServiceMain(DWORD argc,
140 LPWSTR *argv)
141 {
142 DWORD dwError;
143
144 UNREFERENCED_PARAMETER(argc);
145 UNREFERENCED_PARAMETER(argv);
146
147 DPRINT("ServiceMain() called\n");
148
149 ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
150 ServiceControlHandler,
151 NULL);
152 if (!ServiceStatusHandle)
153 {
154 dwError = GetLastError();
155 DPRINT1("RegisterServiceCtrlHandlerW() failed! (Error %lu)\n", dwError);
156 return;
157 }
158
159 UpdateServiceStatus(SERVICE_START_PENDING);
160
161 dwError = ServiceInit();
162 if (dwError != ERROR_SUCCESS)
163 {
164 DPRINT("Service stopped (dwError: %lu\n", dwError);
165 UpdateServiceStatus(SERVICE_START_PENDING);
166 }
167 else
168 {
169 DPRINT("Service started\n");
170 UpdateServiceStatus(SERVICE_RUNNING);
171 }
172
173 DPRINT("ServiceMain() done\n");
174 }
175
176
177 BOOL LoadLogFile(HKEY hKey, WCHAR * LogName)
178 {
179 DWORD MaxValueLen, ValueLen, Type, ExpandedLen;
180 WCHAR *Buf = NULL, *Expanded = NULL;
181 LONG Result;
182 BOOL ret = TRUE;
183 PLOGFILE pLogf;
184
185 DPRINT("LoadLogFile: %S\n", LogName);
186
187 RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
188 NULL, NULL, &MaxValueLen, NULL, NULL);
189
190 Buf = HeapAlloc(MyHeap, 0, MaxValueLen);
191
192 if (!Buf)
193 {
194 DPRINT1("Can't allocate heap!\n");
195 return FALSE;
196 }
197
198 ValueLen = MaxValueLen;
199
200 Result = RegQueryValueEx(hKey,
201 L"File",
202 NULL,
203 &Type,
204 (LPBYTE) Buf,
205 &ValueLen);
206
207 if (Result != ERROR_SUCCESS)
208 {
209 DPRINT1("RegQueryValueEx failed: %d\n", GetLastError());
210 HeapFree(MyHeap, 0, Buf);
211 return FALSE;
212 }
213
214 if (Type != REG_EXPAND_SZ && Type != REG_SZ)
215 {
216 DPRINT1("%S\\File - value of wrong type %x.\n", LogName, Type);
217 HeapFree(MyHeap, 0, Buf);
218 return FALSE;
219 }
220
221 ExpandedLen = ExpandEnvironmentStrings(Buf, NULL, 0);
222 Expanded = HeapAlloc(MyHeap, 0, ExpandedLen * sizeof(WCHAR));
223
224 if (!Expanded)
225 {
226 DPRINT1("Can't allocate heap!\n");
227 HeapFree(MyHeap, 0, Buf);
228 return FALSE;
229 }
230
231 ExpandEnvironmentStrings(Buf, Expanded, ExpandedLen);
232
233 DPRINT("%S -> %S\n", Buf, Expanded);
234
235 pLogf = LogfCreate(LogName, Expanded);
236
237 if (pLogf == NULL)
238 {
239 DPRINT1("Failed to create %S!\n", Expanded);
240 ret = FALSE;
241 }
242
243 HeapFree(MyHeap, 0, Buf);
244 HeapFree(MyHeap, 0, Expanded);
245 return ret;
246 }
247
248 BOOL LoadLogFiles(HKEY eventlogKey)
249 {
250 LONG result;
251 DWORD MaxLognameLen, LognameLen;
252 WCHAR *Buf = NULL;
253 INT i;
254
255 RegQueryInfoKey(eventlogKey,
256 NULL, NULL, NULL, NULL,
257 &MaxLognameLen,
258 NULL, NULL, NULL, NULL, NULL, NULL);
259
260 MaxLognameLen++;
261
262 Buf = HeapAlloc(MyHeap, 0, MaxLognameLen * sizeof(WCHAR));
263
264 if (!Buf)
265 {
266 DPRINT1("Error: can't allocate heap!\n");
267 return FALSE;
268 }
269
270 i = 0;
271 LognameLen = MaxLognameLen;
272
273 while (RegEnumKeyEx(eventlogKey,
274 i,
275 Buf,
276 &LognameLen,
277 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
278 {
279 HKEY SubKey;
280
281 DPRINT("%S\n", Buf);
282
283 result = RegOpenKeyEx(eventlogKey, Buf, 0, KEY_ALL_ACCESS, &SubKey);
284 if (result != ERROR_SUCCESS)
285 {
286 DPRINT1("Failed to open %S key.\n", Buf);
287 HeapFree(MyHeap, 0, Buf);
288 return FALSE;
289 }
290
291 if (!LoadLogFile(SubKey, Buf))
292 DPRINT1("Failed to load %S\n", Buf);
293 else
294 DPRINT("Loaded %S\n", Buf);
295
296 RegCloseKey(SubKey);
297 LognameLen = MaxLognameLen;
298 i++;
299 }
300
301 HeapFree(MyHeap, 0, Buf);
302 return TRUE;
303 }
304
305 INT wmain()
306 {
307 WCHAR LogPath[MAX_PATH];
308 INT RetCode = 0;
309 LONG result;
310 HKEY elogKey;
311
312 LogfListInitialize();
313
314 MyHeap = HeapCreate(0, 1024 * 256, 0);
315
316 if (!MyHeap)
317 {
318 DPRINT1("FATAL ERROR, can't create heap.\n");
319 RetCode = 1;
320 goto bye_bye;
321 }
322
323 GetWindowsDirectory(LogPath, MAX_PATH);
324
325 if (GetDriveType(LogPath) == DRIVE_CDROM)
326 {
327 DPRINT("LiveCD detected\n");
328 onLiveCD = TRUE;
329 }
330 else
331 {
332 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
333 L"SYSTEM\\CurrentControlSet\\Services\\EventLog",
334 0,
335 KEY_ALL_ACCESS,
336 &elogKey);
337
338 if (result != ERROR_SUCCESS)
339 {
340 DPRINT1("Fatal error: can't open eventlog registry key.\n");
341 RetCode = 1;
342 goto bye_bye;
343 }
344
345 LoadLogFiles(elogKey);
346 }
347
348 StartServiceCtrlDispatcher(ServiceTable);
349
350 bye_bye:
351 LogfCloseAll();
352
353 if (MyHeap)
354 HeapDestroy(MyHeap);
355
356 return RetCode;
357 }
358
359 VOID EventTimeToSystemTime(DWORD EventTime, SYSTEMTIME * pSystemTime)
360 {
361 SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
362 FILETIME ftLocal;
363 union
364 {
365 FILETIME ft;
366 ULONGLONG ll;
367 } u1970, uUCT;
368
369 uUCT.ft.dwHighDateTime = 0;
370 uUCT.ft.dwLowDateTime = EventTime;
371 SystemTimeToFileTime(&st1970, &u1970.ft);
372 uUCT.ll = uUCT.ll * 10000000 + u1970.ll;
373 FileTimeToLocalFileTime(&uUCT.ft, &ftLocal);
374 FileTimeToSystemTime(&ftLocal, pSystemTime);
375 }
376
377 VOID SystemTimeToEventTime(SYSTEMTIME * pSystemTime, DWORD * pEventTime)
378 {
379 SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
380 union
381 {
382 FILETIME ft;
383 ULONGLONG ll;
384 } Time, u1970;
385
386 SystemTimeToFileTime(pSystemTime, &Time.ft);
387 SystemTimeToFileTime(&st1970, &u1970.ft);
388 *pEventTime = (Time.ll - u1970.ll) / 10000000;
389 }
390
391 VOID PRINT_HEADER(PEVENTLOGHEADER header)
392 {
393 DPRINT("HeaderSize = %d\n", header->HeaderSize);
394 DPRINT("Signature = 0x%x\n", header->Signature);
395 DPRINT("MajorVersion = %d\n", header->MajorVersion);
396 DPRINT("MinorVersion = %d\n", header->MinorVersion);
397 DPRINT("StartOffset = %d\n", header->StartOffset);
398 DPRINT("EndOffset = 0x%x\n", header->EndOffset);
399 DPRINT("CurrentRecordNumber = %d\n", header->CurrentRecordNumber);
400 DPRINT("OldestRecordNumber = %d\n", header->OldestRecordNumber);
401 DPRINT("MaxSize = 0x%x\n", header->MaxSize);
402 DPRINT("Retention = 0x%x\n", header->Retention);
403 DPRINT("EndHeaderSize = %d\n", header->EndHeaderSize);
404 DPRINT("Flags: ");
405 if (header->Flags & ELF_LOGFILE_HEADER_DIRTY) DPRINT("ELF_LOGFILE_HEADER_DIRTY");
406 if (header->Flags & ELF_LOGFILE_HEADER_WRAP) DPRINT("| ELF_LOGFILE_HEADER_WRAP ");
407 if (header->Flags & ELF_LOGGFILE_LOGFULL_WRITTEN) DPRINT("| ELF_LOGGFILE_LOGFULL_WRITTEN ");
408 if (header->Flags & ELF_LOGFILE_ARCHIVE_SET) DPRINT("| ELF_LOGFILE_ARCHIVE_SET ");
409 DPRINT("\n");
410 }
411
412 VOID PRINT_RECORD(PEVENTLOGRECORD pRec)
413 {
414 UINT i;
415 WCHAR *str;
416 SYSTEMTIME time;
417
418 DPRINT("Length = %d\n", pRec->Length);
419 DPRINT("Reserved = 0x%x\n", pRec->Reserved);
420 DPRINT("RecordNumber = %d\n", pRec->RecordNumber);
421
422 EventTimeToSystemTime(pRec->TimeGenerated, &time);
423 DPRINT("TimeGenerated = %d.%d.%d %d:%d:%d\n",
424 time.wDay, time.wMonth, time.wYear,
425 time.wHour, time.wMinute, time.wSecond);
426
427 EventTimeToSystemTime(pRec->TimeWritten, &time);
428 DPRINT("TimeWritten = %d.%d.%d %d:%d:%d\n",
429 time.wDay, time.wMonth, time.wYear,
430 time.wHour, time.wMinute, time.wSecond);
431
432 DPRINT("EventID = %d\n", pRec->EventID);
433
434 switch (pRec->EventType)
435 {
436 case EVENTLOG_ERROR_TYPE:
437 DPRINT("EventType = EVENTLOG_ERROR_TYPE\n");
438 break;
439 case EVENTLOG_WARNING_TYPE:
440 DPRINT("EventType = EVENTLOG_WARNING_TYPE\n");
441 break;
442 case EVENTLOG_INFORMATION_TYPE:
443 DPRINT("EventType = EVENTLOG_INFORMATION_TYPE\n");
444 break;
445 case EVENTLOG_AUDIT_SUCCESS:
446 DPRINT("EventType = EVENTLOG_AUDIT_SUCCESS\n");
447 break;
448 case EVENTLOG_AUDIT_FAILURE:
449 DPRINT("EventType = EVENTLOG_AUDIT_FAILURE\n");
450 break;
451 default:
452 DPRINT("EventType = %d\n", pRec->EventType);
453 }
454
455 DPRINT("NumStrings = %d\n", pRec->NumStrings);
456 DPRINT("EventCategory = %d\n", pRec->EventCategory);
457 DPRINT("ReservedFlags = 0x%x\n", pRec->ReservedFlags);
458 DPRINT("ClosingRecordNumber = %d\n", pRec->ClosingRecordNumber);
459 DPRINT("StringOffset = %d\n", pRec->StringOffset);
460 DPRINT("UserSidLength = %d\n", pRec->UserSidLength);
461 DPRINT("UserSidOffset = %d\n", pRec->UserSidOffset);
462 DPRINT("DataLength = %d\n", pRec->DataLength);
463 DPRINT("DataOffset = %d\n", pRec->DataOffset);
464
465 DPRINT("SourceName: %S\n", (WCHAR *) (((PBYTE) pRec) + sizeof(EVENTLOGRECORD)));
466
467 i = (lstrlenW((WCHAR *) (((PBYTE) pRec) + sizeof(EVENTLOGRECORD))) + 1) *
468 sizeof(WCHAR);
469
470 DPRINT("ComputerName: %S\n", (WCHAR *) (((PBYTE) pRec) + sizeof(EVENTLOGRECORD) + i));
471
472 if (pRec->StringOffset < pRec->Length && pRec->NumStrings)
473 {
474 DPRINT("Strings:\n");
475 str = (WCHAR *) (((PBYTE) pRec) + pRec->StringOffset);
476 for (i = 0; i < pRec->NumStrings; i++)
477 {
478 DPRINT("[%d] %S\n", i, str);
479 str = str + lstrlenW(str) + 1;
480 }
481 }
482
483 DPRINT("Length2 = %d\n", *(PDWORD) (((PBYTE) pRec) + pRec->Length - 4));
484 }