Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

405 lines
14 KiB

  1. /**************************************************************************************************
  2. FILENAME: ErrLog.cpp
  3. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  4. */
  5. #include "stdafx.h"
  6. #ifdef BOOTIME
  7. extern "C"{
  8. #include <stdio.h>
  9. }
  10. #include "Offline.h"
  11. #else
  12. #ifndef NOWINDOWSH
  13. #include <windows.h>
  14. #endif
  15. #endif
  16. #include "ErrLog.h"
  17. #include "secattr.h"
  18. static HANDLE hErrLogMutex = NULL;
  19. static TCHAR cErrLogName[200];
  20. static BOOL bErrLogEnabled = FALSE;
  21. static TCHAR cLoggerIdentifier[256];
  22. #define ERRLOG_MUTEX_NAME "Dfrg Error Log"
  23. /**************************************************************************************************
  24. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  25. ROUTINE DESCRIPTION:
  26. This routine is called to enable the Error Log.
  27. GLOBALS:
  28. hErrLogMutex : Mutex to sychronize write access to the Error Log.
  29. cErrLogName : Where the name of the error log is stored.
  30. bErrLogEnabled : Boolean to indicate whether the error log has been initialized.
  31. INPUT:
  32. pErrLogName - String containing full path/file name of log file.
  33. pLoggerIdentifier - String containing on identification of who is doing this logging.
  34. RETURN:
  35. TRUE - Success
  36. FALSE - Failure (indicates that the error log could not be created)
  37. */
  38. BOOL
  39. InitializeErrorLog (
  40. IN PTCHAR pErrLogName,
  41. IN PTCHAR pLoggerIdentifier
  42. )
  43. {
  44. HANDLE hErrLog = NULL; // Handle to the Error Log.
  45. BOOL bRetStatus = TRUE;
  46. OVERLAPPED LogOverLap;
  47. SECURITY_ATTRIBUTES saSecurityAttributes;
  48. SECURITY_DESCRIPTOR sdSecurityDescriptor;
  49. ZeroMemory(&LogOverLap, sizeof(OVERLAPPED));
  50. ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  51. // Check if a mutex has been created to synchronize writing to the Log file
  52. if (NULL == hErrLogMutex) {
  53. hErrLogMutex = CreateMutex(NULL, FALSE, TEXT(ERRLOG_MUTEX_NAME));
  54. }
  55. if (NULL == hErrLogMutex) {
  56. return FALSE;
  57. }
  58. saSecurityAttributes.nLength = sizeof (saSecurityAttributes);
  59. saSecurityAttributes.lpSecurityDescriptor = &sdSecurityDescriptor;
  60. saSecurityAttributes.bInheritHandle = FALSE;
  61. if (!ConstructSecurityAttributes(&saSecurityAttributes, esatFile, FALSE)) {
  62. return FALSE;
  63. }
  64. // Make sure that we can Create/Open the Log file
  65. hErrLog = CreateFile(pErrLogName,
  66. GENERIC_READ|GENERIC_WRITE,
  67. FILE_SHARE_READ|FILE_SHARE_WRITE,
  68. &saSecurityAttributes,
  69. OPEN_ALWAYS,
  70. FILE_ATTRIBUTE_NORMAL,
  71. NULL);
  72. CleanupSecurityAttributes(&saSecurityAttributes);
  73. ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  74. if (INVALID_HANDLE_VALUE == hErrLog) {
  75. return FALSE;
  76. }
  77. // On success, set up the overlay option so we known the offset to
  78. // the end of the file, so when we write, we append to the end of the file.
  79. LogOverLap.Offset = GetFileSize(hErrLog, &LogOverLap.OffsetHigh);
  80. LogOverLap.hEvent = NULL;
  81. //If the log file is greater than 64K in size, we want to keep that last 64K and nuke everything before it.
  82. //This keeps the log file from becoming too much larger than 64K,
  83. //and it guarantees that we have all the errors in the last pass (which may be more than 64K, but the file won't be shrunk until another instance is run.)
  84. if(LogOverLap.Offset > 0x10000) {
  85. HANDLE hBuffer = NULL;
  86. char* pBuffer = NULL;
  87. DWORD dwRead = 0;
  88. DWORD dwWritten = 0;
  89. //Allocate a 64K to hold the last 64K of the file.
  90. if(!(hBuffer = GlobalAlloc(GHND, 0x10000))){
  91. bRetStatus = FALSE;
  92. }
  93. if(!(pBuffer = (char*)GlobalLock(hBuffer))){
  94. bRetStatus = FALSE;
  95. }
  96. if (bRetStatus) {
  97. //Read the last 64K
  98. LogOverLap.Offset -= 0x10000;
  99. if(!ReadFile(hErrLog, pBuffer, 0x10000, &dwRead, &LogOverLap)){
  100. bRetStatus = FALSE;
  101. }
  102. //We want to create the file again in order to truncate it.
  103. CloseHandle(hErrLog);
  104. saSecurityAttributes.nLength = sizeof (saSecurityAttributes);
  105. saSecurityAttributes.lpSecurityDescriptor = &sdSecurityDescriptor;
  106. saSecurityAttributes.bInheritHandle = FALSE;
  107. if (!ConstructSecurityAttributes(&saSecurityAttributes, esatFile, FALSE)) {
  108. bRetStatus = FALSE;
  109. }
  110. else {
  111. //This will truncate the file as well as open it.
  112. hErrLog = CreateFile(pErrLogName,
  113. GENERIC_READ|GENERIC_WRITE,
  114. FILE_SHARE_READ|FILE_SHARE_WRITE,
  115. &saSecurityAttributes,
  116. CREATE_ALWAYS,
  117. FILE_ATTRIBUTE_NORMAL,
  118. NULL);
  119. CleanupSecurityAttributes(&saSecurityAttributes);
  120. ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  121. if (INVALID_HANDLE_VALUE == hErrLog) {
  122. // On failure, indicate it in return status
  123. bRetStatus = FALSE;
  124. }
  125. else {
  126. if(!WriteFile(hErrLog, pBuffer, dwRead, &dwWritten, NULL)){
  127. bRetStatus = FALSE;
  128. }
  129. }
  130. }
  131. }
  132. if (hBuffer) {
  133. GlobalUnlock(hBuffer);
  134. GlobalFree(hBuffer);
  135. }
  136. }
  137. if (bRetStatus) {
  138. // On success, close file, save a global copy of the filename, and set flag to indicate the Error Log is enabled
  139. CloseHandle(hErrLog);
  140. lstrcpy(cErrLogName, pErrLogName);
  141. lstrcpy(cLoggerIdentifier, pLoggerIdentifier);
  142. bErrLogEnabled = TRUE;
  143. }
  144. return bRetStatus;
  145. }
  146. /**************************************************************************************************
  147. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  148. ROUTINE DESCRIPTION:
  149. Write the error to the error file. Since this routine may be called from different
  150. processes, a Mutex is used to synchronize write access to the log file. Also, the file is
  151. Opened and Closed for each write. This is done so that each write gets the correct offset
  152. to the end of the file to append the new message data.
  153. GLOBAL VARIABLES:
  154. hErrLogMutex : Mutex to sychronize write access to the Error Log.
  155. cErrLogName : Where the name of the error log is stored.
  156. bErrLogEnabled : Boolean to indicate whether the error log has been initialized.
  157. INPUT:
  158. IN LPTSTR szMessage - message string.
  159. IN HRESULT hr - [Optional] error number. (-1 indicates No valid hr to format)
  160. IN LPTSTR szParameter1 - [Optional] Parameter String, NULL if not present
  161. RETURN:
  162. None.
  163. */
  164. void
  165. WriteErrorToErrorLog(
  166. IN LPTSTR pMessage,
  167. IN HRESULT hr,
  168. IN LPTSTR pParameter1
  169. )
  170. {
  171. //If the error log isn't enabled, don't write to it.
  172. if (!bErrLogEnabled) {
  173. return;
  174. }
  175. static TCHAR szError[128];
  176. static TCHAR szTemp[32];
  177. static BOOL bFirstError = TRUE;
  178. HANDLE hErrLog=NULL; // Handle to the Error Log.
  179. OVERLAPPED LogOverLap;
  180. DWORD dwMsgLength;
  181. DWORD dwNumBytesWritten;
  182. SECURITY_ATTRIBUTES saSecurityAttributes;
  183. SECURITY_DESCRIPTOR sdSecurityDescriptor;
  184. ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  185. //If this is the first time this routine was called, then put in a message identifying that a new logger is present.
  186. if(bFirstError){
  187. bFirstError = FALSE;
  188. WriteErrorToErrorLog(TEXT("INITIALIZE A NEW LOGGER---------------------------------------------------------------------------------"),
  189. -1,
  190. cLoggerIdentifier);
  191. }
  192. saSecurityAttributes.nLength = sizeof (saSecurityAttributes);
  193. saSecurityAttributes.lpSecurityDescriptor = &sdSecurityDescriptor;
  194. saSecurityAttributes.bInheritHandle = FALSE;
  195. if (!ConstructSecurityAttributes(&saSecurityAttributes, esatFile, FALSE)) {
  196. return;
  197. }
  198. // Before writing the entry to the log file, we have to
  199. // 1 Get Mutex to synchronize writing to the Log file
  200. // 2 Create/Open the FR Log file
  201. // If euther fail, then just return without writing to the log file.
  202. if ( (WaitForSingleObject(hErrLogMutex, 30000) != WAIT_FAILED) &&
  203. ((hErrLog = CreateFile(cErrLogName,
  204. GENERIC_READ|GENERIC_WRITE,
  205. FILE_SHARE_READ|FILE_SHARE_WRITE,
  206. &saSecurityAttributes,
  207. OPEN_ALWAYS,
  208. FILE_ATTRIBUTE_NORMAL,
  209. NULL)) != INVALID_HANDLE_VALUE) ) {
  210. // On success, set up the overlay option so we known the offset to
  211. // the end of the file, so when we write, we append to the end of the file.
  212. LogOverLap.Offset = GetFileSize(hErrLog, &LogOverLap.OffsetHigh);
  213. LogOverLap.hEvent = NULL;
  214. // Get the current date
  215. GetDateFormat(LOCALE_SYSTEM_DEFAULT,
  216. DATE_SHORTDATE,
  217. NULL,
  218. NULL,
  219. szError,
  220. sizeof(szError)/sizeof(TCHAR));
  221. // Get the current local time
  222. GetTimeFormat(LOCALE_SYSTEM_DEFAULT,
  223. TIME_FORCE24HOURFORMAT,
  224. NULL,
  225. TEXT(" HH':'mm':'ss"),
  226. szTemp,
  227. sizeof(szTemp)/sizeof(TCHAR));
  228. // 1) Write out 1st part of message = Date stamp, Time stamp & Thread Id
  229. //
  230. // Format message
  231. wcsncat(szError, szTemp, (sizeof(szError)/sizeof(WCHAR) - lstrlen(szError) - 1));
  232. szError[sizeof(szError)/sizeof(WCHAR) - 1] = TEXT('\0');
  233. wsprintf(szTemp, TEXT(" Thread# = %04lx\r\n Message :"), GetCurrentThreadId());
  234. wcsncat(szError, szTemp, (sizeof(szError)/sizeof(WCHAR) - lstrlen(szError) - 1));
  235. szError[sizeof(szError)/sizeof(WCHAR) - 1] = TEXT('\0');
  236. dwMsgLength = lstrlen(szError) * sizeof(TCHAR);
  237. //
  238. // Write data out to file
  239. WriteFile(hErrLog, szError, dwMsgLength, &dwNumBytesWritten, &LogOverLap);
  240. //
  241. // Update the offset to end of file
  242. LogOverLap.Offset += dwMsgLength;
  243. if (pMessage) {
  244. // 2) Write out next part of message = the Message String
  245. dwMsgLength = lstrlen(pMessage) * sizeof(TCHAR);
  246. WriteFile(hErrLog, pMessage, dwMsgLength, &dwNumBytesWritten, &LogOverLap);
  247. LogOverLap.Offset += dwMsgLength;
  248. }
  249. // If a valid error status 'hr' was passed in, then format a message out of it
  250. // A valid status is any number other than -1
  251. if (hr != -1) {
  252. if (HRESULT_FACILITY(hr) == FACILITY_WINDOWS) {
  253. hr = HRESULT_CODE(hr);
  254. }
  255. if((dwMsgLength = FormatMessage(/*FORMAT_MESSAGE_ALLOCATE_BUFFER | */FORMAT_MESSAGE_FROM_SYSTEM,
  256. NULL,
  257. hr,
  258. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //The user default language
  259. (LPTSTR)&szError,
  260. sizeof(szError)/sizeof(TCHAR),
  261. NULL)) == 0) {
  262. GetLastError();
  263. CleanupSecurityAttributes(&saSecurityAttributes);
  264. return;
  265. }
  266. // Remove the line feed at the end of the error string.
  267. szError[dwMsgLength - 2] = 0;
  268. //Append the error number.
  269. wsprintf(szTemp, TEXT("%d"), hr);
  270. lstrcat(szError, TEXT(" - Error #"));
  271. lstrcat(szError, szTemp);
  272. }
  273. else {
  274. // A valid error status was not passed in, so set error message to a Null message
  275. szError[0] = NULL;
  276. }
  277. // 3) Write out next part of message = the Status String
  278. wcscpy(szTemp, TEXT("\r\n Status : "));
  279. dwMsgLength = lstrlen(szTemp) * sizeof(TCHAR);
  280. WriteFile(hErrLog, szTemp, dwMsgLength, &dwNumBytesWritten, &LogOverLap);
  281. LogOverLap.Offset += dwMsgLength;
  282. dwMsgLength = lstrlen(szError) * sizeof(TCHAR);
  283. WriteFile(hErrLog, szError, dwMsgLength, &dwNumBytesWritten, &LogOverLap);
  284. LogOverLap.Offset += dwMsgLength;
  285. // 4) Write out next part of message = the Parameter String
  286. if(pParameter1 != NULL) {
  287. wcscpy(szTemp, TEXT("\r\n Parameter : "));
  288. dwMsgLength = lstrlen(szTemp) * sizeof(TCHAR);
  289. WriteFile(hErrLog, szTemp, dwMsgLength, &dwNumBytesWritten, &LogOverLap);
  290. LogOverLap.Offset += dwMsgLength;
  291. dwMsgLength = lstrlen(pParameter1) * sizeof(TCHAR);
  292. WriteFile(hErrLog, pParameter1, dwMsgLength, &dwNumBytesWritten, &LogOverLap);
  293. LogOverLap.Offset += dwMsgLength;
  294. }
  295. wcscpy(szTemp, TEXT("\r\n"));
  296. dwMsgLength = lstrlen(szTemp) * sizeof(TCHAR);
  297. WriteFile(hErrLog, szTemp, dwMsgLength, &dwNumBytesWritten, &LogOverLap);
  298. LogOverLap.Offset += dwMsgLength;
  299. // Close the handle to the file & release the log file mutex
  300. CloseHandle(hErrLog);
  301. ReleaseMutex(hErrLogMutex);
  302. }
  303. CleanupSecurityAttributes(&saSecurityAttributes);
  304. ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  305. }
  306. /**************************************************************************************************
  307. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  308. ROUTINE DESCRIPTION:
  309. This routine is called to disable the Error Log.
  310. GLOBALS:
  311. bErrLogEnabled : Boolean to indicate whether the error log has been initialized.
  312. INPUT:
  313. None
  314. RETURN:
  315. None
  316. */
  317. void
  318. ExitErrorLog (
  319. )
  320. {
  321. bErrLogEnabled = FALSE;
  322. if(hErrLogMutex){
  323. CloseHandle(hErrLogMutex);
  324. }
  325. return;
  326. }