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