Leaked source code of windows server 2003
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.

408 lines
11 KiB

  1. /*++
  2. Copyright (c) 1990-1999 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. wmi.c
  6. Abstract:
  7. Holds the internal operations for wmi instrumenation
  8. Author:
  9. Stuart de Jong (sdejong) 15-Oct-99
  10. Environment:
  11. User Mode -Win32
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. //
  16. // WMI files
  17. //
  18. #include <wmistr.h>
  19. #include <evntrace.h>
  20. #include "wmi.h"
  21. #include "wmidata.h"
  22. // End WMI
  23. //
  24. // How it works:
  25. //
  26. // There are similar guids defined in the sdktools tracecounter programs, and also
  27. // descriptions there of the information we send them. This is used by them to print out
  28. // and format the data we send.
  29. //
  30. // When we start up we register ourselves with WMI and provide a callback into our control
  31. // code. This allows an external tool to call the start trace code in WMI with our guid, which
  32. // then has WMI call us, and start tracing.
  33. //
  34. // Stopping a trace is also done through the callback. the data is then analyzed by the WMI tools
  35. // and output in human readable form, or it could be further analyzed from there.
  36. //
  37. MODULE_DEBUG_INIT ( DBG_ERROR, DBG_ERROR );
  38. // These Guid's correspond to the definitions in \nt\sdktools\trace\tracedmp\mofdata.guid
  39. //
  40. // Identifies the PrintJob data logged by the delete job event.
  41. //
  42. GUID WmiPrintJobGuid = { /* 127eb555-3b06-46ea-a08b-5dc2c3c57cfd */
  43. 0x127eb555, 0x3b06, 0x46ea, 0xa0, 0x8b, 0x5d, 0xc2, 0xc3, 0xc5, 0x7c, 0xfd
  44. };
  45. //
  46. // Identifies the RenderedJob data logged by the job rendered event.
  47. //
  48. GUID WmiRenderedJobGuid = { /* 1d32b239-92a6-485a-96d2-dc3659fb803e */
  49. 0x1d32b239, 0x92a6, 0x485a, 0x96, 0xd2, 0xdc, 0x36, 0x59, 0xfb, 0x80, 0x3e
  50. };
  51. //
  52. // Used by the control app. to find the callback that turns spooler tracing on
  53. // and off.
  54. //
  55. GUID WmiSpoolerControlGuid = { /* 94a984ef-f525-4bf1-be3c-ef374056a592 */
  56. 0x94a984ef, 0xf525, 0x4bf1, 0xbe, 0x3c, 0xef, 0x37, 0x40, 0x56, 0xa5, 0x92 };
  57. #define szWmiResourceName TEXT("Spooler")
  58. TRACE_GUID_REGISTRATION WmiTraceGuidReg[] =
  59. {
  60. { (LPGUID)&WmiPrintJobGuid,
  61. NULL
  62. },
  63. { (LPGUID)&WmiRenderedJobGuid,
  64. NULL
  65. }
  66. };
  67. //
  68. // The mof fields point to the following data.
  69. // DWORD JobId; // Unique ID for the transaction of printing a job
  70. // WMI_SPOOL_DATA Data; // See splcom.h
  71. //
  72. typedef struct _WMI_SPOOL_EVENT {
  73. EVENT_TRACE_HEADER Header;
  74. MOF_FIELD MofData[2];
  75. } WMI_SPOOL_EVENT, *PWMI_SPOOL_EVENT;
  76. static TRACEHANDLE WmiRegistrationHandle;
  77. static TRACEHANDLE WmiLoggerHandle;
  78. static LONG ulWmiEnableLevel = 0;
  79. static HANDLE hWmiRegisterThread = NULL;
  80. static DWORD dwWmiRegisterThreadId = 0;
  81. static ULONG bWmiTraceOnFlag = FALSE;
  82. static ULONG bWmiIsInitialized = FALSE;
  83. ULONG
  84. WmiControlCallback(
  85. IN WMIDPREQUESTCODE RequestCode,
  86. IN PVOID Context,
  87. IN OUT ULONG *InOutBufferSize,
  88. IN OUT PVOID Buffer
  89. );
  90. /*++
  91. Routine Name:
  92. WmiRegisterTrace()
  93. Routine Description:
  94. Thread routine that registers us with the WMI tools
  95. Arguments:
  96. LPVOID Arg : Not used.
  97. --*/
  98. DWORD
  99. WmiRegisterTrace(
  100. IN LPVOID arg
  101. )
  102. {
  103. ULONG Status = ERROR_SUCCESS;
  104. WCHAR szImagePath[MAX_PATH];
  105. Status = GetModuleFileName(NULL, szImagePath, COUNTOF(szImagePath));
  106. if (Status == 0) {
  107. Status = ERROR_FILE_NOT_FOUND;
  108. }
  109. else {
  110. Status = RegisterTraceGuids(
  111. WmiControlCallback,
  112. NULL,
  113. (LPGUID)&WmiSpoolerControlGuid,
  114. 1,
  115. WmiTraceGuidReg,
  116. szImagePath,
  117. szWmiResourceName,
  118. &WmiRegistrationHandle);
  119. if (Status == ERROR_SUCCESS) {
  120. DBGMSG(DBG_TRACE, ("WmiInitializeTrace: SPOOLER WMI INITIALIZED.\n"));
  121. InterlockedExchange(&bWmiIsInitialized, TRUE);
  122. }
  123. else {
  124. DBGMSG(DBG_TRACE, ("WmiInitializeTrace: SPOOLER WMI INITIALIZE FAILED: %u.\n",
  125. Status));
  126. }
  127. }
  128. return Status;
  129. }
  130. /*++
  131. Routine Name:
  132. WmiInitializeTrace()
  133. Routine Description:
  134. Initialises the Trace structures and registers the callback with WMI.
  135. This creates a thread and calls WmiRegisterTrace, since the registering may take
  136. a long time (up to minutes)
  137. Arguments:
  138. Returns ERROR_SUCCESS if it succeeds or ERROR_ALREADY_EXISTS otherwise
  139. --*/
  140. ULONG
  141. WmiInitializeTrace(VOID)
  142. {
  143. ULONG Status = ERROR_ALREADY_EXISTS;
  144. if (!hWmiRegisterThread)
  145. {
  146. InterlockedExchange(&bWmiIsInitialized, FALSE);
  147. //
  148. // Registering can block for a long time (I've seen minutes
  149. // occationally), so it must be done in its own thread.
  150. //
  151. if (hWmiRegisterThread = CreateThread(NULL,
  152. 0,
  153. (LPTHREAD_START_ROUTINE)WmiRegisterTrace,
  154. 0,
  155. 0,
  156. &dwWmiRegisterThreadId))
  157. {
  158. CloseHandle(hWmiRegisterThread);
  159. Status = ERROR_SUCCESS;
  160. }
  161. else
  162. {
  163. Status = GetLastError();
  164. }
  165. }
  166. return Status;
  167. }
  168. /*++
  169. Routine Name:
  170. WmiTerminateTrace()
  171. Routine Description:
  172. Deregisters us from the WMI tools
  173. Arguments:
  174. Returns ERROR_SUCCESS on success. a Winerror otherwise.
  175. --*/
  176. ULONG
  177. WmiTerminateTrace(VOID)
  178. {
  179. ULONG Status = ERROR_SUCCESS;
  180. DWORD dwExitCode;
  181. if (bWmiIsInitialized) {
  182. InterlockedExchange(&bWmiIsInitialized, FALSE);
  183. Status = UnregisterTraceGuids(WmiRegistrationHandle);
  184. if (Status == ERROR_SUCCESS) {
  185. DBGMSG(DBG_TRACE, ("WmiTerminateTrace: SPOOLER WMI UNREGISTERED.\n"));
  186. }
  187. else {
  188. DBGMSG(DBG_TRACE, ("WmiTerminateTrace: SPOOLER WMI UNREGISTER FAILED.\n"));
  189. }
  190. }
  191. return Status;
  192. }
  193. /*++
  194. Routine Name:
  195. SplWmiTraceEvent()
  196. Routine Description:
  197. If tracing is turned on, this sends the event to the WMI subsystem.
  198. Arguments:
  199. DWORD JobId : the JobID this is related to.
  200. UCHAR EventTraceType : The type of event that happened
  201. PWMI_SPOOL_DATA Data : The Event Data, could be NULL
  202. Returns ERROR_SUCCESS if it doesn't need to do anything, or if it succeeds.
  203. --*/
  204. ULONG
  205. LogWmiTraceEvent(
  206. IN DWORD JobId,
  207. IN UCHAR EventTraceType,
  208. IN PWMI_SPOOL_DATA Data OPTIONAL
  209. )
  210. {
  211. WMI_SPOOL_EVENT WmiSpoolEvent;
  212. ULONG Status;
  213. if (!bWmiTraceOnFlag)
  214. return ERROR_SUCCESS;
  215. //
  216. // Level 1 tracing just traces response time of individual jobs with job data.
  217. // Default level is 0.
  218. //
  219. if (ulWmiEnableLevel == 1) {
  220. switch (EventTraceType) {
  221. //
  222. // Save overhead by not tracking resource usage.
  223. //
  224. case EVENT_TRACE_TYPE_SPL_TRACKTHREAD:
  225. case EVENT_TRACE_TYPE_SPL_ENDTRACKTHREAD:
  226. return ERROR_SUCCESS;
  227. default:
  228. //
  229. // Job data.
  230. //
  231. break;
  232. }
  233. }
  234. //
  235. // Record data.
  236. //
  237. RtlZeroMemory(&WmiSpoolEvent, sizeof(WmiSpoolEvent));
  238. WmiSpoolEvent.Header.Size = sizeof(WMI_SPOOL_EVENT);
  239. WmiSpoolEvent.Header.Flags = (WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR);
  240. WmiSpoolEvent.Header.Class.Type = EventTraceType;
  241. WmiSpoolEvent.Header.Guid = WmiPrintJobGuid;
  242. WmiSpoolEvent.MofData[0].DataPtr = (ULONG64)&JobId;
  243. WmiSpoolEvent.MofData[0].Length = sizeof(DWORD);
  244. WmiSpoolEvent.MofData[1].DataPtr = (ULONG64)Data;
  245. if (Data) {
  246. switch (EventTraceType) {
  247. case EVENT_TRACE_TYPE_SPL_DELETEJOB:
  248. WmiSpoolEvent.MofData[1].Length = sizeof(struct _WMI_JOBDATA);
  249. break;
  250. case EVENT_TRACE_TYPE_SPL_JOBRENDERED:
  251. WmiSpoolEvent.Header.Guid = WmiRenderedJobGuid;
  252. WmiSpoolEvent.MofData[1].Length = sizeof(struct _WMI_EMFDATA);
  253. break;
  254. default:
  255. DBGMSG(DBG_TRACE, ("SplWmiTraceEvent: FAILED to log WMI Trace Event Unexpected Data JobId:%u Type:%u\n",
  256. JobId, (ULONG) EventTraceType));
  257. return ERROR_INVALID_DATA;
  258. }
  259. }
  260. Status = TraceEvent(
  261. WmiLoggerHandle,
  262. (PEVENT_TRACE_HEADER) &WmiSpoolEvent);
  263. //
  264. // logger buffers out of memory should not prevent provider from
  265. // generating events. This will only cause events lost.
  266. //
  267. if (Status == ERROR_NOT_ENOUGH_MEMORY) {
  268. DBGMSG(DBG_TRACE, ("SplWmiTraceEvent: FAILED to log WMI Trace Event No Memory JobId:%u Type:%u\n",
  269. JobId, (ULONG) EventTraceType));
  270. }
  271. else if (Status != ERROR_SUCCESS) {
  272. DBGMSG(DBG_TRACE, ("SplWmiTraceEvent: FAILED to log WMI Trace Event JobId:%u Type:%u Status:%u\n",
  273. JobId, (ULONG) EventTraceType, Status));
  274. }
  275. return Status;
  276. }
  277. /*++
  278. Routine Name:
  279. SplWmiControlCallback()
  280. Routine Description:
  281. This is the function we provite to the WMI subsystem as a callback, it is used to
  282. start and stop the trace events.
  283. Arguments:
  284. IN WMIDPREQUESTCODE RequestCode : The function to provide (enable/disable)
  285. IN PVOID Context : Not used by us.
  286. IN OUT ULONG *InOutBufferSize : The Buffersize
  287. IN OUT PVOID Buffer : The buffer to use for the events
  288. Returns ERROR_SUCCESS on success, or an error code.
  289. --*/
  290. ULONG
  291. WmiControlCallback(
  292. IN WMIDPREQUESTCODE RequestCode,
  293. IN PVOID Context,
  294. IN OUT ULONG *InOutBufferSize,
  295. IN OUT PVOID Buffer
  296. )
  297. {
  298. ULONG Status;
  299. if (!bWmiIsInitialized) {
  300. DBGMSG(DBG_TRACE, ("SplWmiControlCallback: SPOOLER WMI NOT INITIALIZED.\n"));
  301. return ERROR_GEN_FAILURE;
  302. }
  303. Status = ERROR_SUCCESS;
  304. switch (RequestCode)
  305. {
  306. case WMI_ENABLE_EVENTS:
  307. {
  308. WmiLoggerHandle = GetTraceLoggerHandle( Buffer );
  309. ulWmiEnableLevel = GetTraceEnableLevel( WmiLoggerHandle );
  310. InterlockedExchange(&bWmiTraceOnFlag, TRUE);
  311. DBGMSG(DBG_TRACE, ("SplWmiControlCallback: SPOOLER WMI ENABLED LEVEL %u.\n",
  312. ulWmiEnableLevel));
  313. break;
  314. }
  315. case WMI_DISABLE_EVENTS:
  316. {
  317. DBGMSG(DBG_TRACE, ("SplWmiControlCallback: SPOOLER WMI DISABLED.\n"));
  318. InterlockedExchange(&bWmiTraceOnFlag, FALSE);
  319. WmiLoggerHandle = 0;
  320. break;
  321. }
  322. default:
  323. {
  324. Status = ERROR_INVALID_PARAMETER;
  325. break;
  326. }
  327. }
  328. *InOutBufferSize = 0;
  329. return(Status);
  330. }