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.

596 lines
15 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. CONTROL.C
  5. Abstract:
  6. This file contains the control handler for the eventlog service.
  7. Author:
  8. Rajen Shah (rajens) 16-Jul-1991
  9. Revision History:
  10. --*/
  11. //
  12. // INCLUDES
  13. //
  14. #include <eventp.h>
  15. #include <msaudite.h>
  16. //
  17. // DEFINITIONS
  18. //
  19. //
  20. // Controls accepted by the service
  21. //
  22. #define ELF_CONTROLS_ACCEPTED SERVICE_ACCEPT_SHUTDOWN;
  23. //
  24. // GLOBALS
  25. //
  26. CRITICAL_SECTION StatusCriticalSection = {0};
  27. SERVICE_STATUS ElStatus = {0};
  28. DWORD HintCount = 0;
  29. DWORD ElUninstallCode = 0; // reason for uninstalling
  30. DWORD ElSpecificCode = 0;
  31. DWORD ElState = STARTING;
  32. //
  33. // Generate Event with Noon Event Inforamtion.
  34. //
  35. VOID
  36. ElfWriteNoonEvent(
  37. TIMESTAMPEVENT EventType,
  38. ULONG ulTimeStampInterval
  39. );
  40. VOID
  41. ElfControlResponse(
  42. DWORD opCode
  43. )
  44. {
  45. DWORD state;
  46. ELF_LOG1(TRACE,
  47. "ElfControlResponse: Received control %d\n",
  48. opCode);
  49. //
  50. // Determine the type of service control message and modify the
  51. // service status, if necessary.
  52. //
  53. switch(opCode)
  54. {
  55. case SERVICE_CONTROL_SHUTDOWN:
  56. {
  57. HKEY hKey;
  58. ULONG ValueSize;
  59. ULONG ShutdownReason = 0xFF;
  60. ULONG rc;
  61. //
  62. // If the service is installed, shut it down and exit.
  63. //
  64. ElfStatusUpdate(STOPPING);
  65. GetGlobalResource (ELF_GLOBAL_EXCLUSIVE);
  66. //
  67. // Cause the timestamp writing thread to exit
  68. //
  69. if (g_hTimestampEvent != NULL)
  70. {
  71. SetEvent (g_hTimestampEvent);
  72. }
  73. //
  74. // Indicate a normal shutdown in the registry
  75. //
  76. ElfWriteTimeStamp(EVENT_NormalShutdown,
  77. FALSE);
  78. #if 0
  79. //
  80. // Determine the reason for this normal shutdown
  81. //
  82. rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  83. REGSTR_PATH_RELIABILITY,
  84. 0,
  85. NULL,
  86. REG_OPTION_NON_VOLATILE,
  87. KEY_ALL_ACCESS,
  88. NULL,
  89. &hKey,
  90. NULL);
  91. if (rc == ERROR_SUCCESS)
  92. {
  93. ValueSize = sizeof(ULONG);
  94. rc = RegQueryValueEx(hKey,
  95. REGSTR_VAL_SHUTDOWNREASON,
  96. 0,
  97. NULL,
  98. (PUCHAR) &ShutdownReason,
  99. &ValueSize);
  100. if (rc == ERROR_SUCCESS)
  101. {
  102. RegDeleteValue (hKey, REGSTR_VAL_SHUTDOWNREASON);
  103. }
  104. RegCloseKey (hKey);
  105. }
  106. #endif
  107. //
  108. // Log an event that says we're stopping
  109. //
  110. ElfWriteNoonEvent(EVENT_EventlogStopped,
  111. GetNoonEventTimeStamp());
  112. #if 0
  113. ElfpCreateElfEvent(EVENT_EventlogStopped,
  114. EVENTLOG_INFORMATION_TYPE,
  115. 0, // EventCategory
  116. 0, // NumberOfStrings
  117. NULL, // Strings
  118. &ShutdownReason, // Data
  119. sizeof(ULONG), // Datalength
  120. 0, // flags
  121. FALSE); // for security file
  122. #endif
  123. ElfpCreateElfEvent(SE_AUDITID_SYSTEM_SHUTDOWN,
  124. EVENTLOG_AUDIT_SUCCESS,
  125. SE_CATEGID_SYSTEM, // EventCategory
  126. 0, // NumberOfStrings
  127. NULL, // Strings
  128. NULL, // Data
  129. 0, // Datalength
  130. 0, // flags
  131. TRUE); // for security file
  132. //
  133. // Now force it to be written before we shut down
  134. //
  135. WriteQueuedEvents();
  136. ReleaseGlobalResource();
  137. //
  138. // If the RegistryMonitor is started, wakeup that
  139. // worker thread and have it handle the rest of the
  140. // shutdown.
  141. //
  142. // Otherwise The main thread should pick up the
  143. // fact that a shutdown during startup is occuring.
  144. //
  145. if (EventFlags & ELF_STARTED_REGISTRY_MONITOR)
  146. {
  147. StopRegistryMonitor();
  148. }
  149. break ;
  150. }
  151. case SERVICE_CONTROL_INTERROGATE:
  152. ElfStatusUpdate(UPDATE_ONLY);
  153. break;
  154. default:
  155. //
  156. // This should never happen.
  157. //
  158. ELF_LOG1(ERROR,
  159. "ElfControlResponse: Received unexpected control %d\n",
  160. opCode);
  161. ASSERT(FALSE);
  162. break ;
  163. }
  164. return;
  165. }
  166. DWORD
  167. ElfBeginForcedShutdown(
  168. IN BOOL PendingCode,
  169. IN DWORD ExitCode,
  170. IN DWORD ServiceSpecificCode
  171. )
  172. /*++
  173. Routine Description:
  174. Arguments:
  175. Return Value:
  176. --*/
  177. {
  178. DWORD status;
  179. EnterCriticalSection(&StatusCriticalSection);
  180. ELF_LOG2(ERROR,
  181. "ElfBeginForcedShutdown: error %d, service-specific error %d\n",
  182. ExitCode,
  183. ServiceSpecificCode);
  184. //
  185. // See if the eventlog is already stopping for some reason.
  186. // It could be that the ControlHandler thread received a control to
  187. // stop the eventlog just as we decided to stop ourselves.
  188. //
  189. if ((ElState != STOPPING) && (ElState != STOPPED))
  190. {
  191. if (PendingCode == PENDING)
  192. {
  193. ELF_LOG0(TRACE,
  194. "ElfBeginForcedShutdown: Starting pending shutdown\n");
  195. ElStatus.dwCurrentState = SERVICE_STOP_PENDING;
  196. ElState = STOPPING;
  197. }
  198. else
  199. {
  200. //
  201. // The shutdown is to take immediate effect.
  202. //
  203. ELF_LOG0(TRACE,
  204. "ElfBeginForcedShutdown: Starting immediate shutdown\n");
  205. ElStatus.dwCurrentState = SERVICE_STOPPED;
  206. ElStatus.dwControlsAccepted = 0;
  207. ElStatus.dwCheckPoint = 0;
  208. ElStatus.dwWaitHint = 0;
  209. ElState = STOPPED;
  210. }
  211. ElUninstallCode = ExitCode;
  212. ElSpecificCode = ServiceSpecificCode;
  213. ElStatus.dwWin32ExitCode = ExitCode;
  214. ElStatus.dwServiceSpecificExitCode = ServiceSpecificCode;
  215. }
  216. //
  217. // Cause the timestamp writing thread to exit
  218. //
  219. if (g_hTimestampEvent != NULL)
  220. {
  221. SetEvent (g_hTimestampEvent);
  222. }
  223. //
  224. // Send the new status to the service controller.
  225. //
  226. ASSERT(ElfServiceStatusHandle != 0);
  227. if (!SetServiceStatus( ElfServiceStatusHandle, &ElStatus ))
  228. {
  229. ELF_LOG1(ERROR,
  230. "ElfBeginForcedShutdown: SetServicestatus failed %d\n",
  231. GetLastError());
  232. }
  233. status = ElState;
  234. ELF_LOG1(TRACE,
  235. "ElfBeginForcedShutdown: New state is %d\n",
  236. status);
  237. LeaveCriticalSection(&StatusCriticalSection);
  238. return status;
  239. }
  240. DWORD
  241. ElfStatusUpdate(
  242. IN DWORD NewState
  243. )
  244. /*++
  245. Routine Description:
  246. Sends a status to the Service Controller via SetServiceStatus.
  247. The contents of the status message is controlled by this routine.
  248. The caller simply passes in the desired state, and this routine does
  249. the rest. For instance, if the Eventlog passes in a STARTING state,
  250. This routine will update the hint count that it maintains, and send
  251. the appropriate information in the SetServiceStatus call.
  252. This routine uses transitions in state to determine which status
  253. to send. For instance if the status was STARTING, and has changed
  254. to RUNNING, this routine sends SERVICE_RUNNING to the Service
  255. Controller.
  256. Arguments:
  257. NewState - Can be any of the state flags:
  258. UPDATE_ONLY - Simply send out the current status
  259. STARTING - The Eventlog is in the process of initializing
  260. RUNNING - The Eventlog has finished with initialization
  261. STOPPING - The Eventlog is in the process of shutting down
  262. STOPPED - The Eventlog has completed the shutdown.
  263. Return Value:
  264. CurrentState - This may not be the same as the NewState that was
  265. passed in. It could be that the main thread is sending in a new
  266. install state just after the Control Handler set the state to
  267. STOPPING. In this case, the STOPPING state will be returned so as
  268. to inform the main thread that a shut-down is in process.
  269. --*/
  270. {
  271. DWORD status;
  272. BOOL inhibit = FALSE; // Used to inhibit sending the status
  273. // to the service controller.
  274. EnterCriticalSection(&StatusCriticalSection);
  275. ELF_LOG2(TRACE,
  276. "ElfStatusUpdate: old state = %d, new state = %d\n",
  277. ElState,
  278. NewState);
  279. if (NewState == STOPPED)
  280. {
  281. if (ElState == STOPPED)
  282. {
  283. //
  284. // It was already stopped, don't send another SetServiceStatus.
  285. //
  286. inhibit = TRUE;
  287. }
  288. else
  289. {
  290. //
  291. // The shut down is complete, indicate that the eventlog
  292. // has stopped.
  293. //
  294. ElStatus.dwCurrentState = SERVICE_STOPPED;
  295. ElStatus.dwControlsAccepted = 0;
  296. ElStatus.dwCheckPoint = 0;
  297. ElStatus.dwWaitHint = 0;
  298. ElStatus.dwWin32ExitCode = ElUninstallCode;
  299. ElStatus.dwServiceSpecificExitCode = ElSpecificCode;
  300. }
  301. ElState = NewState;
  302. }
  303. else if (NewState != UPDATE_ONLY)
  304. {
  305. //
  306. // We are not being asked to change to the STOPPED state.
  307. //
  308. switch(ElState)
  309. {
  310. case STARTING:
  311. if (NewState == STOPPING)
  312. {
  313. ElStatus.dwCurrentState = SERVICE_STOP_PENDING;
  314. ElStatus.dwControlsAccepted = 0;
  315. ElStatus.dwCheckPoint = HintCount++;
  316. ElStatus.dwWaitHint = ELF_WAIT_HINT_TIME;
  317. ElState = NewState;
  318. EventlogShutdown = TRUE;
  319. }
  320. else if (NewState == RUNNING)
  321. {
  322. //
  323. // The Eventlog Service has completed installation.
  324. //
  325. ElStatus.dwCurrentState = SERVICE_RUNNING;
  326. ElStatus.dwCheckPoint = 0;
  327. ElStatus.dwWaitHint = 0;
  328. ElStatus.dwControlsAccepted = ELF_CONTROLS_ACCEPTED;
  329. ElState = NewState;
  330. }
  331. else
  332. {
  333. //
  334. // The NewState must be STARTING. So update the pending
  335. // count
  336. //
  337. ElStatus.dwCurrentState = SERVICE_START_PENDING;
  338. ElStatus.dwControlsAccepted = 0;
  339. ElStatus.dwCheckPoint = HintCount++;
  340. ElStatus.dwWaitHint = ELF_WAIT_HINT_TIME;
  341. }
  342. break;
  343. case RUNNING:
  344. if (NewState == STOPPING)
  345. {
  346. ElStatus.dwCurrentState = SERVICE_STOP_PENDING;
  347. ElStatus.dwControlsAccepted = 0;
  348. EventlogShutdown = TRUE;
  349. }
  350. ElStatus.dwCheckPoint = HintCount++;
  351. ElStatus.dwWaitHint = ELF_WAIT_HINT_TIME;
  352. ElState = NewState;
  353. break;
  354. case STOPPING:
  355. //
  356. // No matter what else was passed in, force the status to
  357. // indicate that a shutdown is pending.
  358. //
  359. ElStatus.dwCurrentState = SERVICE_STOP_PENDING;
  360. ElStatus.dwControlsAccepted = 0;
  361. ElStatus.dwCheckPoint = HintCount++;
  362. ElStatus.dwWaitHint = ELF_WAIT_HINT_TIME;
  363. EventlogShutdown = TRUE;
  364. break;
  365. case STOPPED:
  366. ASSERT(NewState == STARTING);
  367. //
  368. // The Eventlog Service is starting up after being stopped.
  369. // This can occur if the service is manually started after
  370. // failing to start.
  371. //
  372. ElStatus.dwCurrentState = SERVICE_START_PENDING;
  373. ElStatus.dwCheckPoint = 0;
  374. ElStatus.dwWaitHint = 0;
  375. ElStatus.dwControlsAccepted = ELF_CONTROLS_ACCEPTED;
  376. ElState = NewState;
  377. break;
  378. }
  379. }
  380. if (!inhibit)
  381. {
  382. ASSERT(ElfServiceStatusHandle != 0);
  383. if (!SetServiceStatus(ElfServiceStatusHandle, &ElStatus))
  384. {
  385. ELF_LOG1(ERROR,
  386. "ElfStatusUpdate: SetServiceStatus failed %d\n",
  387. GetLastError());
  388. }
  389. }
  390. status = ElState;
  391. ELF_LOG1(TRACE,
  392. "ElfStatusUpdate: Exiting with state = %d\n",
  393. ElState);
  394. LeaveCriticalSection(&StatusCriticalSection);
  395. return status;
  396. }
  397. DWORD
  398. GetElState (
  399. VOID
  400. )
  401. /*++
  402. Routine Description:
  403. Obtains the state of the Eventlog Service. This state information
  404. is protected as a critical section such that only one thread can
  405. modify or read it at a time.
  406. Arguments:
  407. none
  408. Return Value:
  409. The Eventlog State is returned as the return value.
  410. --*/
  411. {
  412. DWORD status;
  413. EnterCriticalSection(&StatusCriticalSection);
  414. status = ElState;
  415. LeaveCriticalSection(&StatusCriticalSection);
  416. return status;
  417. }
  418. NTSTATUS
  419. ElfpInitStatus(
  420. VOID
  421. )
  422. /*++
  423. Routine Description:
  424. Initializes the critical section that is used to guard access to the
  425. status database.
  426. Arguments:
  427. none
  428. Return Value:
  429. none
  430. --*/
  431. {
  432. ElStatus.dwCurrentState = SERVICE_START_PENDING;
  433. ElStatus.dwServiceType = SERVICE_WIN32;
  434. return ElfpInitCriticalSection(&StatusCriticalSection);
  435. }
  436. VOID
  437. ElCleanupStatus(VOID)
  438. /*++
  439. Routine Description:
  440. Deletes the critical section used to control access to the thread and
  441. status database.
  442. Arguments:
  443. none
  444. Return Value:
  445. none
  446. Note:
  447. --*/
  448. {
  449. DeleteCriticalSection(&StatusCriticalSection);
  450. }