Source code of Windows XP (NT5)
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.

321 lines
12 KiB

  1. /*======================================================================================//
  2. | //
  3. |Copyright (c) 1998, 1999 Sequent Computer Systems, Incorporated. All rights reserved. //
  4. | //
  5. |Description: //
  6. | //
  7. |---------------------------------------------------------------------------------------//
  8. ; This file contains main(), ServiceMain(), and Service Start, Stop, and Control. //
  9. |---------------------------------------------------------------------------------------//
  10. | //
  11. |Created: //
  12. | //
  13. | Jarl McDonald 07-98 //
  14. | //
  15. |Revision History: //
  16. | //
  17. |=======================================================================================*/
  18. #include "ProcConSvc.h"
  19. #include <shellapi.h>
  20. //--------------------------------------------------------------------------------//
  21. // Globals //
  22. //--------------------------------------------------------------------------------//
  23. BOOL svcStop = FALSE; // shows if stop has been issued
  24. BOOL notService = FALSE; // TRUE if we're running as a console app
  25. SERVICE_STATUS_HANDLE ssHandle; // service control handler
  26. SERVICE_STATUS ssStatus; // current service status
  27. PCULONG32 ssErrCode = 0; // error code for status reporting
  28. CProcCon *cPCptr = NULL; // Pointer to give service rtns access
  29. static void
  30. Usage( void )
  31. {
  32. DWORD numWritten;
  33. DWORD numToWrite;
  34. HANDLE StdOut;
  35. StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
  36. numToWrite = _tcslen(PROCCON_SERVICE_USAGE);
  37. if (! WriteConsole(StdOut,
  38. PROCCON_SERVICE_USAGE,
  39. numToWrite,
  40. &numWritten,
  41. 0)) {
  42. WriteFile(StdOut,
  43. PROCCON_SERVICE_USAGE,
  44. numToWrite * sizeof(TCHAR),
  45. &numWritten,
  46. NULL);
  47. }
  48. }
  49. //=======================================================================================//
  50. // main function -- initiate requested action: install, remove, run as console app, run as service
  51. //
  52. // Input: none -- args retrieved via GetCommandLine
  53. // Returns: no return value
  54. //
  55. void _cdecl main( void )
  56. {
  57. // Load our strings so we have proper reporting, etc.
  58. PCLoadStrings();
  59. int argc;
  60. TCHAR *cmdLine = GetCommandLineW();
  61. TCHAR **argv = CommandLineToArgvW( cmdLine, &argc );
  62. if (!argv) {
  63. Usage();
  64. return;
  65. }
  66. // See if a command line command was given -- only true if a switch (- or /)...
  67. if ( argc > 1 && (argv[1][0] == '-' || argv[1][0] == '/') ) {
  68. if ( !_tcsicmp( TEXT("install"), argv[1] + 1 ) ) PCInstallService( argc - 2, &argv[2] );
  69. else if ( !_tcsicmp( TEXT("remove"), argv[1] + 1 ) ) PCRemoveService( argc - 2, &argv[2] );
  70. else if ( !_tcsicmp( TEXT("reinstall"), argv[1] + 1 ) ) {
  71. PCRemoveService( argc - 2, &argv[2] );
  72. PCInstallService( argc - 2, &argv[2] );
  73. }
  74. #ifdef _DEBUG
  75. else if ( !_tcsicmp( TEXT("noservice"), argv[1] + 1 ) ) PCConsoleService( argc - 2, &argv[2] );
  76. #endif
  77. else Usage();
  78. return;
  79. }
  80. // No command line -- we are to run as a service...
  81. // Then kick things off...
  82. static SERVICE_TABLE_ENTRY dispTbl[] = {
  83. { const_cast <TCHAR *> (PROCCON_SVC_NAME), (LPSERVICE_MAIN_FUNCTION) PCServiceMain },
  84. { NULL, NULL }
  85. };
  86. if ( !StartServiceCtrlDispatcher( dispTbl ) ) {
  87. ssErrCode = GetLastError();
  88. PCLogMessage( PC_SERVICE_DISPATCH_ERROR, EVENTLOG_ERROR_TYPE, 1, PROCCON_SVC_DISP_NAME,
  89. sizeof(ssErrCode), &ssErrCode );
  90. }
  91. }
  92. //=======================================================================================//
  93. // PCServiceMain -- our main service routine -- will start processing
  94. //
  95. // Input: argc, argv (now as PCULONG32 and TCHAR).
  96. // Returns: no return value
  97. //
  98. void WINAPI PCServiceMain( PCULONG32 Argc, LPTSTR *Argv ) {
  99. // register our service control handler...
  100. ssHandle = RegisterServiceCtrlHandler( PROCCON_SVC_NAME, PCServiceControl );
  101. if ( ssHandle ) {
  102. // Initialize fixed-value status members...
  103. ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  104. ssStatus.dwServiceSpecificExitCode = 0;
  105. // request handling of alignment errors. We know we have som issues on IA64 machines.
  106. SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT);
  107. // report status to the service control manager and start service...
  108. if ( PCReportStatus( SERVICE_START_PENDING, NO_ERROR, 3000) )
  109. PCStartService( Argc, Argv );
  110. if ( svcStop )
  111. PCLogMessage( PC_SERVICE_STOPPED, EVENTLOG_INFORMATION_TYPE, 1, PROCCON_SVC_DISP_NAME );
  112. // report stopped status to the service control manager...
  113. PCReportStatus( SERVICE_STOPPED, ssErrCode, 0 );
  114. }
  115. return;
  116. }
  117. //=======================================================================================//
  118. // The Process Management app start point
  119. //
  120. // Input: argc, argv (now as PCULONG32 and TCHAR, both ignored)
  121. // Returns: no return value
  122. //
  123. void PCStartService( PCULONG32 Argc, LPTSTR *Argv ) {
  124. // See that we are running under Windows 2000 Datacenter Server only...
  125. #if !defined(_DEBUG) && !defined(IBM_NUMAQ_PC)
  126. if ( !PCTestOSVersion() ) {
  127. PCLogMessage( PC_SERVICE_UNSUPPORTED_WINDOWS_VERSION, EVENTLOG_ERROR_TYPE, 1, PROCCON_SVC_DISP_NAME );
  128. //ssErrCode = ERROR_BAD_ENVIRONMENT; // have to use an NT error to get SCM to put it in the event log nicely
  129. return;
  130. }
  131. #endif
  132. // Make sure we are not already running and set up mutual exclusion...
  133. // If the process is started twice in service mode the
  134. // SCM will enforce the single instance rule but we could be burned
  135. // by a debug version.
  136. // It appears to take the system longer to clean up the orphaned event
  137. // then it take SCM to realize the service crashed, is not running, and
  138. // can be started again.
  139. // If we exit we don't report status to SCM and that's not good.
  140. if (!PCSetIsRunning( PROCCON_SVC_EXCLUSION, PROCCON_SVC_DISP_NAME )) {
  141. // ssErrCode = ERROR_ALREADY_EXISTS; // have to use an NT error to get SCM to put it in the event log nicely
  142. return;
  143. }
  144. //
  145. // Instantiate ourselves and test for success...
  146. //
  147. CProcCon cPC;
  148. if ( !cPC.ReadyToRun() ) {
  149. PCLogMessage( PC_STARTUP_FAILED, EVENTLOG_ERROR_TYPE, 1, PROCCON_SVC_DISP_NAME );
  150. // ssErrCode = ; // have to use an NT error to get SCM to put it in the event log nicely
  151. return;
  152. }
  153. cPCptr = &cPC; // set global pointer for Service Stop usage
  154. // We are ready to start processing so set service started...
  155. if ( !PCReportStatus( SERVICE_RUNNING, NO_ERROR, 0) ) {
  156. // no likely recovery...
  157. cPC.HardStop(ssErrCode);
  158. cPCptr = NULL; // not necesary
  159. return;
  160. }
  161. else if ( !notService )
  162. PCLogMessage( PC_SERVICE_STARTED, EVENTLOG_INFORMATION_TYPE, 1, PROCCON_SVC_DISP_NAME );
  163. //
  164. // Main service process...
  165. //
  166. cPC.Run();
  167. cPCptr = NULL; // a reminder that the global pointer references a stack variable
  168. }
  169. //=============================================================================================
  170. // function to initiate service stop.
  171. //
  172. // Input: none
  173. // Returns: nothing
  174. // Note: what's done here must not take longer than 3 seconds by NT service rules
  175. //
  176. VOID PCStopService()
  177. {
  178. svcStop = TRUE;
  179. if ( cPCptr )
  180. cPCptr->Stop();
  181. }
  182. //=============================================================================================
  183. // function to handle ControlService for us.
  184. //
  185. // Input: control code
  186. // Returns: nothing
  187. //
  188. void WINAPI PCServiceControl( PCULONG32 dwCtrlCode ) {
  189. // Handle the requested control code.
  190. //
  191. switch(dwCtrlCode)
  192. {
  193. // Stop or shutdown the service...
  194. case SERVICE_CONTROL_STOP:
  195. case SERVICE_CONTROL_SHUTDOWN:
  196. PCReportStatus( SERVICE_STOP_PENDING, NO_ERROR, 0 );
  197. PCStopService();
  198. return;
  199. // Other standard control codes...
  200. case SERVICE_CONTROL_PAUSE:
  201. case SERVICE_CONTROL_CONTINUE:
  202. case SERVICE_CONTROL_INTERROGATE:
  203. break;
  204. // invalid or user control codes...
  205. default:
  206. break;
  207. }
  208. PCReportStatus(ssStatus.dwCurrentState, NO_ERROR, 0);
  209. }
  210. //=============================================================================================
  211. // function to handle service status reporting to NT
  212. //
  213. // Input: current state, exit code, wait hint
  214. // Returns: TRUE if status reported (or not a service), else FALSE
  215. //
  216. //
  217. BOOL PCReportStatus( PCULONG32 dwCurrentState, PCULONG32 dwWin32ExitCode, PCULONG32 dwWaitHint ) {
  218. static PCULONG32 dwCheckPoint = 1;
  219. BOOL fResult = TRUE;
  220. if ( !notService ) {
  221. ssStatus.dwControlsAccepted = dwCurrentState == SERVICE_RUNNING? SERVICE_ACCEPT_STOP : 0;
  222. ssStatus.dwCurrentState = dwCurrentState;
  223. ssStatus.dwWin32ExitCode = dwWin32ExitCode;
  224. ssStatus.dwWaitHint = dwWaitHint;
  225. if ( dwCurrentState == SERVICE_RUNNING || dwCurrentState == SERVICE_STOPPED )
  226. ssStatus.dwCheckPoint = 0;
  227. else
  228. ssStatus.dwCheckPoint = dwCheckPoint++;
  229. // Report the status of the service to the service control manager.
  230. //
  231. if ( !(fResult = SetServiceStatus( ssHandle, &ssStatus )) ) {
  232. ssErrCode = GetLastError();
  233. PCLogMessage( PC_SERVICE_STATUS_ERROR, EVENTLOG_ERROR_TYPE, 1, PROCCON_SVC_DISP_NAME,
  234. sizeof(ssErrCode), &ssErrCode );
  235. }
  236. }
  237. return fResult;
  238. }
  239. #ifdef _DEBUG
  240. //=============================================================================================
  241. // FUNCTION: PCConsoleService -- run the service as a console application instead.
  242. //
  243. // Input: standard argc, argv
  244. // Returns: no return value
  245. //
  246. void PCConsoleService(int argc, TCHAR **argv) {
  247. notService = TRUE;
  248. SetConsoleCtrlHandler( PCControlHandler, TRUE );
  249. // Set privileges we may need when not a service under LocalSystem...
  250. PCSetPrivilege( SE_DEBUG_NAME, TRUE );
  251. PCSetPrivilege( SE_INC_BASE_PRIORITY_NAME, TRUE );
  252. PCStartService( argc, argv );
  253. }
  254. //=============================================================================================
  255. // function to handle console ctrl-C and break to simulate service stop when in console mode.
  256. //
  257. // Input: control code
  258. // Returns: TRUE if handled, FALSE if not
  259. //
  260. BOOL WINAPI PCControlHandler( PCULONG32 dwCtrlType ) {
  261. switch( dwCtrlType )
  262. {
  263. case CTRL_BREAK_EVENT:
  264. case CTRL_C_EVENT:
  265. PCStopService();
  266. return TRUE;
  267. break;
  268. }
  269. return FALSE;
  270. }
  271. #endif
  272. // End of PCMain.cpp
  273. //============================================================================J McDonald fecit====//