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
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
];
40 else if (*index
< argc
- 1)
52 const WCHAR
*displayname
;
57 const WCHAR
*password
;
64 static BOOL
parse_create_params( int argc
, const WCHAR
*argv
[], struct create_params
*cp
)
68 cp
->displayname
= NULL
;
69 cp
->type
= SERVICE_WIN32_OWN_PROCESS
;
70 cp
->start
= SERVICE_DEMAND_START
;
71 cp
->error
= SERVICE_ERROR_NORMAL
;
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");
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
;
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
;
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
;
129 if (!cp
->binpath
) return FALSE
;
133 static BOOL
parse_failure_actions( const WCHAR
*arg
, SERVICE_FAILURE_ACTIONSW
*fa
)
135 unsigned int i
, count
;
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
++)
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
);
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
);
177 static BOOL
parse_failure_params( int argc
, const WCHAR
*argv
[], SERVICE_FAILURE_ACTIONSW
*fa
)
181 fa
->dwResetPeriod
= 0;
182 fa
->lpRebootMsg
= NULL
;
183 fa
->lpCommand
= NULL
;
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 );
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
;
209 static void usage( void )
211 WINE_MESSAGE( "Usage: sc command servicename [parameter= value ...]\n" );
215 static const WCHAR
*service_type_string( DWORD 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";
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
];
235 static BOOL
query_service( SC_HANDLE manager
, const WCHAR
*name
)
238 SERVICE_STATUS status
;
241 service
= OpenServiceW( manager
, name
, SERVICE_QUERY_STATUS
);
244 ret
= QueryServiceStatus( service
, &status
);
246 WINE_ERR("failed to query service status %lu\n", GetLastError());
248 printf( "SERVICE_NAME: %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());
267 int __cdecl
wmain( int argc
, const WCHAR
*argv
[] )
269 SC_HANDLE manager
, service
;
270 SERVICE_STATUS status
;
273 if (argc
< 3) usage();
275 if (argv
[2][0] == '\\' && argv
[2][1] == '\\')
277 WINE_FIXME("server argument not supported\n");
281 manager
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
284 WINE_ERR("failed to open service manager\n");
288 if (!wcsicmp( argv
[1], L
"create" ))
290 struct create_params cp
;
294 CloseServiceHandle( manager
);
297 if (!parse_create_params( argc
- 3, argv
+ 3, &cp
))
299 WINE_ERR("failed to parse create parameters\n");
300 CloseServiceHandle( manager
);
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
);
308 CloseServiceHandle( service
);
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
);
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
);
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
);
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
);
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
);
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
);
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");
389 WINE_FIXME("command not supported\n");
391 CloseServiceHandle( manager
);