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