sc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /*
  2. * Copyright 2010 Hans Leidekker
  3. *
  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.
  8. *
  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.
  13. *
  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
  17. */
  18. #define WIN32_LEAN_AND_MEAN
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include <windows.h>
  23. #include <winsvc.h>
  24. #include "wine/debug.h"
  25. WINE_DEFAULT_DEBUG_CHANNEL(sc);
  26. struct create_params
  27. {
  28. const WCHAR *displayname;
  29. const WCHAR *binpath;
  30. const WCHAR *group;
  31. const WCHAR *depend;
  32. const WCHAR *obj;
  33. const WCHAR *password;
  34. DWORD type;
  35. DWORD start;
  36. DWORD error;
  37. BOOL tag;
  38. };
  39. static BOOL parse_create_params( int argc, const WCHAR *argv[], struct create_params *cp )
  40. {
  41. unsigned int i;
  42. cp->displayname = NULL;
  43. cp->type = SERVICE_WIN32_OWN_PROCESS;
  44. cp->start = SERVICE_DEMAND_START;
  45. cp->error = SERVICE_ERROR_NORMAL;
  46. cp->binpath = NULL;
  47. cp->group = NULL;
  48. cp->tag = FALSE;
  49. cp->depend = NULL;
  50. cp->obj = NULL;
  51. cp->password = NULL;
  52. for (i = 0; i < argc; i++)
  53. {
  54. if (!wcsnicmp( argv[i], L"displayname=", 12 )) cp->displayname = argv[i] + 12;
  55. if (!wcsnicmp( argv[i], L"binpath=", 8 )) cp->binpath = argv[i] + 8;
  56. if (!wcsnicmp( argv[i], L"group=", 6 )) cp->group = argv[i] + 6;
  57. if (!wcsnicmp( argv[i], L"depend=", 7 )) cp->depend = argv[i] + 7;
  58. if (!wcsnicmp( argv[i], L"obj=", 4 )) cp->obj = argv[i] + 4;
  59. if (!wcsnicmp( argv[i], L"password=", 9 )) cp->password = argv[i] + 9;
  60. if (!wcsnicmp( argv[i], L"tag=", 4 ))
  61. {
  62. if (!wcsicmp( argv[i] + 4, L"yes" ))
  63. {
  64. WINE_FIXME("tag argument not supported\n");
  65. cp->tag = TRUE;
  66. }
  67. }
  68. if (!wcsnicmp( argv[i], L"type=", 5 ))
  69. {
  70. if (!wcsicmp( argv[i] + 5, L"own" )) cp->type = SERVICE_WIN32_OWN_PROCESS;
  71. if (!wcsicmp( argv[i] + 5, L"share" )) cp->type = SERVICE_WIN32_SHARE_PROCESS;
  72. if (!wcsicmp( argv[i] + 5, L"kernel" )) cp->type = SERVICE_KERNEL_DRIVER;
  73. if (!wcsicmp( argv[i] + 5, L"filesys" )) cp->type = SERVICE_FILE_SYSTEM_DRIVER;
  74. if (!wcsicmp( argv[i] + 5, L"rec" )) cp->type = SERVICE_RECOGNIZER_DRIVER;
  75. if (!wcsicmp( argv[i] + 5, L"interact" )) cp->type |= SERVICE_INTERACTIVE_PROCESS;
  76. }
  77. if (!wcsnicmp( argv[i], L"start=", 6 ))
  78. {
  79. if (!wcsicmp( argv[i] + 6, L"boot" )) cp->start = SERVICE_BOOT_START;
  80. if (!wcsicmp( argv[i] + 6, L"system" )) cp->start = SERVICE_SYSTEM_START;
  81. if (!wcsicmp( argv[i] + 6, L"auto" )) cp->start = SERVICE_AUTO_START;
  82. if (!wcsicmp( argv[i] + 6, L"demand" )) cp->start = SERVICE_DEMAND_START;
  83. if (!wcsicmp( argv[i] + 6, L"disabled" )) cp->start = SERVICE_DISABLED;
  84. }
  85. if (!wcsnicmp( argv[i], L"error=", 6 ))
  86. {
  87. if (!wcsicmp( argv[i] + 6, L"normal" )) cp->error = SERVICE_ERROR_NORMAL;
  88. if (!wcsicmp( argv[i] + 6, L"severe" )) cp->error = SERVICE_ERROR_SEVERE;
  89. if (!wcsicmp( argv[i] + 6, L"critical" )) cp->error = SERVICE_ERROR_CRITICAL;
  90. if (!wcsicmp( argv[i] + 6, L"ignore" )) cp->error = SERVICE_ERROR_IGNORE;
  91. }
  92. }
  93. if (!cp->binpath) return FALSE;
  94. return TRUE;
  95. }
  96. static BOOL parse_failure_actions( const WCHAR *arg, SERVICE_FAILURE_ACTIONSW *fa )
  97. {
  98. unsigned int i, count;
  99. WCHAR *actions, *p;
  100. actions = HeapAlloc( GetProcessHeap(), 0, (lstrlenW( arg ) + 1) * sizeof(WCHAR) );
  101. if (!actions) return FALSE;
  102. lstrcpyW( actions, arg );
  103. for (p = actions, count = 0; *p; p++)
  104. {
  105. if (*p == '/')
  106. {
  107. count++;
  108. *p = 0;
  109. }
  110. }
  111. count = count / 2 + 1;
  112. fa->cActions = count;
  113. fa->lpsaActions = HeapAlloc( GetProcessHeap(), 0, fa->cActions * sizeof(SC_ACTION) );
  114. if (!fa->lpsaActions)
  115. {
  116. HeapFree( GetProcessHeap(), 0, actions );
  117. return FALSE;
  118. }
  119. p = actions;
  120. for (i = 0; i < count; i++)
  121. {
  122. if (!wcsicmp( p, L"run" )) fa->lpsaActions[i].Type = SC_ACTION_RUN_COMMAND;
  123. else if (!wcsicmp( p, L"restart" )) fa->lpsaActions[i].Type = SC_ACTION_RESTART;
  124. else if (!wcsicmp( p, L"reboot" )) fa->lpsaActions[i].Type = SC_ACTION_REBOOT;
  125. else fa->lpsaActions[i].Type = SC_ACTION_NONE;
  126. p += lstrlenW( p ) + 1;
  127. fa->lpsaActions[i].Delay = wcstol( p, NULL, 10 );
  128. p += lstrlenW( p ) + 1;
  129. }
  130. HeapFree( GetProcessHeap(), 0, actions );
  131. return TRUE;
  132. }
  133. static BOOL parse_failure_params( int argc, const WCHAR *argv[], SERVICE_FAILURE_ACTIONSW *fa )
  134. {
  135. unsigned int i;
  136. fa->dwResetPeriod = 0;
  137. fa->lpRebootMsg = NULL;
  138. fa->lpCommand = NULL;
  139. fa->cActions = 0;
  140. fa->lpsaActions = NULL;
  141. for (i = 0; i < argc; i++)
  142. {
  143. if (!wcsnicmp( argv[i], L"reset=", 6 )) fa->dwResetPeriod = wcstol( argv[i] + 6, NULL, 10 );
  144. if (!wcsnicmp( argv[i], L"reboot=", 7 )) fa->lpRebootMsg = (WCHAR *)argv[i] + 7;
  145. if (!wcsnicmp( argv[i], L"command=", 8 )) fa->lpCommand = (WCHAR *)argv[i] + 8;
  146. if (!wcsnicmp( argv[i], L"actions=", 8 ))
  147. {
  148. if (!parse_failure_actions( argv[i] + 8, fa )) return FALSE;
  149. }
  150. }
  151. return TRUE;
  152. }
  153. static void usage( void )
  154. {
  155. WINE_MESSAGE( "Usage: sc command servicename [parameter= value ...]\n" );
  156. exit( 1 );
  157. }
  158. static const WCHAR *service_type_string( DWORD type )
  159. {
  160. switch (type)
  161. {
  162. case SERVICE_WIN32_OWN_PROCESS: return L"WIN32_OWN_PROCESS";
  163. case SERVICE_WIN32_SHARE_PROCESS: return L"WIN32_SHARE_PROCESS";
  164. case SERVICE_WIN32: return L"WIN32";
  165. default: return L"";
  166. }
  167. }
  168. static const WCHAR *service_state_string( DWORD state )
  169. {
  170. static const WCHAR * const state_str[] = { L"", L"STOPPED", L"START_PENDING",
  171. L"STOP_PENDING", L"RUNNING", L"CONTINUE_PENDING", L"PAUSE_PENDING", L"PAUSED" };
  172. if (state < ARRAY_SIZE( state_str )) return state_str[ state ];
  173. return L"";
  174. }
  175. static BOOL query_service( SC_HANDLE manager, const WCHAR *name )
  176. {
  177. SC_HANDLE service;
  178. SERVICE_STATUS status;
  179. BOOL ret = FALSE;
  180. service = OpenServiceW( manager, name, SERVICE_QUERY_STATUS );
  181. if (service)
  182. {
  183. ret = QueryServiceStatus( service, &status );
  184. if (!ret)
  185. WINE_ERR("failed to query service status %lu\n", GetLastError());
  186. else
  187. printf( "SERVICE_NAME: %ls\n"
  188. " TYPE : %lx %ls\n"
  189. " STATE : %lx %ls\n"
  190. " WIN32_EXIT_CODE : %lu (0x%lx)\n"
  191. " SERVICE_EXIT_CODE : %lu (0x%lx)\n"
  192. " CHECKPOINT : 0x%lx\n"
  193. " WAIT_HINT : 0x%lx\n",
  194. name, status.dwServiceType, service_type_string( status.dwServiceType ),
  195. status.dwCurrentState, service_state_string( status.dwCurrentState ),
  196. status.dwWin32ExitCode, status.dwWin32ExitCode,
  197. status.dwServiceSpecificExitCode, status.dwServiceSpecificExitCode,
  198. status.dwCheckPoint, status.dwWaitHint );
  199. CloseServiceHandle( service );
  200. }
  201. else WINE_ERR("failed to open service %lu\n", GetLastError());
  202. return ret;
  203. }
  204. int __cdecl wmain( int argc, const WCHAR *argv[] )
  205. {
  206. SC_HANDLE manager, service;
  207. SERVICE_STATUS status;
  208. BOOL ret = FALSE;
  209. if (argc < 3) usage();
  210. if (argv[2][0] == '\\' && argv[2][1] == '\\')
  211. {
  212. WINE_FIXME("server argument not supported\n");
  213. return 1;
  214. }
  215. manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
  216. if (!manager)
  217. {
  218. WINE_ERR("failed to open service manager\n");
  219. return 1;
  220. }
  221. if (!wcsicmp( argv[1], L"create" ))
  222. {
  223. struct create_params cp;
  224. if (argc < 4)
  225. {
  226. CloseServiceHandle( manager );
  227. usage();
  228. }
  229. if (!parse_create_params( argc - 3, argv + 3, &cp ))
  230. {
  231. WINE_ERR("failed to parse create parameters\n");
  232. CloseServiceHandle( manager );
  233. return 1;
  234. }
  235. service = CreateServiceW( manager, argv[2], cp.displayname, SERVICE_ALL_ACCESS,
  236. cp.type, cp.start, cp.error, cp.binpath, cp.group, NULL,
  237. cp.depend, cp.obj, cp.password );
  238. if (service)
  239. {
  240. CloseServiceHandle( service );
  241. ret = TRUE;
  242. }
  243. else WINE_ERR("failed to create service %lu\n", GetLastError());
  244. }
  245. else if (!wcsicmp( argv[1], L"description" ))
  246. {
  247. service = OpenServiceW( manager, argv[2], SERVICE_CHANGE_CONFIG );
  248. if (service)
  249. {
  250. SERVICE_DESCRIPTIONW sd;
  251. sd.lpDescription = argc > 3 ? (WCHAR *)argv[3] : NULL;
  252. ret = ChangeServiceConfig2W( service, SERVICE_CONFIG_DESCRIPTION, &sd );
  253. if (!ret) WINE_ERR("failed to set service description %lu\n", GetLastError());
  254. CloseServiceHandle( service );
  255. }
  256. else WINE_ERR("failed to open service %lu\n", GetLastError());
  257. }
  258. else if (!wcsicmp( argv[1], L"failure" ))
  259. {
  260. service = OpenServiceW( manager, argv[2], SERVICE_CHANGE_CONFIG );
  261. if (service)
  262. {
  263. SERVICE_FAILURE_ACTIONSW sfa;
  264. if (parse_failure_params( argc - 3, argv + 3, &sfa ))
  265. {
  266. ret = ChangeServiceConfig2W( service, SERVICE_CONFIG_FAILURE_ACTIONS, &sfa );
  267. if (!ret) WINE_ERR("failed to set service failure actions %lu\n", GetLastError());
  268. HeapFree( GetProcessHeap(), 0, sfa.lpsaActions );
  269. }
  270. else
  271. WINE_ERR("failed to parse failure parameters\n");
  272. CloseServiceHandle( service );
  273. }
  274. else WINE_ERR("failed to open service %lu\n", GetLastError());
  275. }
  276. else if (!wcsicmp( argv[1], L"delete" ))
  277. {
  278. service = OpenServiceW( manager, argv[2], DELETE );
  279. if (service)
  280. {
  281. ret = DeleteService( service );
  282. if (!ret) WINE_ERR("failed to delete service %lu\n", GetLastError());
  283. CloseServiceHandle( service );
  284. }
  285. else WINE_ERR("failed to open service %lu\n", GetLastError());
  286. }
  287. else if (!wcsicmp( argv[1], L"start" ))
  288. {
  289. service = OpenServiceW( manager, argv[2], SERVICE_START );
  290. if (service)
  291. {
  292. ret = StartServiceW( service, argc - 3, argv + 3 );
  293. if (!ret) WINE_ERR("failed to start service %lu\n", GetLastError());
  294. else query_service( manager, argv[2] );
  295. CloseServiceHandle( service );
  296. }
  297. else WINE_ERR("failed to open service %lu\n", GetLastError());
  298. }
  299. else if (!wcsicmp( argv[1], L"stop" ))
  300. {
  301. service = OpenServiceW( manager, argv[2], SERVICE_STOP );
  302. if (service)
  303. {
  304. ret = ControlService( service, SERVICE_CONTROL_STOP, &status );
  305. if (!ret) WINE_ERR("failed to stop service %lu\n", GetLastError());
  306. else query_service( manager, argv[2] );
  307. CloseServiceHandle( service );
  308. }
  309. else WINE_ERR("failed to open service %lu\n", GetLastError());
  310. }
  311. else if (!wcsicmp( argv[1], L"query" ))
  312. {
  313. ret = query_service( manager, argv[2] );
  314. }
  315. else if (!wcsicmp( argv[1], L"sdset" ))
  316. {
  317. WINE_FIXME("SdSet command not supported, faking success\n");
  318. ret = TRUE;
  319. }
  320. else
  321. WINE_FIXME("command not supported\n");
  322. CloseServiceHandle( manager );
  323. return !ret;
  324. }