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.

395 lines
10 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. splstat.c
  5. Abstract:
  6. Routines for managing access to the status information and reporting:
  7. SpoolerStatusInit
  8. SpoolerBeginForcedShutdown
  9. SpoolerStatusUpdate
  10. GetSpoolerState
  11. Author:
  12. Krishna Ganugapati (KrishnaG) 17-Oct-1993
  13. Environment:
  14. User Mode -Win32
  15. Notes:
  16. Revision History:
  17. 17-Oct-1993 KrishnaG
  18. created
  19. --*/
  20. #include "precomp.h"
  21. #include "server.h"
  22. #include "splsvr.h"
  23. // Static Data
  24. //
  25. static DWORD Next;
  26. static DWORD InstallState;
  27. static SERVICE_STATUS SpoolerStatus;
  28. static DWORD HintCount;
  29. static DWORD SpoolerUninstallCode; // reason for uninstalling
  30. VOID
  31. SpoolerStatusInit(VOID)
  32. /*++
  33. Routine Description:
  34. Initializes the status database.
  35. Arguments:
  36. none.
  37. Return Value:
  38. none.
  39. Note:
  40. --*/
  41. {
  42. EnterCriticalSection(&ThreadCriticalSection);
  43. SpoolerState=STARTING;
  44. HintCount = 1;
  45. SpoolerUninstallCode = 0;
  46. SpoolerStatus.dwServiceType = SERVICE_WIN32;
  47. SpoolerStatus.dwCurrentState = SERVICE_START_PENDING;
  48. SpoolerStatus.dwControlsAccepted = 0;
  49. SpoolerStatus.dwCheckPoint = HintCount;
  50. SpoolerStatus.dwWaitHint = 20000; // 20 seconds
  51. SpoolerStatus.dwWin32ExitCode = NO_ERROR;
  52. SpoolerStatus.dwServiceSpecificExitCode = NO_ERROR;
  53. LeaveCriticalSection(&ThreadCriticalSection);
  54. return;
  55. }
  56. DWORD
  57. SpoolerBeginForcedShutdown(
  58. IN BOOL PendingCode,
  59. IN DWORD Win32ExitCode,
  60. IN DWORD ServiceSpecificExitCode
  61. )
  62. /*++
  63. Routine Description:
  64. This function is called to set the appropriate status when a shutdown
  65. is to occur due to an error in the Spooler. NOTE: if a shutdown is
  66. based on a request from the Service Controller, SpoolerStatusUpdate is
  67. called instead.
  68. Arguments:
  69. PendingCode - Indicates if the Shutdown is immediate or pending. If
  70. PENDING, the shutdown will take some time, so a pending status is
  71. sent to the ServiceController.
  72. ExitCode - Indicates the reason for the shutdown.
  73. Return Value:
  74. CurrentState - Contains the current state that the spooler is in
  75. upon exit from this routine. In this case it will be STOPPED
  76. if the PendingCode is PENDING, or STOPPING if the PendingCode
  77. is IMMEDIATE.
  78. Note:
  79. We need to clean this code up!
  80. --*/
  81. {
  82. DWORD status;
  83. EnterCriticalSection(&ThreadCriticalSection);
  84. //
  85. // See if the Spooler is already stopping for some reason.
  86. // It could be that the ControlHandler thread received a control to
  87. // stop the Spooler just as we decided to stop ourselves.
  88. //
  89. if ((SpoolerState != STOPPING) && (SpoolerState != STOPPED)) {
  90. if (PendingCode == PENDING) {
  91. SpoolerStatus.dwCurrentState = SERVICE_STOP_PENDING;
  92. SpoolerState = STOPPING;
  93. }
  94. else {
  95. //
  96. // The shutdown is to take immediate effect.
  97. //
  98. SpoolerStatus.dwCurrentState = SERVICE_STOPPED;
  99. SpoolerStatus.dwControlsAccepted = 0;
  100. SpoolerStatus.dwCheckPoint = 0;
  101. SpoolerStatus.dwWaitHint = 0;
  102. SpoolerState = STOPPED;
  103. }
  104. SpoolerUninstallCode = Win32ExitCode;
  105. SpoolerStatus.dwWin32ExitCode = Win32ExitCode;
  106. SpoolerStatus.dwServiceSpecificExitCode = ServiceSpecificExitCode;
  107. }
  108. //
  109. // Send the new status to the service controller.
  110. //
  111. if (!SpoolerStatusHandle) {
  112. DBGMSG(DBG_ERROR,
  113. ("SpoolerBeginForcedShutdown, no handle to call SetServiceStatus\n"));
  114. }
  115. else if (! SetServiceStatus( SpoolerStatusHandle, &SpoolerStatus )) {
  116. status = GetLastError();
  117. if (status != NERR_Success) {
  118. DBGMSG(ERROR,
  119. ("SpoolerBeginForcedShutdown,SetServiceStatus Failed %X\n",
  120. status));
  121. }
  122. }
  123. status = SpoolerState;
  124. LeaveCriticalSection(&ThreadCriticalSection);
  125. return(status);
  126. }
  127. DWORD
  128. SpoolerStatusUpdate(
  129. IN DWORD NewState
  130. )
  131. /*++
  132. Routine Description:
  133. Sends a status to the Service Controller via SetServiceStatus.
  134. The contents of the status message is controlled by this routine.
  135. The caller simply passes in the desired state, and this routine does
  136. the rest. For instance, if the Spooler passes in a STARTING state,
  137. This routine will update the hint count that it maintains, and send
  138. the appropriate information in the SetServiceStatus call.
  139. This routine uses transitions in state to send determine which status
  140. to send. For instance if the status was STARTING, and has changed
  141. to RUNNING, this routine sends out an INSTALLED to the Service
  142. Controller.
  143. Arguments:
  144. NewState - Can be any of the state flags:
  145. UPDATE_ONLY - Simply send out the current status
  146. STARTING - The Spooler is in the process of initializing
  147. RUNNING - The Spooler has finished with initialization
  148. STOPPING - The Spooler is in the process of shutting down
  149. STOPPED - The Spooler has completed the shutdown.
  150. Return Value:
  151. CurrentState - This may not be the same as the NewState that was
  152. passed in. It could be that the main thread is sending in a new
  153. install state just after the Control Handler set the state to
  154. STOPPING. In this case, the STOPPING state will be returned so as
  155. to inform the main thread that a shut-down is in process.
  156. Note:
  157. --*/
  158. {
  159. DWORD status;
  160. BOOL inhibit = FALSE; // Used to inhibit sending the status
  161. // to the service controller.
  162. EnterCriticalSection(&ThreadCriticalSection);
  163. if (NewState == STOPPED) {
  164. if (SpoolerState == STOPPED) {
  165. //
  166. // It was already stopped, don't send another SetServiceStatus.
  167. //
  168. inhibit = TRUE;
  169. }
  170. else {
  171. //
  172. // The shut down is complete, indicate that the spooler
  173. // has stopped.
  174. //
  175. SpoolerStatus.dwCurrentState = SERVICE_STOPPED;
  176. SpoolerStatus.dwControlsAccepted = 0;
  177. SpoolerStatus.dwCheckPoint = 0;
  178. SpoolerStatus.dwWaitHint = 0;
  179. SpoolerStatus.dwWin32ExitCode = NO_ERROR;
  180. SpoolerStatus.dwServiceSpecificExitCode = NO_ERROR;
  181. }
  182. SpoolerState = NewState;
  183. }
  184. else {
  185. //
  186. // We are not being asked to change to the STOPPED state.
  187. //
  188. switch(SpoolerState) {
  189. case STARTING:
  190. if (NewState == STOPPING) {
  191. SpoolerStatus.dwCurrentState = SERVICE_STOP_PENDING;
  192. SpoolerStatus.dwControlsAccepted = 0;
  193. SpoolerStatus.dwCheckPoint = HintCount++;
  194. SpoolerStatus.dwWaitHint = 20000; // 20 seconds
  195. SpoolerState = NewState;
  196. }
  197. else if (NewState == RUNNING) {
  198. //
  199. // The Spooler Service has completed installation.
  200. //
  201. SpoolerStatus.dwCurrentState = SERVICE_RUNNING;
  202. //
  203. // The Spooler Service cannot be stopped once started
  204. //
  205. SpoolerStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  206. SERVICE_ACCEPT_SHUTDOWN |
  207. SERVICE_ACCEPT_POWEREVENT;
  208. SpoolerStatus.dwCheckPoint = 0;
  209. SpoolerStatus.dwWaitHint = 0;
  210. SpoolerState = NewState;
  211. }
  212. else {
  213. //
  214. // The NewState must be STARTING. So update the pending
  215. // count
  216. //
  217. SpoolerStatus.dwCurrentState = SERVICE_START_PENDING;
  218. SpoolerStatus.dwControlsAccepted = 0;
  219. SpoolerStatus.dwCheckPoint = HintCount++;
  220. SpoolerStatus.dwWaitHint = 20000; // 20 seconds
  221. }
  222. break;
  223. case RUNNING:
  224. if (NewState == STOPPING) {
  225. SpoolerStatus.dwCurrentState = SERVICE_STOP_PENDING;
  226. SpoolerStatus.dwControlsAccepted = 0;
  227. SpoolerStatus.dwCheckPoint = HintCount++;
  228. SpoolerStatus.dwWaitHint = 20000; // 20 seconds
  229. SpoolerState = NewState;
  230. }
  231. break;
  232. case STOPPING:
  233. //
  234. // No matter what else was passed in, force the status to
  235. // indicate that a shutdown is pending.
  236. //
  237. SpoolerStatus.dwCurrentState = SERVICE_STOPPED;
  238. SpoolerStatus.dwControlsAccepted = 0;
  239. SpoolerStatus.dwCheckPoint = 0;
  240. SpoolerStatus.dwWaitHint = 0; // 20 seconds
  241. break;
  242. case STOPPED:
  243. //
  244. // We're already stopped. Therefore, an uninstalled status
  245. // as already been sent. Do nothing.
  246. //
  247. inhibit = TRUE;
  248. break;
  249. }
  250. }
  251. if (!inhibit) {
  252. if (!SpoolerStatusHandle) {
  253. DBGMSG(DBG_ERROR,("SpoolerStatusUpdate, no handle to call SetServiceStatus\n"));
  254. }
  255. else if (! SetServiceStatus( SpoolerStatusHandle, &SpoolerStatus )) {
  256. status = GetLastError();
  257. if (status != NERR_Success) {
  258. DBGMSG(DBG_WARN, ("SpoolerStatusUpdate, SetServiceStatus Failed %d\n",status));
  259. }
  260. }
  261. }
  262. status = SpoolerState;
  263. LeaveCriticalSection(&ThreadCriticalSection);
  264. return(status);
  265. }
  266. DWORD
  267. GetSpoolerState (
  268. VOID
  269. )
  270. /*++
  271. Routine Description:
  272. Obtains the state of the Spooler Service. This state information
  273. is protected as a critical section such that only one thread can
  274. modify or read it at a time.
  275. Arguments:
  276. none
  277. Return Value:
  278. The Spooler State is returned as the return value.
  279. --*/
  280. {
  281. DWORD status;
  282. EnterCriticalSection(&ThreadCriticalSection);
  283. status = SpoolerState;
  284. LeaveCriticalSection(&ThreadCriticalSection);
  285. return(status);
  286. }