winetest: Disable the crash dialog in non-interactive mode.
[wine.git] / programs / sc / sc.c
blobbd7e093b61d2f2c2e39bdc50bf8655a577b8e24a
1 /*
2 * Copyright 2010 Hans Leidekker
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define WIN32_LEAN_AND_MEAN
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <windows.h>
25 #include <winsvc.h>
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(sc);
30 static BOOL parse_string_param( int argc, const WCHAR *argv[], unsigned int *index,
31 const WCHAR *param_name, size_t name_len, const WCHAR **out )
33 if (!wcsnicmp( argv[*index], param_name, name_len ))
35 if (argv[*index][name_len])
37 *out = &argv[*index][name_len];
38 return TRUE;
40 else if (*index < argc - 1)
42 *index += 1;
43 *out = argv[*index];
44 return TRUE;
47 return FALSE;
50 struct create_params
52 const WCHAR *displayname;
53 const WCHAR *binpath;
54 const WCHAR *group;
55 const WCHAR *depend;
56 const WCHAR *obj;
57 const WCHAR *password;
58 DWORD type;
59 DWORD start;
60 DWORD error;
61 BOOL tag;
64 static BOOL parse_create_params( int argc, const WCHAR *argv[], struct create_params *cp )
66 unsigned int i;
68 cp->displayname = NULL;
69 cp->type = SERVICE_WIN32_OWN_PROCESS;
70 cp->start = SERVICE_DEMAND_START;
71 cp->error = SERVICE_ERROR_NORMAL;
72 cp->binpath = NULL;
73 cp->group = NULL;
74 cp->tag = FALSE;
75 cp->depend = NULL;
76 cp->obj = NULL;
77 cp->password = NULL;
79 #define PARSE(x, y) parse_string_param( (argc), (argv), &(i), (x), ARRAY_SIZE(x) - 1, (y) )
80 for (i = 0; i < argc; i++)
82 const WCHAR *tag, *type, *start, *error;
84 if (PARSE( L"displayname=", &cp->displayname )) continue;
85 if (PARSE( L"binpath=", &cp->binpath )) continue;
86 if (PARSE( L"group=", &cp->group )) continue;
87 if (PARSE( L"depend=", &cp->depend )) continue;
88 if (PARSE( L"obj=", &cp->obj )) continue;
89 if (PARSE( L"password=", &cp->password )) continue;
91 if (PARSE( L"tag=", &tag ))
93 if (!wcsicmp( tag, L"yes" ))
95 WINE_FIXME("tag argument not supported\n");
96 cp->tag = TRUE;
98 continue;
100 if (PARSE( L"type=", &type ))
102 if (!wcsicmp( type, L"own" )) cp->type = SERVICE_WIN32_OWN_PROCESS;
103 else if (!wcsicmp( type, L"share" )) cp->type = SERVICE_WIN32_SHARE_PROCESS;
104 else if (!wcsicmp( type, L"kernel" )) cp->type = SERVICE_KERNEL_DRIVER;
105 else if (!wcsicmp( type, L"filesys" )) cp->type = SERVICE_FILE_SYSTEM_DRIVER;
106 else if (!wcsicmp( type, L"rec" )) cp->type = SERVICE_RECOGNIZER_DRIVER;
107 else if (!wcsicmp( type, L"interact" )) cp->type |= SERVICE_INTERACTIVE_PROCESS;
108 continue;
110 if (PARSE( L"start=", &start ))
112 if (!wcsicmp( start, L"boot" )) cp->start = SERVICE_BOOT_START;
113 else if (!wcsicmp( start, L"system" )) cp->start = SERVICE_SYSTEM_START;
114 else if (!wcsicmp( start, L"auto" )) cp->start = SERVICE_AUTO_START;
115 else if (!wcsicmp( start, L"demand" )) cp->start = SERVICE_DEMAND_START;
116 else if (!wcsicmp( start, L"disabled" )) cp->start = SERVICE_DISABLED;
117 continue;
119 if (PARSE( L"error=", &error ))
121 if (!wcsicmp( error, L"normal" )) cp->error = SERVICE_ERROR_NORMAL;
122 else if (!wcsicmp( error, L"severe" )) cp->error = SERVICE_ERROR_SEVERE;
123 else if (!wcsicmp( error, L"critical" )) cp->error = SERVICE_ERROR_CRITICAL;
124 else if (!wcsicmp( error, L"ignore" )) cp->error = SERVICE_ERROR_IGNORE;
125 continue;
128 #undef PARSE
129 if (!cp->binpath) return FALSE;
130 return TRUE;
133 static BOOL parse_failure_actions( const WCHAR *arg, SERVICE_FAILURE_ACTIONSW *fa )
135 unsigned int i, count;
136 WCHAR *actions, *p;
138 actions = HeapAlloc( GetProcessHeap(), 0, (lstrlenW( arg ) + 1) * sizeof(WCHAR) );
139 if (!actions) return FALSE;
141 lstrcpyW( actions, arg );
142 for (p = actions, count = 0; *p; p++)
144 if (*p == '/')
146 count++;
147 *p = 0;
150 count = count / 2 + 1;
152 fa->cActions = count;
153 fa->lpsaActions = HeapAlloc( GetProcessHeap(), 0, fa->cActions * sizeof(SC_ACTION) );
154 if (!fa->lpsaActions)
156 HeapFree( GetProcessHeap(), 0, actions );
157 return FALSE;
160 p = actions;
161 for (i = 0; i < count; i++)
163 if (!wcsicmp( p, L"run" )) fa->lpsaActions[i].Type = SC_ACTION_RUN_COMMAND;
164 else if (!wcsicmp( p, L"restart" )) fa->lpsaActions[i].Type = SC_ACTION_RESTART;
165 else if (!wcsicmp( p, L"reboot" )) fa->lpsaActions[i].Type = SC_ACTION_REBOOT;
166 else fa->lpsaActions[i].Type = SC_ACTION_NONE;
168 p += lstrlenW( p ) + 1;
169 fa->lpsaActions[i].Delay = wcstol( p, NULL, 10 );
170 p += lstrlenW( p ) + 1;
173 HeapFree( GetProcessHeap(), 0, actions );
174 return TRUE;
177 static BOOL parse_failure_params( int argc, const WCHAR *argv[], SERVICE_FAILURE_ACTIONSW *fa )
179 unsigned int i;
181 fa->dwResetPeriod = 0;
182 fa->lpRebootMsg = NULL;
183 fa->lpCommand = NULL;
184 fa->cActions = 0;
185 fa->lpsaActions = NULL;
187 #define PARSE(x, y) parse_string_param( (argc), (argv), &(i), (x), ARRAY_SIZE(x) - 1, (y) )
188 for (i = 0; i < argc; i++)
190 const WCHAR *reset, *actions;
192 if (PARSE( L"reset=", &reset ))
194 fa->dwResetPeriod = wcstol( reset, NULL, 10 );
195 continue;
197 if (PARSE( L"reboot=", (const WCHAR **)&fa->lpRebootMsg )) continue;
198 if (PARSE( L"command=", (const WCHAR **)&fa->lpCommand )) continue;
199 if (PARSE( L"actions=", &actions ))
201 if (!parse_failure_actions( actions, fa )) return FALSE;
202 continue;
205 #undef PARSE
206 return TRUE;
209 static void usage( void )
211 WINE_MESSAGE( "Usage: sc command servicename [parameter= value ...]\n" );
212 exit( 1 );
215 static const WCHAR *service_type_string( DWORD type )
217 switch (type)
219 case SERVICE_WIN32_OWN_PROCESS: return L"WIN32_OWN_PROCESS";
220 case SERVICE_WIN32_SHARE_PROCESS: return L"WIN32_SHARE_PROCESS";
221 case SERVICE_WIN32: return L"WIN32";
222 default: return L"";
226 static const WCHAR *service_state_string( DWORD state )
228 static const WCHAR * const state_str[] = { L"", L"STOPPED", L"START_PENDING",
229 L"STOP_PENDING", L"RUNNING", L"CONTINUE_PENDING", L"PAUSE_PENDING", L"PAUSED" };
231 if (state < ARRAY_SIZE( state_str )) return state_str[ state ];
232 return L"";
235 static BOOL query_service( SC_HANDLE manager, const WCHAR *name )
237 SC_HANDLE service;
238 SERVICE_STATUS status;
239 BOOL ret = FALSE;
241 service = OpenServiceW( manager, name, SERVICE_QUERY_STATUS );
242 if (service)
244 ret = QueryServiceStatus( service, &status );
245 if (!ret)
246 WINE_ERR("failed to query service status %lu\n", GetLastError());
247 else
248 printf( "SERVICE_NAME: %ls\n"
249 " TYPE : %lx %ls\n"
250 " STATE : %lx %ls\n"
251 " WIN32_EXIT_CODE : %lu (0x%lx)\n"
252 " SERVICE_EXIT_CODE : %lu (0x%lx)\n"
253 " CHECKPOINT : 0x%lx\n"
254 " WAIT_HINT : 0x%lx\n",
255 name, status.dwServiceType, service_type_string( status.dwServiceType ),
256 status.dwCurrentState, service_state_string( status.dwCurrentState ),
257 status.dwWin32ExitCode, status.dwWin32ExitCode,
258 status.dwServiceSpecificExitCode, status.dwServiceSpecificExitCode,
259 status.dwCheckPoint, status.dwWaitHint );
260 CloseServiceHandle( service );
262 else WINE_ERR("failed to open service %lu\n", GetLastError());
264 return ret;
267 int __cdecl wmain( int argc, const WCHAR *argv[] )
269 SC_HANDLE manager, service;
270 SERVICE_STATUS status;
271 BOOL ret = FALSE;
273 if (argc < 3) usage();
275 if (argv[2][0] == '\\' && argv[2][1] == '\\')
277 WINE_FIXME("server argument not supported\n");
278 return 1;
281 manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
282 if (!manager)
284 WINE_ERR("failed to open service manager\n");
285 return 1;
288 if (!wcsicmp( argv[1], L"create" ))
290 struct create_params cp;
292 if (argc < 4)
294 CloseServiceHandle( manager );
295 usage();
297 if (!parse_create_params( argc - 3, argv + 3, &cp ))
299 WINE_ERR("failed to parse create parameters\n");
300 CloseServiceHandle( manager );
301 return 1;
303 service = CreateServiceW( manager, argv[2], cp.displayname, SERVICE_ALL_ACCESS,
304 cp.type, cp.start, cp.error, cp.binpath, cp.group, NULL,
305 cp.depend, cp.obj, cp.password );
306 if (service)
308 CloseServiceHandle( service );
309 ret = TRUE;
311 else WINE_ERR("failed to create service %lu\n", GetLastError());
313 else if (!wcsicmp( argv[1], L"description" ))
315 service = OpenServiceW( manager, argv[2], SERVICE_CHANGE_CONFIG );
316 if (service)
318 SERVICE_DESCRIPTIONW sd;
319 sd.lpDescription = argc > 3 ? (WCHAR *)argv[3] : NULL;
320 ret = ChangeServiceConfig2W( service, SERVICE_CONFIG_DESCRIPTION, &sd );
321 if (!ret) WINE_ERR("failed to set service description %lu\n", GetLastError());
322 CloseServiceHandle( service );
324 else WINE_ERR("failed to open service %lu\n", GetLastError());
326 else if (!wcsicmp( argv[1], L"failure" ))
328 service = OpenServiceW( manager, argv[2], SERVICE_CHANGE_CONFIG );
329 if (service)
331 SERVICE_FAILURE_ACTIONSW sfa;
332 if (parse_failure_params( argc - 3, argv + 3, &sfa ))
334 ret = ChangeServiceConfig2W( service, SERVICE_CONFIG_FAILURE_ACTIONS, &sfa );
335 if (!ret) WINE_ERR("failed to set service failure actions %lu\n", GetLastError());
336 HeapFree( GetProcessHeap(), 0, sfa.lpsaActions );
338 else
339 WINE_ERR("failed to parse failure parameters\n");
340 CloseServiceHandle( service );
342 else WINE_ERR("failed to open service %lu\n", GetLastError());
344 else if (!wcsicmp( argv[1], L"delete" ))
346 service = OpenServiceW( manager, argv[2], DELETE );
347 if (service)
349 ret = DeleteService( service );
350 if (!ret) WINE_ERR("failed to delete service %lu\n", GetLastError());
351 CloseServiceHandle( service );
353 else WINE_ERR("failed to open service %lu\n", GetLastError());
355 else if (!wcsicmp( argv[1], L"start" ))
357 service = OpenServiceW( manager, argv[2], SERVICE_START );
358 if (service)
360 ret = StartServiceW( service, argc - 3, argv + 3 );
361 if (!ret) WINE_ERR("failed to start service %lu\n", GetLastError());
362 else query_service( manager, argv[2] );
363 CloseServiceHandle( service );
365 else WINE_ERR("failed to open service %lu\n", GetLastError());
367 else if (!wcsicmp( argv[1], L"stop" ))
369 service = OpenServiceW( manager, argv[2], SERVICE_STOP );
370 if (service)
372 ret = ControlService( service, SERVICE_CONTROL_STOP, &status );
373 if (!ret) WINE_ERR("failed to stop service %lu\n", GetLastError());
374 else query_service( manager, argv[2] );
375 CloseServiceHandle( service );
377 else WINE_ERR("failed to open service %lu\n", GetLastError());
379 else if (!wcsicmp( argv[1], L"query" ))
381 ret = query_service( manager, argv[2] );
383 else if (!wcsicmp( argv[1], L"sdset" ))
385 WINE_FIXME("SdSet command not supported, faking success\n");
386 ret = TRUE;
388 else
389 WINE_FIXME("command not supported\n");
391 CloseServiceHandle( manager );
392 return !ret;