1 /*
2  * PROJECT:     ReactOS Services
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        base/applications/mscutils/servman/start.c
5  * PURPOSE:     Start a service
6  * COPYRIGHT:   Copyright 2005-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
DoStartService(LPWSTR ServiceName,HANDLE hProgress,LPWSTR lpStartParams)18 DoStartService(LPWSTR ServiceName,
19                HANDLE hProgress,
20                LPWSTR lpStartParams)
21 {
22     SC_HANDLE hSCManager;
23     SC_HANDLE hService;
24     SERVICE_STATUS_PROCESS ServiceStatus;
25     DWORD BytesNeeded = 0;
26     DWORD StartTickCount;
27     DWORD OldCheckPoint;
28     DWORD WaitTime;
29     DWORD MaxWait;
30     BOOL Result = FALSE;
31 
32     BOOL bWhiteSpace = TRUE;
33     LPWSTR lpChar;
34     DWORD dwArgsCount = 0;
35     DWORD dwResult = ERROR_SUCCESS;
36     LPCWSTR *lpArgsVector = NULL;
37 
38     if (lpStartParams != NULL)
39     {
40         /* Count the number of arguments */
41         lpChar = lpStartParams;
42         while (*lpChar != 0)
43         {
44             if (iswspace(*lpChar))
45             {
46                 bWhiteSpace = TRUE;
47             }
48             else
49             {
50                 if (bWhiteSpace != FALSE)
51                 {
52                     dwArgsCount++;
53                     bWhiteSpace = FALSE;
54                 }
55             }
56 
57             lpChar++;
58         }
59 
60         /*
61          * Allocate the arguments vector.
62          * Do not add the service name here because services.exe does it for us!
63          */
64         lpArgsVector = LocalAlloc(LMEM_FIXED, dwArgsCount * sizeof(LPCWSTR));
65         if (!lpArgsVector)
66             return GetLastError();
67 
68         /* Fill the arguments vector */
69         dwArgsCount = 0;
70         bWhiteSpace = TRUE;
71         lpChar = lpStartParams;
72         while (*lpChar != 0)
73         {
74             if (iswspace(*lpChar))
75             {
76                 *lpChar = 0;
77                 bWhiteSpace = TRUE;
78             }
79             else
80             {
81                 if (bWhiteSpace != FALSE)
82                 {
83                     lpArgsVector[dwArgsCount] = lpChar;
84                     dwArgsCount++;
85                     bWhiteSpace = FALSE;
86                 }
87             }
88 
89             lpChar++;
90         }
91     }
92 
93     hSCManager = OpenSCManagerW(NULL,
94                                 NULL,
95                                 SC_MANAGER_CONNECT);
96     if (!hSCManager)
97     {
98         dwResult = GetLastError();
99         if (lpArgsVector)
100             LocalFree((LPVOID)lpArgsVector);
101         return dwResult;
102     }
103 
104     hService = OpenServiceW(hSCManager,
105                             ServiceName,
106                             SERVICE_START | SERVICE_QUERY_STATUS);
107     if (!hService)
108     {
109         dwResult = GetLastError();
110         CloseServiceHandle(hSCManager);
111         if (lpArgsVector)
112             LocalFree((LPVOID)lpArgsVector);
113         return dwResult;
114     }
115 
116     /* Start the service */
117     Result = StartServiceW(hService,
118                             dwArgsCount,
119                             lpArgsVector);
120     if (!Result && GetLastError() == ERROR_SERVICE_ALREADY_RUNNING)
121     {
122         /* If it's already running, just return TRUE */
123         Result = TRUE;
124     }
125     else if (Result)
126     {
127         if (hProgress)
128         {
129             /* Increment the progress bar */
130             IncrementProgressBar(hProgress, DEFAULT_STEP);
131         }
132 
133         /* Get the service status to check if it's running */
134         Result = QueryServiceStatusEx(hService,
135                                         SC_STATUS_PROCESS_INFO,
136                                         (LPBYTE)&ServiceStatus,
137                                         sizeof(SERVICE_STATUS_PROCESS),
138                                         &BytesNeeded);
139         if (Result)
140         {
141             Result = FALSE;
142             MaxWait = MAX_WAIT_TIME;
143             OldCheckPoint = ServiceStatus.dwCheckPoint;
144             StartTickCount = GetTickCount();
145 
146             /* Loop until it's running */
147             while (ServiceStatus.dwCurrentState != SERVICE_RUNNING)
148             {
149                 int i;
150                 /* Fixup the wait time */
151                 WaitTime = ServiceStatus.dwWaitHint / 10;
152 
153                 if (WaitTime < 1000) WaitTime = 1000;
154                 else if (WaitTime > 10000) WaitTime = 10000;
155 
156                 /* We don't wanna wait for up to 10 secs without incrementing */
157                 for (i = WaitTime / 1000; i > 0; i--)
158                 {
159                     Sleep(1000);
160                     if (hProgress)
161                     {
162                         /* Increment the progress bar */
163                         IncrementProgressBar(hProgress, DEFAULT_STEP);
164                     }
165                 }
166 
167 
168                 /* Get the latest status info */
169                 if (!QueryServiceStatusEx(hService,
170                                             SC_STATUS_PROCESS_INFO,
171                                             (LPBYTE)&ServiceStatus,
172                                             sizeof(SERVICE_STATUS_PROCESS),
173                                             &BytesNeeded))
174                 {
175                     /* Something went wrong... */
176                     dwResult = GetLastError();
177                     DPRINT1("QueryServiceStatusEx failed: %d\n", dwResult);
178                     break;
179                 }
180 
181                 /* Is the service making progress? */
182                 if (ServiceStatus.dwCheckPoint > OldCheckPoint)
183                 {
184                     /* It is, get the latest tickcount to reset the max wait time */
185                     StartTickCount = GetTickCount();
186                     OldCheckPoint = ServiceStatus.dwCheckPoint;
187                 }
188                 else
189                 {
190                     /* It's not, make sure we haven't exceeded our wait time */
191                     if (GetTickCount() >= StartTickCount + MaxWait)
192                     {
193                         /* We have, give up */
194                         DPRINT1("Timeout\n");
195                         dwResult = ERROR_SERVICE_REQUEST_TIMEOUT;
196                         break;
197                     }
198                 }
199             }
200         }
201         else
202         {
203             dwResult = GetLastError();
204         }
205 
206         if (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
207         {
208             dwResult = ERROR_SUCCESS;
209         }
210     }
211 
212     CloseServiceHandle(hService);
213     CloseServiceHandle(hSCManager);
214 
215     if (lpArgsVector)
216         LocalFree((LPVOID)lpArgsVector);
217 
218     return dwResult;
219 }
220