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.

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