1 /*
2  * PROJECT:     ReactOS Services
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        base/applications/mscutils/servman/control.c
5  * PURPOSE:     Pauses and resumes a service
6  * COPYRIGHT:   Copyright 2006-2015 Ged Murphy <gedmurphy@reactos.org>
7  *
8  */
9 
10 #include "precomp.h"
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 #define MAX_WAIT_TIME   30000
16 
17 DWORD
18 DoControlService(LPWSTR ServiceName,
19                  HWND hProgress,
20                  DWORD Control)
21 {
22     SC_HANDLE hSCManager;
23     SC_HANDLE hService;
24     SERVICE_STATUS_PROCESS ServiceStatus = {0};
25     SERVICE_STATUS Status;
26     DWORD BytesNeeded = 0;
27     DWORD StartTickCount;
28     DWORD OldCheckPoint;
29     DWORD WaitTime;
30     DWORD MaxWait;
31     DWORD ReqState, i;
32     BOOL Result;
33     DWORD dwResult = ERROR_SUCCESS;
34 
35     /* Set the state we're interested in */
36     switch (Control)
37     {
38         case SERVICE_CONTROL_PAUSE:
39             ReqState = SERVICE_PAUSED;
40             break;
41         case SERVICE_CONTROL_CONTINUE:
42             ReqState = SERVICE_RUNNING;
43             break;
44         default:
45             /* Unhandled control code */
46             DPRINT1("Unknown control command: 0x%X\n", Control);
47             return ERROR_INVALID_SERVICE_CONTROL;
48     }
49 
50     hSCManager = OpenSCManagerW(NULL,
51                                 NULL,
52                                 SC_MANAGER_CONNECT);
53     if (!hSCManager) return GetLastError();
54 
55     hService = OpenServiceW(hSCManager,
56                             ServiceName,
57                             SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_QUERY_STATUS);
58     if (!hService)
59     {
60         dwResult = GetLastError();
61         CloseServiceHandle(hSCManager);
62         return dwResult;
63     }
64 
65         /* Send the control message to the service */
66     Result = ControlService(hService,
67                             Control,
68                             &Status);
69     if (Result)
70     {
71         if (hProgress)
72         {
73             /* Increment the progress bar */
74             IncrementProgressBar(hProgress, DEFAULT_STEP);
75         }
76 
77         /* Get the service status */
78         Result = QueryServiceStatusEx(hService,
79                                       SC_STATUS_PROCESS_INFO,
80                                       (LPBYTE)&ServiceStatus,
81                                       sizeof(SERVICE_STATUS_PROCESS),
82                                       &BytesNeeded);
83         if (Result)
84         {
85             Result = FALSE;
86             MaxWait = MAX_WAIT_TIME;
87             OldCheckPoint = ServiceStatus.dwCheckPoint;
88             StartTickCount = GetTickCount();
89 
90             /* Loop until it's at the correct state */
91             while (ServiceStatus.dwCurrentState != ReqState)
92             {
93                 /* Fixup the wait time */
94                 WaitTime = ServiceStatus.dwWaitHint / 10;
95 
96                 if (WaitTime < 1000) WaitTime = 1000;
97                 else if (WaitTime > 10000) WaitTime = 10000;
98 
99                 /* We don't wanna wait for up to 10 secs without incrementing */
100                 for (i = WaitTime / 1000; i > 0; i--)
101                 {
102                     Sleep(1000);
103                     if (hProgress)
104                     {
105                         /* Increment the progress bar */
106                         IncrementProgressBar(hProgress, DEFAULT_STEP);
107                     }
108                 }
109 
110                 /* Get the latest status info */
111                 if (!QueryServiceStatusEx(hService,
112                                             SC_STATUS_PROCESS_INFO,
113                                             (LPBYTE)&ServiceStatus,
114                                             sizeof(SERVICE_STATUS_PROCESS),
115                                             &BytesNeeded))
116                 {
117                     /* Something went wrong... */
118                     dwResult = GetLastError();
119                     DPRINT1("QueryServiceStatusEx failed: %d\n", dwResult);
120                     break;
121                 }
122 
123                 /* Is the service making progress? */
124                 if (ServiceStatus.dwCheckPoint > OldCheckPoint)
125                 {
126                     /* It is, get the latest tickcount to reset the max wait time */
127                     StartTickCount = GetTickCount();
128                     OldCheckPoint = ServiceStatus.dwCheckPoint;
129                     IncrementProgressBar(hProgress, DEFAULT_STEP);
130                 }
131                 else
132                 {
133                     /* It's not, make sure we haven't exceeded our wait time */
134                     if (GetTickCount() >= StartTickCount + MaxWait)
135                     {
136                         /* We have, give up */
137                         DPRINT1("Timeout\n");
138                         dwResult = ERROR_SERVICE_REQUEST_TIMEOUT;
139                         break;
140                     }
141                 }
142             }
143         }
144         else
145         {
146             dwResult = GetLastError();
147         }
148 
149         if (ServiceStatus.dwCurrentState == ReqState)
150         {
151             dwResult = ERROR_SUCCESS;
152         }
153     }
154     else
155     {
156         dwResult = GetLastError();
157     }
158 
159     CloseServiceHandle(hService);
160     CloseServiceHandle(hSCManager);
161 
162     return dwResult;
163 }
164