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.

1277 lines
38 KiB

  1. /*
  2. IisRsta.cxx
  3. Command line utility for access to IIisServiceControl
  4. FILE HISTORY:
  5. Phillich 06-Oct-1998 Created
  6. */
  7. #define INITGUID
  8. #include <windows.h>
  9. #include <tchar.h>
  10. #include <stdio.h>
  11. #include <ole2.h>
  12. #include <locale.h>
  13. #include "iisrsta.h"
  14. #include "iisrstam.h"
  15. typedef BOOL (*PFNQUERYSERVICECONFIG2)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD) ;
  16. typedef BOOL (*PFNCHANGESERVICECONFIG2)(SC_HANDLE,DWORD,LPVOID);
  17. //
  18. // HRESULTTOWIN32() maps an HRESULT to a Win32 error. If the facility code
  19. // of the HRESULT is FACILITY_WIN32, then the code portion (i.e. the
  20. // original Win32 error) is returned. Otherwise, the original HRESULT is
  21. // returned unchagned.
  22. //
  23. #define HRESULTTOWIN32(hres) \
  24. ((HRESULT_FACILITY(hres) == FACILITY_WIN32) \
  25. ? HRESULT_CODE(hres) \
  26. : (hres))
  27. //
  28. // RETURNCODETOHRESULT() maps a return code to an HRESULT. If the return
  29. // code is a Win32 error (identified by a zero high word) then it is mapped
  30. // using the standard HRESULT_FROM_WIN32() macro. Otherwise, the return
  31. // code is assumed to already be an HRESULT and is returned unchanged.
  32. //
  33. #define RETURNCODETOHRESULT(rc) \
  34. (((rc) < 0x10000) \
  35. ? HRESULT_FROM_WIN32(rc) \
  36. : (rc))
  37. //
  38. // Helper functions
  39. //
  40. VOID
  41. DisplayErrorMessage(
  42. DWORD dwErr
  43. )
  44. /*++
  45. DisplayErrorMessage
  46. Display error message associated with error code
  47. Arguments:
  48. dwErr - Win32 error code
  49. Returns:
  50. Nothing
  51. --*/
  52. {
  53. LPTSTR pErr;
  54. if ( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  55. NULL,
  56. dwErr,
  57. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  58. (LPTSTR)&pErr,
  59. 0,
  60. NULL ) )
  61. {
  62. LPTSTR p;
  63. if ( p = _tcschr( pErr, TEXT('\r') ) )
  64. {
  65. *p = TEXT('\0');
  66. }
  67. _fputts( pErr, stdout );
  68. LocalFree( pErr );
  69. }
  70. }
  71. VOID
  72. PrintMessage(
  73. DWORD dwId,
  74. DWORD dwParams,
  75. LPVOID* pParams
  76. )
  77. /*++
  78. PrintMessage
  79. Print message ( from message file ) with optional parameters
  80. Arguments:
  81. dwId - message ID
  82. dwParams - # of params in pParams
  83. pParams - ptr to array of parameters
  84. Returns:
  85. Nothing
  86. --*/
  87. {
  88. LPTSTR pBuf;
  89. if ( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_HMODULE|FORMAT_MESSAGE_ARGUMENT_ARRAY,
  90. (LPCVOID)NULL, //GetModuleHandle(NULL),
  91. dwId,
  92. 0,
  93. (LPTSTR)&pBuf,
  94. dwParams,
  95. (va_list *)pParams ) )
  96. {
  97. _fputts( pBuf, stdout );
  98. LocalFree( pBuf );
  99. }
  100. }
  101. VOID
  102. CmdError(
  103. DWORD dwId,
  104. HRESULT hRes
  105. )
  106. /*++
  107. CmdError
  108. Display message followed by error description ( error message + numerical code )
  109. Arguments:
  110. dwId - message ID
  111. hRes - error code
  112. Returns:
  113. Nothing
  114. --*/
  115. {
  116. TCHAR achBuf[128];
  117. PrintMessage( dwId, 0, NULL );
  118. if ( hRes == RETURNCODETOHRESULT( ERROR_RESOURCE_DISABLED ) )
  119. {
  120. PrintMessage( IRSTASTR_REMOTE_DISABLED, 0, NULL );
  121. }
  122. else if ( hRes == RETURNCODETOHRESULT( ERROR_ACCESS_DENIED ) )
  123. {
  124. PrintMessage( IRSTASTR_ACCESS_DENIED, 0, NULL );
  125. }
  126. else if ( hRes == RETURNCODETOHRESULT( ERROR_SERVICE_NOT_ACTIVE ) )
  127. {
  128. PrintMessage( IRSTASTR_IISADMIN_DISABLED, 0, NULL );
  129. }
  130. else
  131. {
  132. DisplayErrorMessage( HRESULTTOWIN32( hRes ) );
  133. wsprintf( achBuf, _T(" (%u, %x)\n"), (DWORD)hRes, (DWORD)hRes );
  134. _fputts( achBuf, stdout );
  135. }
  136. }
  137. LPTSTR
  138. GetString(
  139. DWORD dwId
  140. )
  141. /*++
  142. GetString
  143. Retrieve message content
  144. Arguments:
  145. dwId - message ID
  146. Returns:
  147. Ptr to message. Must be freed using LocalFree()
  148. --*/
  149. {
  150. #if 0
  151. TCHAR aBuf[32];
  152. aBuf[0] = TEXT('#');
  153. _ultot( dwId, aBuf + 1, 10 );
  154. return (LPTSTR)LoadResource( NULL, FindResourceEx( NULL, RT_MESSAGETABLE, aBuf, MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL) ) );
  155. #else
  156. LPTSTR pBuf;
  157. if ( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_HMODULE,
  158. (LPCVOID)NULL,
  159. dwId,
  160. 0,
  161. (LPTSTR)&pBuf,
  162. 0,
  163. NULL ) )
  164. {
  165. LPTSTR p;
  166. if ( p = _tcschr( pBuf, TEXT('\r') ) )
  167. {
  168. *p = TEXT('\0');
  169. }
  170. return pBuf;
  171. }
  172. return NULL;
  173. #endif
  174. }
  175. HRESULT
  176. DeserializeEnumServiceBuffer(
  177. LPBYTE pbInBuffer,
  178. DWORD dwNumServices,
  179. LPBYTE pbBuffer,
  180. DWORD dwBufferSize,
  181. LPDWORD pdwMDRequiredBufferSize
  182. )
  183. /*++
  184. DeserializeEnumServiceBuffer
  185. Deserialize array of SERIALIZED_ENUM_SERVICE_STATUS to buffer,
  186. replacing offset in buffer by ptr
  187. Arguments:
  188. pbInBuffer - buffer containing serialized status as array of SERIALIZED_ENUM_SERVICE_STATUS
  189. dwNumServices - # of entries in pbInBuffer
  190. pbBuffer - buffer filled with deserialized status as array of ENUM_SERVICE_STATUS
  191. dwBufferSize - maximum size of pbBuffer
  192. pdwMDRequiredBufferSize - updated with required size if dwBufferSize too small
  193. Returns:
  194. ERROR_INSUFFICIENT_BUFFER if dwBufferSize too small
  195. otherwise COM status
  196. --*/
  197. {
  198. HRESULT hresReturn = S_OK;
  199. DWORD dwMinSize = 0;
  200. UINT i;
  201. SERIALIZED_ENUM_SERVICE_STATUS* pessDependentServices = (SERIALIZED_ENUM_SERVICE_STATUS*)pbInBuffer;
  202. if ( !pbBuffer )
  203. {
  204. dwBufferSize = 0;
  205. }
  206. dwMinSize = sizeof(ENUM_SERVICE_STATUS) * dwNumServices;
  207. for ( i = 0 ;
  208. i < dwNumServices ;
  209. ++i )
  210. {
  211. UINT cServiceName = _tcslen( (TCHAR*)(pbInBuffer + pessDependentServices[i].iServiceName) ) + 1;
  212. UINT cDisplayName = _tcslen( (TCHAR*)(pbInBuffer + pessDependentServices[i].iDisplayName) ) + 1;
  213. if ( dwBufferSize >= dwMinSize + ( cServiceName + cDisplayName ) * sizeof(TCHAR) )
  214. {
  215. ((LPENUM_SERVICE_STATUS)pbBuffer)[i].ServiceStatus =
  216. pessDependentServices[i].ServiceStatus;
  217. memcpy( pbBuffer + dwMinSize, pbInBuffer + pessDependentServices[i].iServiceName, cServiceName * sizeof(TCHAR) );
  218. ((LPENUM_SERVICE_STATUS)pbBuffer)[i].lpServiceName = (TCHAR*)(pbBuffer + dwMinSize);
  219. memcpy( pbBuffer + dwMinSize + cServiceName * sizeof(TCHAR), pbInBuffer + pessDependentServices[i].iDisplayName, cDisplayName * sizeof(TCHAR) );
  220. ((LPENUM_SERVICE_STATUS)pbBuffer)[i].lpDisplayName = (TCHAR*)(pbBuffer + dwMinSize) + cServiceName;
  221. }
  222. dwMinSize += ( cServiceName + cDisplayName ) * sizeof(TCHAR);
  223. }
  224. if ( dwBufferSize < dwMinSize )
  225. {
  226. *pdwMDRequiredBufferSize = dwMinSize;
  227. hresReturn = RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER );
  228. }
  229. return hresReturn;
  230. }
  231. HRESULT
  232. SetEnableRemote(
  233. DWORD dwValue
  234. )
  235. /*++
  236. SetEnableRemote
  237. set restart I/F enabled flag in registry
  238. ( HKLM\SOFTWARE\Microsoft\INetStp::EnableRestart::REG_DWORD )
  239. Arguments:
  240. dwValue - 0 to disable I/F, !0 to enable
  241. Returns:
  242. status
  243. --*/
  244. {
  245. DWORD dwSt = NO_ERROR;
  246. HKEY hKey;
  247. //
  248. // Check admin privilege by accessing IISADMIN key for write
  249. //
  250. if ( ( dwSt = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  251. TEXT("SYSTEM\\CurrentControlSet\\Services\\IISADMIN"),
  252. 0,
  253. KEY_WRITE,
  254. &hKey ) ) == ERROR_SUCCESS )
  255. {
  256. RegCloseKey( hKey );
  257. //
  258. // Set IISCTL interface access flag in registry
  259. //
  260. if ( ( dwSt = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  261. TEXT("SOFTWARE\\Microsoft\\INetStp"),
  262. 0,
  263. KEY_WRITE,
  264. &hKey ) ) == ERROR_SUCCESS )
  265. {
  266. if ( ( dwSt = RegSetValueEx( hKey,
  267. TEXT("EnableRestart"),
  268. 0,
  269. REG_DWORD,
  270. (const BYTE*)&dwValue,
  271. sizeof(DWORD) ) ) == ERROR_SUCCESS )
  272. {
  273. }
  274. RegCloseKey( hKey );
  275. }
  276. }
  277. return RETURNCODETOHRESULT( dwSt );
  278. }
  279. BOOL
  280. GetNumeric(
  281. LPSTR pszNumArg,
  282. LPDWORD pdwVal
  283. )
  284. {
  285. if ( !isdigit( (UCHAR)(*pszNumArg) ) )
  286. {
  287. return FALSE;
  288. }
  289. *pdwVal = atoi( pszNumArg );
  290. return TRUE;
  291. }
  292. BOOL
  293. IsIIS6orGreater(
  294. )
  295. /*++
  296. IsIIS6orGreater
  297. According to Aaron we are guaranteed to have
  298. the appropriate keys in the registry by the
  299. time iisreset /scm is called.
  300. Arguments:
  301. None
  302. Returns:
  303. TRUE = IIS 6 or greater;
  304. FALSE = anything below IIS 6;
  305. --*/
  306. {
  307. // Assume it is not IIS 6.
  308. BOOL IsIIS6 = FALSE;
  309. HKEY hKey;
  310. DWORD dwValue;
  311. DWORD dwType;
  312. DWORD dwSize;
  313. // Check the registry of the major version setup number.
  314. // If it is not there we assume it is not a 6.0 machine,
  315. // since it's better to setup a 6.0 machine in 5.0 state
  316. // instead of a 5.0 machine in 6.0 state.
  317. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  318. TEXT("System\\CurrentControlSet\\Services\\W3SVC\\Parameters"),
  319. 0,
  320. KEY_READ,
  321. &hKey ) == ERROR_SUCCESS )
  322. {
  323. if ( RegQueryValueEx( hKey,
  324. TEXT("MajorVersion"),
  325. 0,
  326. &dwType,
  327. (LPBYTE)&dwValue,
  328. &dwSize ) == ERROR_SUCCESS )
  329. {
  330. if ( dwType == REG_DWORD )
  331. {
  332. if ( dwValue >= 6 )
  333. {
  334. // were are running on a system that does not
  335. // have atleast IIS 6 on it
  336. IsIIS6 = TRUE;
  337. }
  338. }
  339. }
  340. RegCloseKey( hKey );
  341. }
  342. return IsIIS6;
  343. }
  344. HRESULT
  345. SetSCM(
  346. LPCTSTR pszCmdline,
  347. BOOL fEnable
  348. )
  349. /*++
  350. SetSCM
  351. set SCM Recovery configuration for IISADMIN service.
  352. Does nothing on pre Windows 2000 systems.
  353. Arguments:
  354. pszCmdline - command line to invoke on service failure ( for IISAdmin ), can be NULL to invoke current EXE ( i.e. IISRESET )
  355. fEnable - TRUE to enable IISRESET invocation on service failure, FALSE to disable
  356. Returns:
  357. status
  358. --*/
  359. {
  360. PFNQUERYSERVICECONFIG2 pfnQueryServiceConfig2 = NULL;
  361. PFNCHANGESERVICECONFIG2 pfnChangeServiceConfig2 = NULL;
  362. SERVICE_FAILURE_ACTIONS sfaAction;
  363. SC_ACTION saCmdline[3];
  364. SC_HANDLE schSCM;
  365. SC_HANDLE schSrv;
  366. HRESULT hres = S_OK;
  367. TCHAR achModuleName[MAX_PATH];
  368. TCHAR achFailureCommand[MAX_PATH+32];
  369. HINSTANCE hAdvapi;
  370. if ( hAdvapi = LoadLibrary(_T("ADVAPI32.DLL")) )
  371. {
  372. pfnQueryServiceConfig2 = (PFNQUERYSERVICECONFIG2)GetProcAddress( hAdvapi, "QueryServiceConfig2W" );
  373. pfnChangeServiceConfig2 = (PFNCHANGESERVICECONFIG2)GetProcAddress( hAdvapi, "ChangeServiceConfig2W" );
  374. }
  375. if ( pfnQueryServiceConfig2
  376. && pfnChangeServiceConfig2 )
  377. {
  378. if ( pszCmdline == NULL )
  379. {
  380. if ( !GetModuleFileName( NULL,
  381. achModuleName,
  382. sizeof(achModuleName)/sizeof(TCHAR) ) )
  383. {
  384. hres = RETURNCODETOHRESULT( GetLastError() );
  385. }
  386. else
  387. {
  388. pszCmdline = achModuleName;
  389. }
  390. }
  391. if ( SUCCEEDED( hres ) )
  392. {
  393. schSCM = OpenSCManager(NULL,
  394. NULL,
  395. SC_MANAGER_ALL_ACCESS);
  396. if ( schSCM == NULL )
  397. {
  398. hres = RETURNCODETOHRESULT( GetLastError() );
  399. }
  400. else
  401. {
  402. // We need to determine what IIS version we are running on
  403. // in order to know the correct way to setup the server.
  404. BOOL fIIS6orGreater = IsIIS6orGreater();
  405. //
  406. // In IIS 5.1 we want to use the default /restart
  407. // setting of iisreset. In IIS 6 or greater we
  408. // want to use the /start option. A customer
  409. // can configure it to use the /restart option, but
  410. // that is not the default for the scm.
  411. //
  412. if ( fIIS6orGreater )
  413. {
  414. wsprintf( achFailureCommand, _T("\"%s\" /start /fail=%%1%%"), pszCmdline );
  415. }
  416. else
  417. {
  418. wsprintf( achFailureCommand, _T("\"%s\" /fail=%%1%%"), pszCmdline );
  419. }
  420. sfaAction.lpCommand = achFailureCommand;
  421. sfaAction.lpRebootMsg = _T("");
  422. sfaAction.dwResetPeriod = 24 * 60 * 60;
  423. if ( fEnable )
  424. {
  425. sfaAction.cActions = 3;
  426. sfaAction.lpsaActions = saCmdline;
  427. saCmdline[0].Type = SC_ACTION_RUN_COMMAND;
  428. saCmdline[0].Delay = 1;
  429. saCmdline[1].Type = SC_ACTION_RUN_COMMAND;
  430. saCmdline[1].Delay = 1;
  431. saCmdline[2].Type = SC_ACTION_RUN_COMMAND;
  432. saCmdline[2].Delay = 1;
  433. }
  434. else
  435. {
  436. sfaAction.cActions = 3;
  437. sfaAction.lpsaActions = saCmdline;
  438. saCmdline[0].Type = SC_ACTION_NONE;
  439. saCmdline[0].Delay = 0;
  440. saCmdline[1].Type = SC_ACTION_NONE;
  441. saCmdline[1].Delay = 0;
  442. saCmdline[2].Type = SC_ACTION_NONE;
  443. saCmdline[2].Delay = 0;
  444. }
  445. schSrv = OpenService( schSCM,
  446. _T("IISADMIN"),
  447. SERVICE_ALL_ACCESS);
  448. if ( schSrv )
  449. {
  450. if ( !pfnChangeServiceConfig2( schSrv,
  451. SERVICE_CONFIG_FAILURE_ACTIONS,
  452. &sfaAction ) )
  453. {
  454. hres = RETURNCODETOHRESULT( GetLastError() );
  455. }
  456. CloseServiceHandle( schSrv );
  457. }
  458. else
  459. {
  460. hres = RETURNCODETOHRESULT( GetLastError() );
  461. }
  462. //
  463. // Now that we have configured IISAdmin correctly, we also need to
  464. // configure W3SVC.
  465. //
  466. if ( fIIS6orGreater )
  467. {
  468. sfaAction.lpCommand = NULL;
  469. sfaAction.lpRebootMsg = _T("");
  470. sfaAction.dwResetPeriod = 24 * 60 * 60;
  471. if ( fEnable )
  472. {
  473. sfaAction.cActions = 3;
  474. sfaAction.lpsaActions = saCmdline;
  475. saCmdline[0].Type = SC_ACTION_RESTART;
  476. saCmdline[0].Delay = 1;
  477. saCmdline[1].Type = SC_ACTION_RESTART;
  478. saCmdline[1].Delay = 1;
  479. saCmdline[2].Type = SC_ACTION_RESTART;
  480. saCmdline[2].Delay = 1;
  481. }
  482. else
  483. {
  484. sfaAction.cActions = 3;
  485. sfaAction.lpsaActions = saCmdline;
  486. saCmdline[0].Type = SC_ACTION_NONE;
  487. saCmdline[0].Delay = 0;
  488. saCmdline[1].Type = SC_ACTION_NONE;
  489. saCmdline[1].Delay = 0;
  490. saCmdline[2].Type = SC_ACTION_NONE;
  491. saCmdline[2].Delay = 0;
  492. }
  493. schSrv = OpenService( schSCM,
  494. _T("W3SVC"),
  495. SERVICE_ALL_ACCESS);
  496. if ( schSrv )
  497. {
  498. if ( !pfnChangeServiceConfig2( schSrv,
  499. SERVICE_CONFIG_FAILURE_ACTIONS,
  500. &sfaAction ) )
  501. {
  502. hres = RETURNCODETOHRESULT( GetLastError() );
  503. }
  504. CloseServiceHandle( schSrv );
  505. }
  506. else
  507. {
  508. hres = RETURNCODETOHRESULT( GetLastError() );
  509. }
  510. } // end of setting up restart on w3svc.
  511. CloseServiceHandle( schSCM );
  512. }
  513. }
  514. }
  515. if ( hAdvapi )
  516. {
  517. FreeLibrary( hAdvapi );
  518. }
  519. return hres;
  520. }
  521. enum CMDS { CMD_NONE, CMD_START, CMD_STOP, CMD_REBOOT, CMD_RESTART, CMD_KILL };
  522. int __cdecl
  523. main(
  524. int argc,
  525. char*argv[]
  526. )
  527. /*++
  528. main
  529. main function
  530. Arguments:
  531. argc
  532. argv
  533. Returns:
  534. 0 if no error, otherwise error code
  535. --*/
  536. {
  537. IIisServiceControl* pIf;
  538. int iA;
  539. int Status = 0;
  540. HRESULT hRes;
  541. CMDS iCmd = CMD_NONE;
  542. DWORD dwStopTimeout = 60 * 1000;
  543. DWORD dwRestartTimeout = 20 * 1000;
  544. DWORD dwStartTimeout = 60 * 1000;
  545. LPBYTE pbBuffer;
  546. BYTE abBuffer[4096];
  547. LPBYTE pbOutBuffer;
  548. BYTE abOutBuffer[4096];
  549. DWORD dwRequired;
  550. DWORD dwNumServices;
  551. LPVOID apvParams[8];
  552. UINT i;
  553. BOOL fNoCmd = FALSE;
  554. BOOL fRebootOnError = FALSE;
  555. BOOL fKillOnError = TRUE;
  556. BOOL fForce = TRUE;
  557. BOOL fRebootRestart = FALSE;
  558. BOOL fStatus = FALSE;
  559. COSERVERINFO csiMachineName;
  560. MULTI_QI rgmq;
  561. WCHAR awchComputer[64];
  562. LPSTR pszMachineName = NULL;
  563. BOOL fErrDisplayed = FALSE;
  564. DWORD dwFailCount;
  565. //
  566. // Make sure international versions display text ok - RonaldM
  567. //
  568. _tsetlocale( LC_ALL, _T(".OCP") );
  569. _fputts( _T("\n"), stdout );
  570. //
  571. // scan command line
  572. //
  573. for ( iA = 1 ;
  574. iA < argc ;
  575. ++iA )
  576. {
  577. if ( argv[iA][0] == '-' || argv[iA][0] == '/' )
  578. {
  579. if ( !lstrcmpiA( argv[iA]+1, "ENABLE" ) )
  580. {
  581. hRes = SetEnableRemote( 1 );
  582. if ( FAILED( hRes ) )
  583. {
  584. if ( hRes == RETURNCODETOHRESULT( ERROR_ACCESS_DENIED ) )
  585. {
  586. PrintMessage( IRSTASTR_ACCESS_DENIED, 0, NULL );
  587. }
  588. else
  589. {
  590. DisplayErrorMessage( HRESULTTOWIN32( hRes ) );
  591. }
  592. Status = HRESULTTOWIN32( hRes );
  593. }
  594. else
  595. {
  596. PrintMessage( IRSTASTR_ENABLED, 0, NULL );
  597. }
  598. fNoCmd = TRUE;
  599. }
  600. else if ( !lstrcmpiA( argv[iA]+1, "DISABLE" ) )
  601. {
  602. hRes = SetEnableRemote( 0 );
  603. if ( FAILED( hRes ) )
  604. {
  605. if ( hRes == RETURNCODETOHRESULT( ERROR_ACCESS_DENIED ) )
  606. {
  607. PrintMessage( IRSTASTR_ACCESS_DENIED, 0, NULL );
  608. }
  609. else
  610. {
  611. DisplayErrorMessage( HRESULTTOWIN32( hRes ) );
  612. }
  613. Status = HRESULTTOWIN32( hRes );
  614. }
  615. else
  616. {
  617. PrintMessage( IRSTASTR_DISABLED, 0, NULL );
  618. }
  619. fNoCmd = TRUE;
  620. }
  621. else if ( !_strnicmp( argv[iA]+1, "SCM", sizeof("SCM")-1 ) )
  622. {
  623. if ( FAILED( hRes = SetSCM( NULL, TRUE ) ) )
  624. {
  625. DisplayErrorMessage( HRESULTTOWIN32( hRes ) );
  626. Status = HRESULTTOWIN32( hRes );
  627. }
  628. goto Exit;
  629. }
  630. else if ( !_strnicmp( argv[iA]+1, "NOSCM", sizeof("NOSCM")-1 ) )
  631. {
  632. if ( FAILED( hRes = SetSCM( NULL, FALSE ) ) )
  633. {
  634. DisplayErrorMessage( HRESULTTOWIN32( hRes ) );
  635. Status = HRESULTTOWIN32( hRes );
  636. }
  637. goto Exit;
  638. }
  639. else if ( !_strnicmp( argv[iA]+1, "STOPTIMEOUT:", sizeof("STOPTIMEOUT:")-1 ) )
  640. {
  641. if ( !GetNumeric( argv[iA]+ 1 + sizeof("STOPTIMEOUT:") - 1, &dwStopTimeout ) )
  642. {
  643. goto invalid_param;
  644. }
  645. dwStopTimeout *= 1000;
  646. }
  647. else if ( !_strnicmp( argv[iA]+1, "TIMEOUT:", sizeof("TIMEOUT:")-1 ) )
  648. {
  649. if ( !GetNumeric( argv[iA]+ 1 + sizeof("TIMEOUT:") - 1, &dwStopTimeout ) )
  650. {
  651. goto invalid_param;
  652. }
  653. dwStopTimeout *= 1000;
  654. dwRestartTimeout = dwStopTimeout;
  655. }
  656. else if ( !_strnicmp( argv[iA]+1, "STARTTIMEOUT:", sizeof("STARTTIMEOUT:")-1 ) )
  657. {
  658. if ( !GetNumeric( argv[iA]+ 1 + sizeof("STARTTIMEOUT:") - 1, &dwStartTimeout ) )
  659. {
  660. goto invalid_param;
  661. }
  662. dwStartTimeout *= 1000;
  663. }
  664. else if ( !_strnicmp( argv[iA]+1, "RESTARTTIMEOUT:", sizeof("RESTARTTIMEOUT:")-1 ) )
  665. {
  666. if ( !GetNumeric( argv[iA]+ 1 + sizeof("RESTARTTIMEOUT:") - 1, &dwRestartTimeout ) )
  667. {
  668. goto invalid_param;
  669. }
  670. dwRestartTimeout *= 1000;
  671. }
  672. else if ( !_strnicmp( argv[iA]+1, "fail=", sizeof("fail=")-1 ) )
  673. {
  674. //
  675. // SCM flag to control restart threshold. We restart only
  676. // 50 times per SCM restart period.
  677. //
  678. // ... The SCM UI already has a way to address this: they add
  679. // a "/fail=N" parameter to the command line
  680. // of the restarter app for each time they fail within the time
  681. // period and leave it up to the restarter app to interpret
  682. // this parameter and throttle restarts approprately.
  683. // So...(here's the change request) we need to capture this
  684. // value, and if "N" is greater than our limit for 1 day of
  685. // restarting (hardcoded to 50), we should just exit the
  686. // command line app with a success code without doing anything,
  687. // i.e. "IISRESET.EXE /fail=50" should restart IIS,
  688. // but "IISRESET.EXE /fail=51" should be a no-op.
  689. // For simplicity, we should hardcode this value of 50 in
  690. // our app-- if a user wants a different value, he can write
  691. // a batch file wrapper to do it! You can see
  692. // the SCM recovery tab for more info.
  693. //
  694. dwFailCount = atoi( argv[iA]+ 1 + sizeof("fail=") - 1 );
  695. if ( dwFailCount > 50 )
  696. {
  697. return 0;
  698. }
  699. }
  700. else if ( !lstrcmpiA( argv[iA]+1, "START" ) )
  701. {
  702. if ( fRebootRestart )
  703. {
  704. }
  705. else if ( iCmd == CMD_STOP )
  706. {
  707. iCmd = CMD_RESTART;
  708. }
  709. else
  710. {
  711. iCmd = CMD_START;
  712. }
  713. }
  714. else if ( !lstrcmpiA( argv[iA]+1, "STOP" ) )
  715. {
  716. if ( fRebootRestart )
  717. {
  718. }
  719. if ( iCmd == CMD_START )
  720. {
  721. iCmd = CMD_RESTART;
  722. }
  723. else
  724. {
  725. iCmd = CMD_STOP;
  726. }
  727. }
  728. else if ( !lstrcmpiA( argv[iA]+1, "REBOOT" ) )
  729. {
  730. iCmd = CMD_REBOOT;
  731. fRebootRestart = TRUE;
  732. }
  733. else if ( !lstrcmpiA( argv[iA]+1, "KILL" ) )
  734. {
  735. iCmd = CMD_KILL;
  736. fRebootRestart = TRUE;
  737. }
  738. else if ( !lstrcmpiA( argv[iA]+1, "RESTART" ) )
  739. {
  740. iCmd = CMD_RESTART;
  741. fRebootRestart = TRUE;
  742. }
  743. else if ( !lstrcmpiA( argv[iA]+1, "STATUS" ) )
  744. {
  745. fStatus = TRUE;
  746. }
  747. else if ( !lstrcmpiA( argv[iA]+1, "REBOOTONERROR" ) )
  748. {
  749. fRebootOnError = TRUE;
  750. fKillOnError = FALSE;
  751. }
  752. else if ( !lstrcmpiA( argv[iA]+1, "NOFORCE" ) )
  753. {
  754. fKillOnError = FALSE;
  755. fForce = FALSE;
  756. }
  757. else if ( !lstrcmpiA( argv[iA]+1, "HELP" ) )
  758. {
  759. PrintMessage( IRSTASTR_USAGE, 0, NULL );
  760. return 0;
  761. }
  762. else
  763. {
  764. invalid_param:
  765. PrintMessage( IRSTASTR_USAGE, 0, NULL );
  766. return ERROR_INVALID_PARAMETER;
  767. }
  768. }
  769. else
  770. {
  771. pszMachineName = argv[iA];
  772. }
  773. }
  774. if ( iCmd == CMD_NONE && !fNoCmd && !fStatus )
  775. {
  776. iCmd = CMD_RESTART;
  777. }
  778. //
  779. //fill the structure for CoCreateInstanceEx
  780. //
  781. ZeroMemory( &csiMachineName, sizeof(csiMachineName) );
  782. if ( pszMachineName )
  783. {
  784. if ( !MultiByteToWideChar( CP_ACP,
  785. MB_PRECOMPOSED,
  786. pszMachineName,
  787. -1,
  788. awchComputer,
  789. sizeof(awchComputer) / sizeof(WCHAR)) )
  790. {
  791. return GetLastError();
  792. }
  793. csiMachineName.pwszName = awchComputer;
  794. }
  795. else
  796. {
  797. csiMachineName.pwszName = NULL;
  798. }
  799. if ( fNoCmd )
  800. {
  801. iCmd = CMD_NONE;
  802. fStatus = FALSE;
  803. }
  804. if ( iCmd != CMD_NONE || fStatus )
  805. {
  806. BOOL fCoInitialized = true;
  807. //
  808. // call method
  809. //
  810. rgmq.pIID = &IID_IIisServiceControl;
  811. rgmq.pItf = NULL;
  812. rgmq.hr = 0;
  813. if (FAILED(hRes = CoInitializeEx( NULL, COINIT_MULTITHREADED ))) {
  814. fCoInitialized = false;
  815. }
  816. else if ( SUCCEEDED( hRes = CoCreateInstanceEx( CLSID_IisServiceControl,
  817. NULL,
  818. CLSCTX_SERVER,
  819. &csiMachineName,
  820. 1,
  821. &rgmq ) ) &&
  822. SUCCEEDED( hRes = rgmq.hr ) )
  823. {
  824. pIf = (IIisServiceControl*)rgmq.pItf;
  825. switch ( iCmd )
  826. {
  827. case CMD_START:
  828. PrintMessage( IRSTASTR_START_ATTEMPT, 0, NULL );
  829. hRes = pIf->Start( dwStartTimeout );
  830. if ( SUCCEEDED( hRes ) )
  831. {
  832. PrintMessage( IRSTASTR_START_SUCCESS, 0, NULL );
  833. }
  834. else
  835. {
  836. CmdError( IRSTASTR_START_FAILED, hRes );
  837. fErrDisplayed = TRUE;
  838. }
  839. break;
  840. case CMD_STOP:
  841. PrintMessage( IRSTASTR_STOP_ATTEMPT, 0, NULL );
  842. hRes = pIf->Stop( dwStopTimeout, fKillOnError );
  843. if ( SUCCEEDED( hRes ) )
  844. {
  845. PrintMessage( IRSTASTR_STOP_SUCCESS, 0, NULL );
  846. }
  847. else
  848. {
  849. CmdError( IRSTASTR_STOP_FAILED, hRes );
  850. fErrDisplayed = TRUE;
  851. }
  852. break;
  853. case CMD_REBOOT:
  854. PrintMessage( IRSTASTR_REBOOT_ATTEMPT, 0, NULL );
  855. hRes = pIf->Reboot( dwRestartTimeout, fForce );
  856. if ( SUCCEEDED( hRes ) )
  857. {
  858. PrintMessage( IRSTASTR_REBOOT_SUCCESS, 0, NULL );
  859. }
  860. else
  861. {
  862. CmdError( IRSTASTR_REBOOT_FAILED, hRes );
  863. fErrDisplayed = TRUE;
  864. }
  865. break;
  866. case CMD_KILL:
  867. PrintMessage( IRSTASTR_KILL_ON_ERROR, 0, NULL );
  868. hRes = pIf->Kill();
  869. if ( SUCCEEDED( hRes ) )
  870. {
  871. PrintMessage( IRSTASTR_KILL_SUCCESS, 0, NULL );
  872. }
  873. else
  874. {
  875. CmdError( IRSTASTR_KILL_FAILED, hRes );
  876. fErrDisplayed = TRUE;
  877. }
  878. break;
  879. case CMD_RESTART:
  880. PrintMessage( IRSTASTR_STOP_ATTEMPT, 0, NULL );
  881. hRes = pIf->Stop( dwRestartTimeout, fKillOnError );
  882. if ( SUCCEEDED( hRes ) )
  883. {
  884. PrintMessage( IRSTASTR_STOP_SUCCESS, 0, NULL );
  885. PrintMessage( IRSTASTR_START_ATTEMPT, 0, NULL );
  886. hRes = pIf->Start( dwStartTimeout );
  887. if ( SUCCEEDED( hRes ) )
  888. {
  889. PrintMessage( IRSTASTR_RESTART_SUCCESS, 0, NULL );
  890. }
  891. }
  892. if ( FAILED( hRes ) )
  893. {
  894. CmdError( IRSTASTR_RESTART_FAILED, hRes );
  895. fErrDisplayed = TRUE;
  896. }
  897. break;
  898. }
  899. if ( fStatus )
  900. {
  901. pbBuffer = NULL;
  902. fErrDisplayed = FALSE;
  903. if ( FAILED( hRes = pIf->Status( sizeof(abBuffer),
  904. abBuffer,
  905. &dwRequired,
  906. &dwNumServices ) ) )
  907. {
  908. if ( RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER ) == hRes )
  909. {
  910. if ( (pbBuffer = (LPBYTE)LocalAlloc( LMEM_FIXED, dwRequired )) == NULL )
  911. {
  912. hRes = RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
  913. }
  914. else
  915. {
  916. hRes = pIf->Status( dwRequired,
  917. pbBuffer,
  918. &dwRequired,
  919. &dwNumServices );
  920. }
  921. }
  922. }
  923. else
  924. {
  925. pbBuffer = abBuffer;
  926. }
  927. if ( SUCCEEDED( hRes ) )
  928. {
  929. pbOutBuffer = NULL;
  930. if ( FAILED( hRes = DeserializeEnumServiceBuffer( pbBuffer,
  931. dwNumServices,
  932. abOutBuffer,
  933. sizeof(abOutBuffer),
  934. &dwRequired ) ) )
  935. {
  936. if ( RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER ) == hRes )
  937. {
  938. if ( (pbOutBuffer = (LPBYTE)LocalAlloc( LMEM_FIXED, dwRequired )) == NULL )
  939. {
  940. hRes = RETURNCODETOHRESULT( ERROR_NOT_ENOUGH_MEMORY );
  941. }
  942. else
  943. {
  944. hRes = DeserializeEnumServiceBuffer( pbBuffer,
  945. dwNumServices,
  946. pbOutBuffer,
  947. dwRequired,
  948. &dwRequired );
  949. }
  950. }
  951. }
  952. else
  953. {
  954. pbOutBuffer = abOutBuffer;
  955. }
  956. }
  957. if ( SUCCEEDED( hRes ) )
  958. {
  959. for ( i = 0 ; i < dwNumServices ; ++i )
  960. {
  961. apvParams[0] = ((LPENUM_SERVICE_STATUS)pbOutBuffer)[i].lpDisplayName;
  962. apvParams[1] = ((LPENUM_SERVICE_STATUS)pbOutBuffer)[i].lpServiceName;
  963. switch ( ((LPENUM_SERVICE_STATUS)pbOutBuffer)[i].ServiceStatus.dwCurrentState )
  964. {
  965. case SERVICE_STOPPED:
  966. apvParams[2] = GetString(IRSTASTR_SERVICE_STOPPED); break;
  967. case SERVICE_START_PENDING:
  968. apvParams[2] = GetString(IRSTASTR_SERVICE_START_PENDING); break;
  969. case SERVICE_STOP_PENDING:
  970. apvParams[2] = GetString(IRSTASTR_SERVICE_STOP_PENDING); break;
  971. case SERVICE_RUNNING:
  972. apvParams[2] = GetString(IRSTASTR_SERVICE_RUNNING); break;
  973. case SERVICE_CONTINUE_PENDING:
  974. apvParams[2] = GetString(IRSTASTR_SERVICE_CONTINUE_PENDING); break;
  975. case SERVICE_PAUSE_PENDING:
  976. apvParams[2] = GetString(IRSTASTR_SERVICE_PAUSE_PENDING); break;
  977. case SERVICE_PAUSED:
  978. apvParams[2] = GetString(IRSTASTR_SERVICE_PAUSED); break;
  979. default:
  980. apvParams[2] = GetString(IRSTASTR_SERVICE_DEFAULT); break;
  981. }
  982. PrintMessage( IRSTASTR_STATUS_ITEM, 3, apvParams );
  983. }
  984. }
  985. if ( pbBuffer != NULL && pbBuffer != abBuffer )
  986. {
  987. LocalFree( pbBuffer );
  988. }
  989. if ( pbOutBuffer != NULL && pbOutBuffer != abOutBuffer )
  990. {
  991. LocalFree( pbOutBuffer );
  992. }
  993. }
  994. if ( FAILED( hRes ) && fRebootOnError
  995. && ( iCmd == CMD_STOP || iCmd == CMD_RESTART ) )
  996. {
  997. fErrDisplayed = FALSE;
  998. PrintMessage( IRSTASTR_REBOOT_ON_ERROR, 0, NULL );
  999. hRes = pIf->Reboot( 0, fForce );
  1000. if ( SUCCEEDED( hRes ) )
  1001. {
  1002. PrintMessage( IRSTASTR_REBOOT_SUCCESS, 0, NULL );
  1003. }
  1004. }
  1005. #if 0
  1006. if ( FAILED( hRes ) && fKillOnError
  1007. && ( iCmd == CMD_STOP || iCmd == CMD_RESTART ) )
  1008. {
  1009. fErrDisplayed = FALSE;
  1010. PrintMessage( IRSTASTR_KILL_ON_ERROR, 0, NULL );
  1011. hRes = pIf->Kill();
  1012. if ( SUCCEEDED( hRes ) )
  1013. {
  1014. PrintMessage( IRSTASTR_KILL_SUCCESS, 0, NULL );
  1015. }
  1016. }
  1017. #endif
  1018. pIf->Release();
  1019. if ( FAILED( hRes ) )
  1020. {
  1021. if ( !fErrDisplayed )
  1022. {
  1023. if ( hRes == RETURNCODETOHRESULT( ERROR_RESOURCE_DISABLED ) )
  1024. {
  1025. PrintMessage( IRSTASTR_REMOTE_DISABLED, 0, NULL );
  1026. }
  1027. else if ( hRes == RETURNCODETOHRESULT( ERROR_ACCESS_DENIED ) )
  1028. {
  1029. PrintMessage( IRSTASTR_ACCESS_DENIED, 0, NULL );
  1030. }
  1031. else
  1032. {
  1033. DisplayErrorMessage( HRESULTTOWIN32( hRes ) );
  1034. }
  1035. }
  1036. Status = HRESULTTOWIN32( hRes );
  1037. }
  1038. }
  1039. else
  1040. {
  1041. if ( hRes == RETURNCODETOHRESULT( ERROR_ACCESS_DENIED ) )
  1042. {
  1043. PrintMessage( IRSTASTR_ACCESS_DENIED, 0, NULL );
  1044. }
  1045. else
  1046. {
  1047. DisplayErrorMessage( HRESULTTOWIN32( hRes ) );
  1048. }
  1049. Status = HRESULTTOWIN32( hRes );
  1050. }
  1051. if (fCoInitialized) {
  1052. CoUninitialize();
  1053. }
  1054. }
  1055. Exit:
  1056. return Status;
  1057. }