Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

583 lines
15 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. Service.c
  5. Abstract:
  6. License Logging Service - Common routines for all service.
  7. Author:
  8. Arthur Hanson (arth) Dec 07, 1994
  9. Environment:
  10. Revision History:
  11. --*/
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <windows.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <process.h>
  19. #include <tchar.h>
  20. #pragma warning (push)
  21. #pragma warning (disable : 4201) //avoid W4 from sdk\inc\shellapi.h
  22. #include <shellapi.h>
  23. #pragma warning (pop)
  24. #include "service.h"
  25. #include "debug.h"
  26. // internal variables
  27. static SERVICE_STATUS ssStatus; // current status of the service
  28. SERVICE_STATUS_HANDLE sshStatusHandle = 0;
  29. static DWORD dwErr = 0;
  30. BOOL bDebug = FALSE;
  31. TCHAR szErr[256];
  32. // internal function prototypes
  33. VOID WINAPI ServiceCtrl(DWORD dwCtrlCode);
  34. VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv);
  35. VOID CmdInstallService();
  36. VOID CmdRemoveService();
  37. VOID CmdDebugService(int argc, char **argv);
  38. BOOL WINAPI ControlHandler ( DWORD dwCtrlType );
  39. LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
  40. extern BOOL g_fRunning;
  41. /////////////////////////////////////////////////////////////////////////
  42. VOID __cdecl
  43. main(
  44. int argc,
  45. char **argv
  46. )
  47. /*++
  48. Routine Description:
  49. Main routine to setup the exception handlers and initialize everything
  50. before spawning threads to listen to LPC and RPC port requests.
  51. main() either performs the command line task, or calls
  52. StartServiceCtrlDispatcher to register the main service thread. When the
  53. this call returns, the service has stopped, so exit.
  54. Arguments:
  55. argc - number of command line arguments
  56. argv - array of command line arguments
  57. Return Values:
  58. None.
  59. --*/
  60. {
  61. SERVICE_TABLE_ENTRY dispatchTable[] = {
  62. { TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION) ServiceMain },
  63. { NULL, NULL }
  64. };
  65. if ( (argc > 1) && ((*argv[1] == '-') || (*argv[1] == '/')) ) {
  66. if ( _stricmp( "install", argv[1]+1 ) == 0 ) {
  67. CmdInstallService();
  68. } else if ( _stricmp( "remove", argv[1]+1 ) == 0 ) {
  69. CmdRemoveService();
  70. } else if ( _stricmp( "debug", argv[1]+1 ) == 0 ) {
  71. bDebug = TRUE;
  72. CmdDebugService(argc, argv);
  73. } else {
  74. goto dispatch;
  75. }
  76. exit(0);
  77. }
  78. // if it doesn't match any of the above parameters
  79. // the service control manager may be starting the service
  80. // so we must call StartServiceCtrlDispatcher
  81. dispatch:
  82. #ifdef DEBUG
  83. // this is just to be friendly
  84. printf( "%s -install to install the service\n", SZAPPNAME );
  85. printf( "%s -remove to remove the service\n", SZAPPNAME );
  86. printf( "%s -debug <params> to run as a console app for debugging\n", SZAPPNAME );
  87. printf( "\nStartServiceCtrlDispatcher being called.\n" );
  88. printf( "This may take several seconds. Please wait.\n" );
  89. #endif
  90. if (!StartServiceCtrlDispatcher(dispatchTable))
  91. dprintf(TEXT("LLS TRACE: StartServiceCtrlDispatcher failed\n"));
  92. } // main
  93. /////////////////////////////////////////////////////////////////////////
  94. VOID WINAPI
  95. ServiceMain(
  96. DWORD dwArgc,
  97. LPTSTR *lpszArgv
  98. )
  99. /*++
  100. Routine Description:
  101. Performs the service initialization and then calls the ServiceStart()
  102. routine to perform majority of the work.
  103. Arguments:
  104. dwArgc - number of command line arguments ***UNUSED***
  105. lpszArgv - array of command line arguments ***UNUSED***
  106. Return Values:
  107. None.
  108. --*/
  109. {
  110. // register our service control handler:
  111. //
  112. sshStatusHandle = RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), ServiceCtrl);
  113. if (!sshStatusHandle)
  114. goto cleanup;
  115. // SERVICE_STATUS members that don't change in example
  116. //
  117. ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  118. ssStatus.dwServiceSpecificExitCode = 0;
  119. // report the status to the service control manager.
  120. //
  121. if (!ReportStatusToSCMgr(
  122. SERVICE_START_PENDING, // service state
  123. NO_ERROR, // exit code
  124. NSERVICEWAITHINT)) // wait hint
  125. goto cleanup;
  126. ServiceStart( dwArgc, lpszArgv );
  127. cleanup:
  128. // try to report the stopped status to the service control manager.
  129. //
  130. if (sshStatusHandle)
  131. (VOID)ReportStatusToSCMgr(
  132. SERVICE_STOPPED,
  133. dwErr,
  134. 0);
  135. return;
  136. } // ServiceMain
  137. /////////////////////////////////////////////////////////////////////////
  138. VOID WINAPI
  139. ServiceCtrl(
  140. DWORD dwCtrlCode
  141. )
  142. /*++
  143. Routine Description:
  144. Called by the SCM whenever ControlService() is called on this service.
  145. Arguments:
  146. dwCtrlCode - type of control requested
  147. Return Values:
  148. None.
  149. --*/
  150. {
  151. DWORD dwState = SERVICE_RUNNING;
  152. // Handle the requested control code.
  153. //
  154. switch(dwCtrlCode) {
  155. // Stop the service.
  156. //
  157. case SERVICE_CONTROL_STOP:
  158. dwState = SERVICE_STOP_PENDING;
  159. ssStatus.dwCurrentState = SERVICE_STOP_PENDING;
  160. break;
  161. // Update the service status.
  162. //
  163. case SERVICE_CONTROL_INTERROGATE:
  164. break;
  165. // invalid control code
  166. //
  167. default:
  168. break;
  169. }
  170. ReportStatusToSCMgr(dwState, NO_ERROR, 0);
  171. if ( SERVICE_CONTROL_STOP == dwCtrlCode )
  172. {
  173. ServiceStop();
  174. }
  175. } // ServiceCtrl
  176. /////////////////////////////////////////////////////////////////////////
  177. BOOL
  178. ReportStatusToSCMgr(
  179. DWORD dwCurrentState,
  180. DWORD dwWin32ExitCode,
  181. DWORD dwWaitHint
  182. )
  183. /*++
  184. Routine Description:
  185. Sets the current status of the service and reports it to the SCM.
  186. Arguments:
  187. dwCurrentState - the state of the service
  188. dwWin32ExitCode - error code to report
  189. dwWaitHint - worst case estimate to next checkpoint
  190. Return Values:
  191. None.
  192. --*/
  193. {
  194. static DWORD dwCheckPoint = 1;
  195. BOOL fResult = TRUE;
  196. if ((g_fRunning) && (SERVICE_STOPPED != dwCurrentState) && (SERVICE_STOP_PENDING != dwCurrentState))
  197. {
  198. return TRUE;
  199. }
  200. if (sshStatusHandle == 0)
  201. {
  202. return FALSE;
  203. }
  204. ssStatus.dwControlsAccepted = 0;
  205. if ( !bDebug ) { // when debugging we don't report to the SCM
  206. if (dwCurrentState == SERVICE_START_PENDING)
  207. ssStatus.dwControlsAccepted = 0;
  208. else
  209. ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  210. ssStatus.dwCurrentState = dwCurrentState;
  211. ssStatus.dwWin32ExitCode = dwWin32ExitCode;
  212. ssStatus.dwWaitHint = dwWaitHint;
  213. if ( ( dwCurrentState == SERVICE_RUNNING ) ||
  214. ( dwCurrentState == SERVICE_STOPPED ) )
  215. ssStatus.dwCheckPoint = 0;
  216. else
  217. ssStatus.dwCheckPoint = dwCheckPoint++;
  218. // Report the status of the service to the service control manager.
  219. //
  220. if (FALSE == (fResult = SetServiceStatus( sshStatusHandle, &ssStatus))) {
  221. dprintf(TEXT("LLS TRACE: SetServiceStatus failed\n"));
  222. }
  223. }
  224. return fResult;
  225. } // ReportStatusToSCMgr
  226. /////////////////////////////////////////////////////////////////////////
  227. //
  228. // The following code handles service installation and removal
  229. //
  230. /////////////////////////////////////////////////////////////////////////
  231. /////////////////////////////////////////////////////////////////////////
  232. VOID
  233. CmdInstallService()
  234. /*++
  235. Routine Description:
  236. Installs the service.
  237. Arguments:
  238. None.
  239. Return Values:
  240. None.
  241. --*/
  242. {
  243. SC_HANDLE schService;
  244. SC_HANDLE schSCManager;
  245. TCHAR szPath[512];
  246. if (0 == GetModuleFileName( NULL, szPath, sizeof(szPath) / sizeof(szPath[0] )))
  247. {
  248. _tprintf(TEXT("Unable to install %s - %s\n"), TEXT(SZSERVICEDISPLAYNAME), GetLastErrorText(szErr, 256));
  249. return;
  250. }
  251. schSCManager = OpenSCManager(
  252. NULL, // machine (NULL == local)
  253. NULL, // database (NULL == default)
  254. SC_MANAGER_ALL_ACCESS // access required
  255. );
  256. if ( schSCManager ) {
  257. schService = CreateService(
  258. schSCManager, // SCManager database
  259. TEXT(SZSERVICENAME), // name of service
  260. TEXT(SZSERVICEDISPLAYNAME), // name to display
  261. SERVICE_ALL_ACCESS, // desired access
  262. SERVICE_WIN32_OWN_PROCESS, // service type
  263. SERVICE_DEMAND_START, // start type
  264. SERVICE_ERROR_NORMAL, // error control type
  265. szPath, // service's binary
  266. NULL, // no load ordering group
  267. NULL, // no tag identifier
  268. TEXT(SZDEPENDENCIES), // dependencies
  269. NULL, // LocalSystem account
  270. NULL); // no password
  271. if ( schService ) {
  272. _tprintf(TEXT("%s installed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
  273. CloseServiceHandle(schService);
  274. } else {
  275. _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(szErr, 256));
  276. }
  277. CloseServiceHandle(schSCManager);
  278. } else
  279. _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
  280. } // CmdInstallService
  281. /////////////////////////////////////////////////////////////////////////
  282. VOID
  283. CmdRemoveService()
  284. /*++
  285. Routine Description:
  286. Stops and removes the service.
  287. Arguments:
  288. None.
  289. Return Values:
  290. None.
  291. --*/
  292. {
  293. SC_HANDLE schService;
  294. SC_HANDLE schSCManager;
  295. schSCManager = OpenSCManager(
  296. NULL, // machine (NULL == local)
  297. NULL, // database (NULL == default)
  298. SC_MANAGER_ALL_ACCESS // access required
  299. );
  300. if ( schSCManager ) {
  301. schService = OpenService(schSCManager, TEXT(SZSERVICENAME), SERVICE_ALL_ACCESS);
  302. if (schService) {
  303. // try to stop the service
  304. if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) ) {
  305. _tprintf(TEXT("Stopping %s."), TEXT(SZSERVICEDISPLAYNAME));
  306. Sleep( 1000 );
  307. while( QueryServiceStatus( schService, &ssStatus ) ) {
  308. if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING ) {
  309. _tprintf(TEXT("."));
  310. Sleep( 1000 );
  311. } else
  312. break;
  313. }
  314. if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
  315. _tprintf(TEXT("\n%s stopped.\n"), TEXT(SZSERVICEDISPLAYNAME) );
  316. else
  317. _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) );
  318. }
  319. // now remove the service
  320. if( DeleteService(schService) )
  321. _tprintf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
  322. else
  323. _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256));
  324. CloseServiceHandle(schService);
  325. } else
  326. _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));
  327. CloseServiceHandle(schSCManager);
  328. } else
  329. _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
  330. } // CmdRemoveService
  331. /////////////////////////////////////////////////////////////////////////
  332. //
  333. // Routines for running the service as a console app
  334. //
  335. /////////////////////////////////////////////////////////////////////////
  336. /////////////////////////////////////////////////////////////////////////
  337. VOID CmdDebugService(
  338. int argc,
  339. char ** argv
  340. )
  341. /*++
  342. Routine Description:
  343. Runs the service as a console application
  344. Arguments:
  345. argc - number of command line arguments ***UNUSED***
  346. argv - array of command line arguments ***UNUSED***
  347. Return Values:
  348. None.
  349. --*/
  350. {
  351. UNREFERENCED_PARAMETER(argc);
  352. UNREFERENCED_PARAMETER(argv);
  353. _tprintf(TEXT("Debugging %s.\n"), TEXT(SZSERVICEDISPLAYNAME));
  354. SetConsoleCtrlHandler( ControlHandler, TRUE );
  355. // assumption: argv and argc unused
  356. ServiceStart( 0, NULL );
  357. } // CmdDebugService
  358. /////////////////////////////////////////////////////////////////////////
  359. BOOL WINAPI
  360. ControlHandler (
  361. DWORD dwCtrlType
  362. )
  363. /*++
  364. Routine Description:
  365. Handle console control events.
  366. Arguments:
  367. dwCtrlType - type of control event
  368. lpszMsg - text for message
  369. Return Values:
  370. True - handled
  371. False - unhandled
  372. --*/
  373. {
  374. switch( dwCtrlType ) {
  375. case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
  376. case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode
  377. _tprintf(TEXT("Stopping %s.\n"), TEXT(SZSERVICEDISPLAYNAME));
  378. ServiceStop();
  379. return TRUE;
  380. break;
  381. }
  382. return FALSE;
  383. } // ControlHandler
  384. /////////////////////////////////////////////////////////////////////////
  385. LPTSTR
  386. GetLastErrorText(
  387. LPTSTR lpszBuf,
  388. DWORD dwSize
  389. )
  390. /*++
  391. Routine Description:
  392. Copies last error message text to string.
  393. Arguments:
  394. lpszBuf - destination buffer
  395. dwSize - size of buffer
  396. Return Values:
  397. destination buffer
  398. --*/
  399. {
  400. DWORD dwRet;
  401. LPTSTR lpszTemp = NULL;
  402. dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
  403. NULL,
  404. GetLastError(),
  405. LANG_NEUTRAL,
  406. (LPTSTR)&lpszTemp,
  407. 0,
  408. NULL );
  409. // supplied buffer is not long enough
  410. if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
  411. {
  412. ASSERT(NULL != lpszBuf);
  413. lpszBuf[0] = TEXT('\0');
  414. }
  415. else {
  416. lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); //remove cr and newline character
  417. _stprintf( lpszBuf, TEXT("%s (0x%x)"), lpszTemp, GetLastError() );
  418. }
  419. if ( lpszTemp )
  420. LocalFree((HLOCAL) lpszTemp );
  421. return lpszBuf;
  422. } // GetLastErrorText