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
);
32 const WCHAR
*displayname
;
37 const WCHAR
*password
;
44 static BOOL
parse_create_params( int argc
, const WCHAR
*argv
[], struct create_params
*cp
)
48 cp
->displayname
= NULL
;
49 cp
->type
= SERVICE_WIN32_OWN_PROCESS
;
50 cp
->start
= SERVICE_DEMAND_START
;
51 cp
->error
= SERVICE_ERROR_NORMAL
;
59 for (i
= 0; i
< argc
; i
++)
61 if (!wcsnicmp( argv
[i
], L
"displayname=", 12 )) cp
->displayname
= argv
[i
] + 12;
62 if (!wcsnicmp( argv
[i
], L
"binpath=", 8 )) cp
->binpath
= argv
[i
] + 8;
63 if (!wcsnicmp( argv
[i
], L
"group=", 6 )) cp
->group
= argv
[i
] + 6;
64 if (!wcsnicmp( argv
[i
], L
"depend=", 7 )) cp
->depend
= argv
[i
] + 7;
65 if (!wcsnicmp( argv
[i
], L
"obj=", 4 )) cp
->obj
= argv
[i
] + 4;
66 if (!wcsnicmp( argv
[i
], L
"password=", 9 )) cp
->password
= argv
[i
] + 9;
68 if (!wcsnicmp( argv
[i
], L
"tag=", 4 ))
70 if (!wcsicmp( argv
[i
] + 4, L
"yes" ))
72 WINE_FIXME("tag argument not supported\n");
76 if (!wcsnicmp( argv
[i
], L
"type=", 5 ))
78 if (!wcsicmp( argv
[i
] + 5, L
"own" )) cp
->type
= SERVICE_WIN32_OWN_PROCESS
;
79 if (!wcsicmp( argv
[i
] + 5, L
"share" )) cp
->type
= SERVICE_WIN32_SHARE_PROCESS
;
80 if (!wcsicmp( argv
[i
] + 5, L
"kernel" )) cp
->type
= SERVICE_KERNEL_DRIVER
;
81 if (!wcsicmp( argv
[i
] + 5, L
"filesys" )) cp
->type
= SERVICE_FILE_SYSTEM_DRIVER
;
82 if (!wcsicmp( argv
[i
] + 5, L
"rec" )) cp
->type
= SERVICE_RECOGNIZER_DRIVER
;
83 if (!wcsicmp( argv
[i
] + 5, L
"interact" )) cp
->type
|= SERVICE_INTERACTIVE_PROCESS
;
85 if (!wcsnicmp( argv
[i
], L
"start=", 6 ))
87 if (!wcsicmp( argv
[i
] + 6, L
"boot" )) cp
->start
= SERVICE_BOOT_START
;
88 if (!wcsicmp( argv
[i
] + 6, L
"system" )) cp
->start
= SERVICE_SYSTEM_START
;
89 if (!wcsicmp( argv
[i
] + 6, L
"auto" )) cp
->start
= SERVICE_AUTO_START
;
90 if (!wcsicmp( argv
[i
] + 6, L
"demand" )) cp
->start
= SERVICE_DEMAND_START
;
91 if (!wcsicmp( argv
[i
] + 6, L
"disabled" )) cp
->start
= SERVICE_DISABLED
;
93 if (!wcsnicmp( argv
[i
], L
"error=", 6 ))
95 if (!wcsicmp( argv
[i
] + 6, L
"normal" )) cp
->error
= SERVICE_ERROR_NORMAL
;
96 if (!wcsicmp( argv
[i
] + 6, L
"severe" )) cp
->error
= SERVICE_ERROR_SEVERE
;
97 if (!wcsicmp( argv
[i
] + 6, L
"critical" )) cp
->error
= SERVICE_ERROR_CRITICAL
;
98 if (!wcsicmp( argv
[i
] + 6, L
"ignore" )) cp
->error
= SERVICE_ERROR_IGNORE
;
101 if (!cp
->binpath
) return FALSE
;
105 static BOOL
parse_failure_actions( const WCHAR
*arg
, SERVICE_FAILURE_ACTIONSW
*fa
)
107 unsigned int i
, count
;
110 actions
= HeapAlloc( GetProcessHeap(), 0, (lstrlenW( arg
) + 1) * sizeof(WCHAR
) );
111 if (!actions
) return FALSE
;
113 lstrcpyW( actions
, arg
);
114 for (p
= actions
, count
= 0; *p
; p
++)
122 count
= count
/ 2 + 1;
124 fa
->cActions
= count
;
125 fa
->lpsaActions
= HeapAlloc( GetProcessHeap(), 0, fa
->cActions
* sizeof(SC_ACTION
) );
126 if (!fa
->lpsaActions
)
128 HeapFree( GetProcessHeap(), 0, actions
);
133 for (i
= 0; i
< count
; i
++)
135 if (!wcsicmp( p
, L
"run" )) fa
->lpsaActions
[i
].Type
= SC_ACTION_RUN_COMMAND
;
136 else if (!wcsicmp( p
, L
"restart" )) fa
->lpsaActions
[i
].Type
= SC_ACTION_RESTART
;
137 else if (!wcsicmp( p
, L
"reboot" )) fa
->lpsaActions
[i
].Type
= SC_ACTION_REBOOT
;
138 else fa
->lpsaActions
[i
].Type
= SC_ACTION_NONE
;
140 p
+= lstrlenW( p
) + 1;
141 fa
->lpsaActions
[i
].Delay
= wcstol( p
, NULL
, 10 );
142 p
+= lstrlenW( p
) + 1;
145 HeapFree( GetProcessHeap(), 0, actions
);
149 static BOOL
parse_failure_params( int argc
, const WCHAR
*argv
[], SERVICE_FAILURE_ACTIONSW
*fa
)
153 fa
->dwResetPeriod
= 0;
154 fa
->lpRebootMsg
= NULL
;
155 fa
->lpCommand
= NULL
;
157 fa
->lpsaActions
= NULL
;
159 for (i
= 0; i
< argc
; i
++)
161 if (!wcsnicmp( argv
[i
], L
"reset=", 6 )) fa
->dwResetPeriod
= wcstol( argv
[i
] + 6, NULL
, 10 );
162 if (!wcsnicmp( argv
[i
], L
"reboot=", 7 )) fa
->lpRebootMsg
= (WCHAR
*)argv
[i
] + 7;
163 if (!wcsnicmp( argv
[i
], L
"command=", 8 )) fa
->lpCommand
= (WCHAR
*)argv
[i
] + 8;
164 if (!wcsnicmp( argv
[i
], L
"actions=", 8 ))
166 if (!parse_failure_actions( argv
[i
] + 8, fa
)) return FALSE
;
172 static void usage( void )
174 WINE_MESSAGE( "Usage: sc command servicename [parameter= value ...]\n" );
178 static const WCHAR
*service_type_string( DWORD type
)
182 case SERVICE_WIN32_OWN_PROCESS
: return L
"WIN32_OWN_PROCESS";
183 case SERVICE_WIN32_SHARE_PROCESS
: return L
"WIN32_SHARE_PROCESS";
184 case SERVICE_WIN32
: return L
"WIN32";
189 static const WCHAR
*service_state_string( DWORD state
)
191 static const WCHAR
* const state_str
[] = { L
"", L
"STOPPED", L
"START_PENDING",
192 L
"STOP_PENDING", L
"RUNNING", L
"CONTINUE_PENDING", L
"PAUSE_PENDING", L
"PAUSED" };
194 if (state
< ARRAY_SIZE( state_str
)) return state_str
[ state
];
198 static BOOL
query_service( SC_HANDLE manager
, const WCHAR
*name
)
201 SERVICE_STATUS status
;
204 service
= OpenServiceW( manager
, name
, SERVICE_QUERY_STATUS
);
207 ret
= QueryServiceStatus( service
, &status
);
209 WINE_ERR("failed to query service status %lu\n", GetLastError());
211 printf( "SERVICE_NAME: %ls\n"
214 " WIN32_EXIT_CODE : %lu (0x%lx)\n"
215 " SERVICE_EXIT_CODE : %lu (0x%lx)\n"
216 " CHECKPOINT : 0x%lx\n"
217 " WAIT_HINT : 0x%lx\n",
218 name
, status
.dwServiceType
, service_type_string( status
.dwServiceType
),
219 status
.dwCurrentState
, service_state_string( status
.dwCurrentState
),
220 status
.dwWin32ExitCode
, status
.dwWin32ExitCode
,
221 status
.dwServiceSpecificExitCode
, status
.dwServiceSpecificExitCode
,
222 status
.dwCheckPoint
, status
.dwWaitHint
);
223 CloseServiceHandle( service
);
225 else WINE_ERR("failed to open service %lu\n", GetLastError());
230 int __cdecl
wmain( int argc
, const WCHAR
*argv
[] )
232 SC_HANDLE manager
, service
;
233 SERVICE_STATUS status
;
236 if (argc
< 3) usage();
238 if (argv
[2][0] == '\\' && argv
[2][1] == '\\')
240 WINE_FIXME("server argument not supported\n");
244 manager
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
247 WINE_ERR("failed to open service manager\n");
251 if (!wcsicmp( argv
[1], L
"create" ))
253 struct create_params cp
;
257 CloseServiceHandle( manager
);
260 if (!parse_create_params( argc
- 3, argv
+ 3, &cp
))
262 WINE_ERR("failed to parse create parameters\n");
263 CloseServiceHandle( manager
);
266 service
= CreateServiceW( manager
, argv
[2], cp
.displayname
, SERVICE_ALL_ACCESS
,
267 cp
.type
, cp
.start
, cp
.error
, cp
.binpath
, cp
.group
, NULL
,
268 cp
.depend
, cp
.obj
, cp
.password
);
271 CloseServiceHandle( service
);
274 else WINE_ERR("failed to create service %lu\n", GetLastError());
276 else if (!wcsicmp( argv
[1], L
"description" ))
278 service
= OpenServiceW( manager
, argv
[2], SERVICE_CHANGE_CONFIG
);
281 SERVICE_DESCRIPTIONW sd
;
282 sd
.lpDescription
= argc
> 3 ? (WCHAR
*)argv
[3] : NULL
;
283 ret
= ChangeServiceConfig2W( service
, SERVICE_CONFIG_DESCRIPTION
, &sd
);
284 if (!ret
) WINE_ERR("failed to set service description %lu\n", GetLastError());
285 CloseServiceHandle( service
);
287 else WINE_ERR("failed to open service %lu\n", GetLastError());
289 else if (!wcsicmp( argv
[1], L
"failure" ))
291 service
= OpenServiceW( manager
, argv
[2], SERVICE_CHANGE_CONFIG
);
294 SERVICE_FAILURE_ACTIONSW sfa
;
295 if (parse_failure_params( argc
- 3, argv
+ 3, &sfa
))
297 ret
= ChangeServiceConfig2W( service
, SERVICE_CONFIG_FAILURE_ACTIONS
, &sfa
);
298 if (!ret
) WINE_ERR("failed to set service failure actions %lu\n", GetLastError());
299 HeapFree( GetProcessHeap(), 0, sfa
.lpsaActions
);
302 WINE_ERR("failed to parse failure parameters\n");
303 CloseServiceHandle( service
);
305 else WINE_ERR("failed to open service %lu\n", GetLastError());
307 else if (!wcsicmp( argv
[1], L
"delete" ))
309 service
= OpenServiceW( manager
, argv
[2], DELETE
);
312 ret
= DeleteService( service
);
313 if (!ret
) WINE_ERR("failed to delete service %lu\n", GetLastError());
314 CloseServiceHandle( service
);
316 else WINE_ERR("failed to open service %lu\n", GetLastError());
318 else if (!wcsicmp( argv
[1], L
"start" ))
320 service
= OpenServiceW( manager
, argv
[2], SERVICE_START
);
323 ret
= StartServiceW( service
, argc
- 3, argv
+ 3 );
324 if (!ret
) WINE_ERR("failed to start service %lu\n", GetLastError());
325 else query_service( manager
, argv
[2] );
326 CloseServiceHandle( service
);
328 else WINE_ERR("failed to open service %lu\n", GetLastError());
330 else if (!wcsicmp( argv
[1], L
"stop" ))
332 service
= OpenServiceW( manager
, argv
[2], SERVICE_STOP
);
335 ret
= ControlService( service
, SERVICE_CONTROL_STOP
, &status
);
336 if (!ret
) WINE_ERR("failed to stop service %lu\n", GetLastError());
337 else query_service( manager
, argv
[2] );
338 CloseServiceHandle( service
);
340 else WINE_ERR("failed to open service %lu\n", GetLastError());
342 else if (!wcsicmp( argv
[1], L
"query" ))
344 ret
= query_service( manager
, argv
[2] );
346 else if (!wcsicmp( argv
[1], L
"sdset" ))
348 WINE_FIXME("SdSet command not supported, faking success\n");
352 WINE_FIXME("command not supported\n");
354 CloseServiceHandle( manager
);