456c0a26b1b4eda5eafbf8052254198caf9aaea6
[reactos.git] / reactos / subsys / system / sc / query.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS SC utility
4 * FILE: subsys/system/sc/query.c
5 * PURPOSE: control ReactOS services
6 * PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com)
7 * REVISIONS:
8 * Ged Murphy 20/10/05 Created
9 *
10 */
11 /*
12 * TODO:
13 * Allow calling of 2 options e.g.:
14 * type= driver state= inactive
15 */
16
17 #include "sc.h"
18
19 #define DEBUG
20 #include <debug.h>
21
22 /* local function decs */
23 VOID PrintService(BOOL bExtended);
24 BOOL EnumServices(DWORD ServiceType, DWORD ServiceState);
25 BOOL QueryService(LPCTSTR ServiceName, BOOL bExtended);
26
27 /* global variables */
28 static ENUM_SERVICE_STATUS_PROCESS *pServiceStatus = NULL;
29 DWORD NumServices = 0;
30
31
32 BOOL
33 Query(LPCTSTR ServiceName, LPCTSTR *ServiceArgs, BOOL bExtended)
34 {
35 if (! ServiceName) /* display all running services and drivers */
36 {
37 /* get default values */
38 EnumServices(SERVICE_WIN32, SERVICE_ACTIVE);
39
40 /* print default values */
41 PrintService(bExtended);
42 }
43 else if (_tcsicmp(ServiceName, _T("type=")) == 0)
44 {
45 LPCTSTR Type = *ServiceArgs;
46
47 if (_tcsicmp(Type, _T("driver")) == 0)
48 EnumServices(SERVICE_DRIVER, SERVICE_ACTIVE);
49 else if (_tcsicmp(Type, _T("service")) == 0)
50 EnumServices(SERVICE_WIN32, SERVICE_ACTIVE);
51 else if (_tcsicmp(Type, _T("all")) == 0)
52 EnumServices(SERVICE_DRIVER|SERVICE_WIN32, SERVICE_ACTIVE);
53 else
54 {
55 _tprintf(_T("\nERROR following \"type=\"!\n"));
56 _tprintf(_T("Must be \"driver\" or \"service\" or \"all\"\n"));
57 }
58
59 PrintService(bExtended);
60 }
61 else if(_tcsicmp(ServiceName, _T("state=")) == 0)
62 {
63 LPCTSTR State = *ServiceArgs;
64
65 if (_tcsicmp(State, _T("inactive")) == 0)
66 EnumServices(SERVICE_WIN32, SERVICE_INACTIVE);
67 else if (_tcsicmp(State, _T("all")) == 0)
68 EnumServices(SERVICE_WIN32, SERVICE_STATE_ALL);
69 else
70 {
71 _tprintf(_T("\nERROR following \"state=\"!\n"));
72 _tprintf(_T("Must be \"active\" or \"inactive\" or \"all\"\n"));
73 }
74
75 PrintService(bExtended);
76 }
77 /*
78 else if(_tcsicmp(ServiceName, _T("bufsize=")))
79
80 else if(_tcsicmp(ServiceName, _T("ri=")))
81
82 else if(_tcsicmp(ServiceName, _T("group=")))
83 */
84 else /* print only the service requested */
85 {
86 QueryService(ServiceName, bExtended);
87 }
88
89 return TRUE;
90 }
91
92
93 BOOL
94 QueryService(LPCTSTR ServiceName, BOOL bExtended)
95 {
96 SERVICE_STATUS_PROCESS *pServiceInfo = NULL;
97 SC_HANDLE hSc;
98 DWORD BufSiz = 0;
99 DWORD BytesNeeded = 0;
100 DWORD Ret;
101
102 hSc = OpenService(hSCManager, ServiceName, SERVICE_QUERY_STATUS);
103
104 if (hSc == NULL)
105 {
106 _tprintf(_T("QueryService: openService failed\n"));
107 ReportLastError();
108 return FALSE;
109 }
110
111 Ret = QueryServiceStatusEx(hSc,
112 SC_STATUS_PROCESS_INFO,
113 NULL,
114 BufSiz,
115 &BytesNeeded);
116
117 if ((Ret != 0) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
118 {
119 _tprintf(_T("QueryService: First call to QueryServiceStatusEx failed : "));
120 ReportLastError();
121 return FALSE;
122 }
123 else /* Call function again if required size was returned */
124 {
125 /* reserve memory for service info array */
126 pServiceInfo = (SERVICE_STATUS_PROCESS *)
127 HeapAlloc(GetProcessHeap(), 0, BytesNeeded);
128 if (pServiceInfo == NULL)
129 {
130 _tprintf(_T("QueryService: Failed to allocate memory : "));
131 ReportLastError();
132 return FALSE;
133 }
134
135 /* fill array with service info */
136 if (! QueryServiceStatusEx(hSc,
137 SC_STATUS_PROCESS_INFO,
138 (LPBYTE)pServiceInfo,
139 BytesNeeded,
140 &BytesNeeded))
141 {
142 _tprintf(_T("QueryService: Second call to QueryServiceStatusEx failed : "));
143 ReportLastError();
144 HeapFree(GetProcessHeap(), 0, pServiceInfo);
145 return FALSE;
146 }
147 }
148
149
150 _tprintf(_T("SERVICE_NAME: %s\n"), ServiceName);
151
152 _tprintf(_T("\tTYPE : %x "),
153 (unsigned int)pServiceInfo->dwServiceType);
154 switch (pServiceInfo->dwServiceType)
155 {
156 case 1 : _tprintf(_T("KERNEL_DRIVER\n")); break;
157 case 2 : _tprintf(_T("FILE_SYSTEM_DRIVER\n")); break;
158 case 16 : _tprintf(_T("WIN32_OWN_PROCESS\n")); break;
159 case 32 : _tprintf(_T("WIN32_SHARE_PROCESS\n")); break;
160 default : _tprintf(_T("\n")); break;
161 }
162
163 _tprintf(_T("\tSTATE : %x "),
164 (unsigned int)pServiceInfo->dwCurrentState);
165
166 switch (pServiceInfo->dwCurrentState)
167 {
168 case 1 : _tprintf(_T("STOPPED\n")); break;
169 case 2 : _tprintf(_T("START_PENDING\n")); break;
170 case 3 : _tprintf(_T("STOP_PENDING\n")); break;
171 case 4 : _tprintf(_T("RUNNING\n")); break;
172 case 5 : _tprintf(_T("CONTINUE_PENDING\n")); break;
173 case 6 : _tprintf(_T("PAUSE_PENDING\n")); break;
174 case 7 : _tprintf(_T("PAUSED\n")); break;
175 default : _tprintf(_T("\n")); break;
176 }
177
178 // _tprintf(_T("\n\taccepted : 0x%x\n\n"),
179 // pServiceStatus[i].ServiceStatusProcess.dwControlsAccepted);
180 // (STOPPABLE,NOT_PAUSABLE,ACCEPTS_SHUTDOWN)
181
182 _tprintf(_T("\tWIN32_EXIT_CODE : %d (0x%x)\n"),
183 (unsigned int)pServiceInfo->dwWin32ExitCode,
184 (unsigned int)pServiceInfo->dwWin32ExitCode);
185 _tprintf(_T("\tSERVICE_EXIT_CODE : %d (0x%x)\n"),
186 (unsigned int)pServiceInfo->dwServiceSpecificExitCode,
187 (unsigned int)pServiceInfo->dwServiceSpecificExitCode);
188 _tprintf(_T("\tCHECKPOINT : 0x%x\n"),
189 (unsigned int)pServiceInfo->dwCheckPoint);
190 _tprintf(_T("\tWAIT_HINT : 0x%x\n"),
191 (unsigned int)pServiceInfo->dwWaitHint);
192 if (bExtended)
193 {
194 _tprintf(_T("\tPID : %lu\n"),
195 pServiceInfo->dwProcessId);
196 _tprintf(_T("\tFLAGS : %lu\n"),
197 pServiceInfo->dwServiceFlags);
198 }
199
200 HeapFree(GetProcessHeap(), 0, pServiceInfo);
201
202 return TRUE;
203 }
204
205
206 BOOL
207 EnumServices(DWORD ServiceType, DWORD ServiceState)
208 {
209 DWORD BufSize = 0;
210 DWORD BytesNeeded = 0;
211 DWORD ResumeHandle = 0;
212 DWORD Ret;
213
214 /* determine required buffer size */
215 Ret = EnumServicesStatusEx(hSCManager,
216 SC_ENUM_PROCESS_INFO,
217 ServiceType,
218 ServiceState,
219 (LPBYTE)pServiceStatus,
220 BufSize,
221 &BytesNeeded,
222 &NumServices,
223 &ResumeHandle,
224 0);
225
226 if ((Ret != 0) && (GetLastError() != ERROR_MORE_DATA))
227 {
228 _tprintf(_T("EnumServices: First call to EnumServicesStatusEx failed : "));
229 ReportLastError();
230 return FALSE;
231 }
232 else /* Call function again if required size was returned */
233 {
234 /* reserve memory for service info array */
235 pServiceStatus = (ENUM_SERVICE_STATUS_PROCESS *)
236 HeapAlloc(GetProcessHeap(), 0, BytesNeeded);
237 if (pServiceStatus == NULL)
238 {
239 _tprintf(_T("EnumServices: Failed to allocate memory : "));
240 ReportLastError();
241 return FALSE;
242 }
243
244 /* fill array with service info */
245 if (! EnumServicesStatusEx(hSCManager,
246 SC_ENUM_PROCESS_INFO,
247 ServiceType,
248 ServiceState,
249 (LPBYTE)pServiceStatus,
250 BytesNeeded,
251 &BytesNeeded,
252 &NumServices,
253 &ResumeHandle,
254 0))
255 {
256 _tprintf(_T("EnumServices: Second call to EnumServicesStatusEx failed : "));
257 ReportLastError();
258 HeapFree(GetProcessHeap(), 0, pServiceStatus);
259 return FALSE;
260 }
261 }
262
263 return TRUE;
264 }
265
266
267 VOID
268 PrintService(BOOL bExtended)
269 {
270 DWORD i;
271
272 for (i=0; i < NumServices; i++)
273 {
274
275 _tprintf(_T("SERVICE_NAME: %s\n"), pServiceStatus[i].lpServiceName);
276 _tprintf(_T("DISPLAY_NAME: %s\n"), pServiceStatus[i].lpDisplayName);
277
278 _tprintf(_T("\tTYPE : %x "),
279 (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwServiceType);
280 switch (pServiceStatus[i].ServiceStatusProcess.dwServiceType)
281 {
282 case 1 : _tprintf(_T("KERNEL_DRIVER\n")); break;
283 case 2 : _tprintf(_T("FILE_SYSTEM_DRIVER\n")); break;
284 case 16 : _tprintf(_T("WIN32_OWN_PROCESS\n")); break;
285 case 32 : _tprintf(_T("WIN32_SHARE_PROCESS\n")); break;
286 default : _tprintf(_T("\n")); break;
287 }
288
289 _tprintf(_T("\tSTATE : %x "),
290 (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwCurrentState);
291
292 switch (pServiceStatus[i].ServiceStatusProcess.dwCurrentState)
293 {
294 case 1 : _tprintf(_T("STOPPED\n")); break;
295 case 2 : _tprintf(_T("START_PENDING\n")); break;
296 case 3 : _tprintf(_T("STOP_PENDING\n")); break;
297 case 4 : _tprintf(_T("RUNNING\n")); break;
298 case 5 : _tprintf(_T("CONTINUE_PENDING\n")); break;
299 case 6 : _tprintf(_T("PAUSE_PENDING\n")); break;
300 case 7 : _tprintf(_T("PAUSED\n")); break;
301 default : _tprintf(_T("\n")); break;
302 }
303
304 // _tprintf(_T("\n\taccepted : 0x%x\n\n"),
305 // pServiceStatus[i].ServiceStatusProcess.dwControlsAccepted);
306 // (STOPPABLE,NOT_PAUSABLE,ACCEPTS_SHUTDOWN)
307
308 _tprintf(_T("\tWIN32_EXIT_CODE : %d (0x%x)\n"),
309 (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwWin32ExitCode,
310 (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwWin32ExitCode);
311 _tprintf(_T("\tSERVICE_EXIT_CODE : %d (0x%x)\n"),
312 (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwServiceSpecificExitCode,
313 (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwServiceSpecificExitCode);
314 _tprintf(_T("\tCHECKPOINT : 0x%x\n"),
315 (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwCheckPoint);
316 _tprintf(_T("\tWAIT_HINT : 0x%x\n"),
317 (unsigned int)pServiceStatus[i].ServiceStatusProcess.dwWaitHint);
318 if (bExtended)
319 {
320 _tprintf(_T("\tPID : %lu\n"),
321 pServiceStatus[i].ServiceStatusProcess.dwProcessId);
322 _tprintf(_T("\tFLAGS : %lu\n"),
323 pServiceStatus[i].ServiceStatusProcess.dwServiceFlags);
324 }
325
326 _tprintf(_T("\n"));
327 }
328
329 _tprintf(_T("number : %lu\n"), NumServices);
330 }