xref: /reactos/base/applications/sc/query.c (revision b893124a)
1 /*
2  * PROJECT:     ReactOS Services
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        base/applications/sc/query.c
5  * PURPOSE:     queries service info
6  * COPYRIGHT:   Copyright 2005 - 2006 Ged Murphy <gedmurphy@gmail.com>
7  *              Copyright 2018 Eric Kohl <eric.kohl@reactos.org>
8  */
9 
10 #include "sc.h"
11 
12 LPSERVICE_STATUS_PROCESS
13 QueryService(LPCTSTR ServiceName)
14 {
15     SC_HANDLE hSCManager = NULL;
16     LPSERVICE_STATUS_PROCESS pServiceInfo = NULL;
17     SC_HANDLE hSc = NULL;
18     DWORD BufSiz = 0;
19     DWORD BytesNeeded = 0;
20     DWORD Ret;
21 
22     hSCManager = OpenSCManager(NULL,
23                                NULL,
24                                SC_MANAGER_CONNECT);
25     if (hSCManager == NULL)
26     {
27         ReportLastError();
28         return NULL;
29     }
30 
31     hSc = OpenService(hSCManager,
32                       ServiceName,
33                       SERVICE_QUERY_STATUS);
34     if (hSc == NULL)
35         goto fail;
36 
37     Ret = QueryServiceStatusEx(hSc,
38                                SC_STATUS_PROCESS_INFO,
39                                NULL,
40                                BufSiz,
41                                &BytesNeeded);
42     if ((Ret != 0) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
43         goto fail;
44 
45     pServiceInfo = (LPSERVICE_STATUS_PROCESS)HeapAlloc(GetProcessHeap(),
46                                                        0,
47                                                        BytesNeeded);
48     if (pServiceInfo == NULL)
49         goto fail;
50 
51     if (!QueryServiceStatusEx(hSc,
52                               SC_STATUS_PROCESS_INFO,
53                               (LPBYTE)pServiceInfo,
54                               BytesNeeded,
55                               &BytesNeeded))
56     {
57         goto fail;
58     }
59 
60     CloseServiceHandle(hSc);
61     CloseServiceHandle(hSCManager);
62     return pServiceInfo;
63 
64 fail:
65     ReportLastError();
66     if (pServiceInfo) HeapFree(GetProcessHeap(), 0, pServiceInfo);
67     if (hSc) CloseServiceHandle(hSc);
68     if (hSCManager) CloseServiceHandle(hSCManager);
69     return NULL;
70 }
71 
72 
73 static
74 DWORD
75 EnumServices(ENUM_SERVICE_STATUS_PROCESS **pServiceStatus,
76              DWORD dwServiceType,
77              DWORD dwServiceState,
78              DWORD dwBufferSize,
79              DWORD dwResumeIndex,
80              LPCTSTR pszGroupName)
81 {
82     SC_HANDLE hSCManager;
83     DWORD BytesNeeded = 0;
84     DWORD ResumeHandle = dwResumeIndex;
85     DWORD NumServices = 0;
86     BOOL Ret;
87 
88     hSCManager = OpenSCManager(NULL,
89                                NULL,
90                                SC_MANAGER_ENUMERATE_SERVICE);
91     if (hSCManager == NULL)
92     {
93         ReportLastError();
94         return 0;
95     }
96 
97     if (dwBufferSize == 0)
98     {
99         Ret = EnumServicesStatusEx(hSCManager,
100                                    SC_ENUM_PROCESS_INFO,
101                                    dwServiceType,
102                                    dwServiceState,
103                                    (LPBYTE)*pServiceStatus,
104                                    dwBufferSize,
105                                    &BytesNeeded,
106                                    &NumServices,
107                                    &ResumeHandle,
108                                    pszGroupName);
109         if ((Ret == 0) && (GetLastError() != ERROR_MORE_DATA))
110         {
111             ReportLastError();
112             return 0;
113         }
114 
115         dwBufferSize = BytesNeeded;
116     }
117 
118     *pServiceStatus = (ENUM_SERVICE_STATUS_PROCESS *)
119                       HeapAlloc(GetProcessHeap(),
120                                 0,
121                                 dwBufferSize);
122     if (*pServiceStatus != NULL)
123     {
124         if (EnumServicesStatusEx(hSCManager,
125                                  SC_ENUM_PROCESS_INFO,
126                                  dwServiceType,
127                                  dwServiceState,
128                                  (LPBYTE)*pServiceStatus,
129                                  dwBufferSize,
130                                  &BytesNeeded,
131                                  &NumServices,
132                                  &ResumeHandle,
133                                  pszGroupName))
134         {
135             CloseServiceHandle(hSCManager);
136             return NumServices;
137         }
138     }
139 
140     ReportLastError();
141     if (*pServiceStatus)
142         HeapFree(GetProcessHeap(), 0, *pServiceStatus);
143 
144     CloseServiceHandle(hSCManager);
145 
146     return NumServices;
147 }
148 
149 
150 static
151 BOOL
152 ParseQueryArguments(
153     IN LPCTSTR *ServiceArgs,
154     IN INT ArgCount,
155     OUT PDWORD pdwServiceType,
156     OUT PDWORD pdwServiceState,
157     OUT PDWORD pdwBufferSize,
158     OUT PDWORD pdwResumeIndex,
159     OUT LPCTSTR *ppszGroupName,
160     OUT LPCTSTR *ppszServiceName)
161 {
162     INT TmpCount, TmpIndex;
163     DWORD dwValue;
164 
165     TmpCount = ArgCount;
166     TmpIndex = 0;
167     while (TmpCount > 0)
168     {
169         if (!lstrcmpi(ServiceArgs[TmpIndex], _T("type=")))
170         {
171             TmpIndex++;
172             TmpCount--;
173 
174             if (TmpCount > 0)
175             {
176                 if (!lstrcmpi(ServiceArgs[TmpIndex], _T("service")))
177                 {
178                     *pdwServiceType = SERVICE_WIN32;
179                 }
180                 else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("driver")))
181                 {
182                     *pdwServiceType = SERVICE_DRIVER;
183                 }
184                 else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("all")))
185                 {
186                     *pdwServiceType = SERVICE_TYPE_ALL;
187                 }
188                 else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("interact")))
189                 {
190                     *pdwServiceType |= SERVICE_INTERACTIVE_PROCESS;
191                 }
192                 else
193                 {
194                     _tprintf(_T("ERROR following \"type=\"!\nMust be one of: all, driver, interact, service.\n"));
195                     return FALSE;
196                 }
197 
198                 TmpIndex++;
199                 TmpCount--;
200             }
201         }
202         else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("state=")))
203         {
204             TmpIndex++;
205             TmpCount--;
206 
207             if (TmpCount > 0)
208             {
209                 if (!lstrcmpi(ServiceArgs[TmpIndex], _T("active")))
210                 {
211                     *pdwServiceState = SERVICE_ACTIVE;
212                 }
213                 else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("inactive")))
214                 {
215                     *pdwServiceState = SERVICE_INACTIVE;
216                 }
217                 else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("all")))
218                 {
219                     *pdwServiceState = SERVICE_STATE_ALL;
220                 }
221                 else
222                 {
223                     _tprintf(_T("ERROR following \"state=\"!\nMust be one of: active, all, inactive.\n"));
224                     return FALSE;
225                 }
226 
227                 TmpIndex++;
228                 TmpCount--;
229             }
230         }
231         else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("bufsize=")))
232         {
233             TmpIndex++;
234             TmpCount--;
235 
236             if (TmpCount > 0)
237             {
238                 dwValue = _tcstoul(ServiceArgs[TmpIndex], NULL, 10);
239                 if (dwValue > 0)
240                 {
241                     *pdwBufferSize = dwValue;
242                 }
243 
244                 TmpIndex++;
245                 TmpCount--;
246             }
247         }
248         else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("ri=")))
249         {
250             TmpIndex++;
251             TmpCount--;
252 
253             if (TmpCount >= 0)
254             {
255                 dwValue = _tcstoul(ServiceArgs[TmpIndex], NULL, 10);
256                 if (dwValue > 0)
257                 {
258                     *pdwResumeIndex = dwValue;
259                 }
260 
261                 TmpIndex++;
262                 TmpCount--;
263             }
264         }
265         else if (!lstrcmpi(ServiceArgs[TmpIndex], _T("group=")))
266         {
267             TmpIndex++;
268             TmpCount--;
269 
270             if (TmpCount > 0)
271             {
272                 *ppszGroupName = ServiceArgs[TmpIndex];
273 
274                 TmpIndex++;
275                 TmpCount--;
276             }
277         }
278         else
279         {
280             *ppszServiceName = ServiceArgs[TmpIndex];
281 
282             TmpIndex++;
283             TmpCount--;
284         }
285     }
286 
287     return TRUE;
288 }
289 
290 
291 BOOL
292 Query(LPCTSTR *ServiceArgs,
293       DWORD ArgCount,
294       BOOL bExtended)
295 {
296     LPENUM_SERVICE_STATUS_PROCESS pServiceStatus = NULL;
297     DWORD NumServices = 0;
298     DWORD dwServiceType = SERVICE_WIN32;
299     DWORD dwServiceState = SERVICE_ACTIVE;
300     DWORD dwBufferSize = 0;
301     DWORD dwResumeIndex = 0;
302     LPCTSTR pszGroupName = NULL;
303     LPCTSTR pszServiceName = NULL;
304     DWORD i;
305 
306 #ifdef SCDBG
307     LPCTSTR *TmpArgs = ServiceArgs;
308     INT TmpCnt = ArgCount;
309 
310     _tprintf(_T("Arguments:\n"));
311     while (TmpCnt)
312     {
313         _tprintf(_T("  %s\n"), *TmpArgs);
314         TmpArgs++;
315         TmpCnt--;
316     }
317     _tprintf(_T("\n"));
318 #endif /* SCDBG */
319 
320     /* Parse arguments */
321     if (!ParseQueryArguments(ServiceArgs,
322                              ArgCount,
323                              &dwServiceType,
324                              &dwServiceState,
325                              &dwBufferSize,
326                              &dwResumeIndex,
327                              &pszGroupName,
328                              &pszServiceName))
329         return FALSE;
330 
331 #ifdef SCDBG
332     _tprintf(_T("Service type: %lx\n"), dwServiceType);
333     _tprintf(_T("Service state: %lx\n"), dwServiceState);
334     _tprintf(_T("Buffer size: %lu\n"), dwBufferSize);
335     _tprintf(_T("Resume index: %lu\n"), dwResumeIndex);
336     _tprintf(_T("Group name: %s\n"), pszGroupName);
337     _tprintf(_T("Service name: %s\n"), pszServiceName);
338 #endif
339 
340     if (pszServiceName)
341     {
342         /* Print only the requested service */
343 
344         LPSERVICE_STATUS_PROCESS pStatus;
345 
346         pStatus = QueryService(pszServiceName);
347         if (pStatus)
348         {
349             PrintService(pszServiceName,
350                          NULL,
351                          pStatus,
352                          bExtended);
353 
354             HeapFree(GetProcessHeap(), 0, pStatus);
355         }
356     }
357     else
358     {
359         /* Print all matching services */
360 
361         NumServices = EnumServices(&pServiceStatus,
362                                    dwServiceType,
363                                    dwServiceState,
364                                    dwBufferSize,
365                                    dwResumeIndex,
366                                    pszGroupName);
367         if (NumServices == 0)
368             return FALSE;
369 
370         for (i = 0; i < NumServices; i++)
371         {
372             PrintService(pServiceStatus[i].lpServiceName,
373                          pServiceStatus[i].lpDisplayName,
374                          &pServiceStatus[i].ServiceStatusProcess,
375                          bExtended);
376         }
377 
378 #ifdef SCDBG
379         _tprintf(_T("number : %lu\n"), NumServices);
380 #endif
381 
382         if (pServiceStatus)
383             HeapFree(GetProcessHeap(), 0, pServiceStatus);
384     }
385 
386     return TRUE;
387 }
388