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.

2511 lines
66 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. main.c
  5. Abstract:
  6. This is the main thread for the File Replication Service.
  7. Author:
  8. Billy J. Fuller 20-Mar-1997
  9. Environment
  10. User mode winnt
  11. --*/
  12. #include <ntreppch.h>
  13. #pragma hdrstop
  14. #include <frs.h>
  15. #include <tablefcn.h>
  16. #include <perrepsr.h>
  17. #include <objbase.h>
  18. #define INITGUID
  19. #include "frstrace.h"
  20. PCHAR LatestChanges[] = {
  21. "Latest changes:",
  22. "Server 2003 01-07-2003",
  23. #ifdef DS_FREE
  24. "DS_FREE mode",
  25. #endif DS_FREE
  26. NULL
  27. };
  28. HANDLE ShutDownEvent;
  29. HANDLE ShutDownComplete;
  30. HANDLE DataBaseEvent;
  31. HANDLE JournalEvent;
  32. HANDLE ChgOrdEvent;
  33. HANDLE ReplicaEvent;
  34. HANDLE CommEvent;
  35. HANDLE DsPollEvent;
  36. HANDLE DsShutDownComplete;
  37. //
  38. // Event to signal the end of freeze operation.
  39. //
  40. HANDLE FrsThawEvent;
  41. BOOL FrsFrozenForBackup = FALSE;
  42. //
  43. // Event to signal that there are no installs in
  44. // progress.
  45. //
  46. HANDLE FrsNoInstallsInProgressEvent;
  47. PWCHAR ServerPrincName;
  48. BOOL IsAMember = FALSE;
  49. BOOL IsADc = FALSE;
  50. BOOL IsAPrimaryDc = FALSE;
  51. BOOL EventLogIsRunning = FALSE;
  52. BOOL RpcssIsRunning = FALSE;
  53. BOOL RunningAsAService = TRUE;
  54. BOOL NoDs = FALSE;
  55. BOOL FrsIsShuttingDown = FALSE;
  56. BOOL FrsScmRequestedShutdown = FALSE;
  57. BOOL FrsIsAsserting = FALSE;
  58. //
  59. // Require mutual authentication
  60. //
  61. BOOL MutualAuthenticationIsEnabled;
  62. BOOL MutualAuthenticationIsEnabledAndRequired;
  63. //
  64. // Directory and file filter lists from registry.
  65. //
  66. PWCHAR RegistryFileExclFilterList;
  67. PWCHAR RegistryFileInclFilterList;
  68. PWCHAR RegistryDirExclFilterList;
  69. PWCHAR RegistryDirInclFilterList;
  70. extern CRITICAL_SECTION CritSec_pValidPartnerTableStruct;
  71. extern CRITICAL_SECTION OldValidPartnerTableStructListHeadLock;
  72. //
  73. // Synchronize the shutdown thread with the service controller
  74. //
  75. CRITICAL_SECTION ServiceLock;
  76. //
  77. // Synchronize initialization
  78. //
  79. CRITICAL_SECTION MainInitLock;
  80. //
  81. // Convert the ANSI ArgV into a UNICODE ArgV
  82. //
  83. PWCHAR *WideArgV;
  84. //
  85. // Process Handle
  86. //
  87. HANDLE ProcessHandle;
  88. //
  89. // Working path / DB Log path
  90. //
  91. PWCHAR WorkingPath;
  92. PWCHAR DbLogPath;
  93. //
  94. // Database directories (UNICODE and ASCII)
  95. //
  96. PWCHAR JetPath;
  97. PWCHAR JetFile;
  98. PWCHAR JetFileCompact;
  99. PWCHAR JetSys;
  100. PWCHAR JetTemp;
  101. PWCHAR JetLog;
  102. PCHAR JetPathA;
  103. PCHAR JetFileA;
  104. PCHAR JetFileCompactA;
  105. PCHAR JetSysA;
  106. PCHAR JetTempA;
  107. PCHAR JetLogA;
  108. //
  109. // Limit the amount of staging area used (in kilobytes). This is
  110. // a soft limit, the actual usage may be higher.
  111. //
  112. DWORD StagingLimitInKb;
  113. //
  114. // Default staging limit in kb to be assigned to a new staging area.
  115. //
  116. DWORD DefaultStagingLimitInKb;
  117. //
  118. // Max number replica sets and Jet Sessions allowed.
  119. //
  120. ULONG MaxNumberReplicaSets;
  121. ULONG MaxNumberJetSessions;
  122. //
  123. // Maximum number of outbound changeorders allowed outstanding per connection.
  124. //
  125. ULONG MaxOutLogCoQuota;
  126. //
  127. // If TRUE then try to preserve existing file OIDs whenever possible.
  128. // -- See Bug 352250 for why this is a risky thing to do.
  129. //
  130. BOOL PreserveFileOID;
  131. //
  132. // Limits on how many time and for how long we will continue to retry a
  133. // change order when the parent is missing.
  134. //
  135. ULONG MaxCoRetryTimeoutMinutes;
  136. ULONG MaxCoRetryTimeoutCount;
  137. //
  138. // Major/minor (see frs.h)
  139. //
  140. ULONG NtFrsMajor = NTFRS_MAJOR;
  141. ULONG NtFrsMinor = NTFRS_MINOR;
  142. ULONG NtFrsStageMajor = NTFRS_STAGE_MAJOR;
  143. ULONG NtFrsStageMinor = NTFRS_STAGE_MINOR_3;
  144. ULONG NtFrsCommMinor = NTFRS_COMM_MINOR_8;
  145. ULONG NtFrsPerfCounterVer = NTFRS_PERF_COUNTER_VER_1;
  146. PCHAR NtFrsModule = __FILE__;
  147. PCHAR NtFrsDate = __DATE__;
  148. PCHAR NtFrsTime = __TIME__;
  149. //
  150. // Shutdown timeout
  151. //
  152. ULONG ShutDownTimeOut = DEFAULT_SHUTDOWN_TIMEOUT;
  153. //
  154. // A useful thing to have around
  155. //
  156. WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 2];
  157. PWCHAR ComputerDnsName;
  158. PWCHAR ServiceLongName;
  159. //
  160. // The rpc server may reference this table as soon as the rpc interface
  161. // is registered. Make sure it is setup.
  162. //
  163. extern PGEN_TABLE ReplicasByGuid;
  164. extern BOOL LockedOutlogCleanup;
  165. //
  166. // The staging area table is references early in the startup process
  167. //
  168. extern PGEN_TABLE StagingAreaTable;
  169. extern CRITICAL_SECTION StagingAreaCleanupLock;
  170. //
  171. // This table is used to keep contexts across multiple calls from ntfrsutl.exe
  172. //
  173. extern PGEN_TABLE FrsInfoContextTable;
  174. PGEN_TABLE CompressionTable;
  175. extern PGEN_TABLE ReparseTagTable;
  176. //
  177. // Size of buffer to use when enumerating directories. Actual memory
  178. // usage will be #levels * SizeOfBuffer.
  179. //
  180. LONG EnumerateDirectorySizeInBytes;
  181. BOOL MainInitHasRun;
  182. //
  183. // Do not accept stop control unless the service is in SERVICE_RUNNING state.
  184. // This prevents the service from getting confused when a stop is called
  185. // while the service is starting.
  186. //
  187. SERVICE_STATUS ServiceStatus = {
  188. SERVICE_WIN32_OWN_PROCESS,
  189. SERVICE_START_PENDING,
  190. // SERVICE_ACCEPT_STOP |
  191. // SERVICE_ACCEPT_PAUSE_CONTINUE |
  192. SERVICE_ACCEPT_SHUTDOWN,
  193. 0,
  194. 0,
  195. 0,
  196. 60*1000
  197. };
  198. //
  199. // Supported compression formats.
  200. //
  201. //
  202. // This is the compression format for uncompressed data.
  203. //
  204. DEFINE_GUID ( /* 00000000-0000-0000-0000-000000000000 */
  205. FrsGuidCompressionFormatNone,
  206. 0x00000000,
  207. 0x0000,
  208. 0x0000,
  209. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  210. );
  211. //
  212. // This is the compression format for data compressed using NTFS's LZNT1 compression
  213. // routines.
  214. //
  215. DEFINE_GUID ( /* 64d2f7d2-2695-436d-8830-8d3c58701e15 */
  216. FrsGuidCompressionFormatLZNT1,
  217. 0x64d2f7d2,
  218. 0x2695,
  219. 0x436d,
  220. 0x88, 0x30, 0x8d, 0x3c, 0x58, 0x70, 0x1e, 0x15
  221. );
  222. //
  223. // Fixed guid for the dummy cxtion (aka GhostCxtion) assigned to orphan remote
  224. // change orders whose inbound cxtion has been deleted from the DS but they
  225. // have already past the fetching state and can finish without the real cxtion
  226. // coming back. No authentication checks are made for this dummy cxtion.
  227. //
  228. DEFINE_GUID ( /* b9d307a7-a140-4405-991e-281033f03309 */
  229. FrsGuidGhostCxtion,
  230. 0xb9d307a7,
  231. 0xa140,
  232. 0x4405,
  233. 0x99, 0x1e, 0x28, 0x10, 0x33, 0xf0, 0x33, 0x09
  234. );
  235. DEFINE_GUID ( /* 3fe2820f-3045-4932-97fe-00d10b746dbf */
  236. FrsGhostJoinGuid,
  237. 0x3fe2820f,
  238. 0x3045,
  239. 0x4932,
  240. 0x97, 0xfe, 0x00, 0xd1, 0x0b, 0x74, 0x6d, 0xbf
  241. );
  242. //
  243. // Static Ghost cxtion structure. This cxtion is assigned to orphan remote change
  244. // orders in the inbound log whose cxtion is deleted from the DS but who have already
  245. // past the fetching state and do not need the cxtion to complete processing. No
  246. // authentication checks are made for this dummy cxtion.
  247. //
  248. PCXTION FrsGhostCxtion;
  249. SERVICE_STATUS_HANDLE ServiceStatusHandle = NULL;
  250. VOID
  251. InitializeEventLog(
  252. VOID
  253. );
  254. DWORD
  255. FrsSetServiceFailureAction(
  256. VOID
  257. );
  258. VOID
  259. FrsRpcInitializeAccessChecks(
  260. VOID
  261. );
  262. BOOL
  263. FrsSetupPrivileges (
  264. VOID
  265. );
  266. VOID
  267. CfgRegAdjustTuningDefaults(
  268. VOID
  269. );
  270. VOID
  271. CommInitializeCommSubsystem(
  272. VOID
  273. );
  274. VOID
  275. SndCsInitialize(
  276. VOID
  277. );
  278. VOID
  279. SndCsUnInitialize(
  280. VOID
  281. );
  282. VOID
  283. SndCsShutDown(
  284. VOID
  285. );
  286. VOID
  287. DbgPrintAllStats(
  288. VOID
  289. );
  290. // FRS Capacity Planning
  291. //
  292. #define RESOURCE_NAME L"MofResourceName"
  293. #define IMAGE_PATH L"ntfrs.exe"
  294. DWORD FrsWmiEventTraceFlag = FALSE;
  295. TRACEHANDLE FrsWmiTraceRegistrationHandle = (TRACEHANDLE) 0;
  296. TRACEHANDLE FrsWmiTraceLoggerHandle = (TRACEHANDLE) 0;
  297. // This is the FRS control Guid for the group of Guids traced below
  298. //
  299. DEFINE_GUID ( /* 78a8f0b1-290e-4c4c-9720-c7f1ef68ce21 */
  300. FrsControlGuid,
  301. 0x78a8f0b1,
  302. 0x290e,
  303. 0x4c4c,
  304. 0x97, 0x20, 0xc7, 0xf1, 0xef, 0x68, 0xce, 0x21
  305. );
  306. // Traceable Guids start here
  307. //
  308. DEFINE_GUID ( /* 2eee6bbf-6665-44cf-8ed7-ceea1d306085 */
  309. FrsTransGuid,
  310. 0x2eee6bbf,
  311. 0x6665,
  312. 0x44cf,
  313. 0x8e, 0xd7, 0xce, 0xea, 0x1d, 0x30, 0x60, 0x85
  314. );
  315. TRACE_GUID_REGISTRATION FrsTraceGuids[] =
  316. {
  317. { & FrsTransGuid, NULL }
  318. };
  319. #define FrsGuidCount (sizeof(FrsTraceGuids) / sizeof(TRACE_GUID_REGISTRATION))
  320. //
  321. // Trace initialization / shutdown routines
  322. //
  323. ULONG
  324. FrsWmiTraceControlCallback(
  325. IN WMIDPREQUESTCODE RequestCode,
  326. IN PVOID RequestContext,
  327. IN OUT ULONG * InOutBufferSize,
  328. IN OUT PVOID Buffer
  329. )
  330. /*++
  331. Routine Description:
  332. Arguments:
  333. Return Value:
  334. --*/
  335. {
  336. #undef DEBSUB
  337. #define DEBSUB "FrsWmiTraceControlCallback:"
  338. PWNODE_HEADER Wnode = (PWNODE_HEADER) Buffer;
  339. ULONG Status;
  340. ULONG RetSize;
  341. Status = ERROR_SUCCESS;
  342. switch (RequestCode) {
  343. case WMI_ENABLE_EVENTS:
  344. FrsWmiTraceLoggerHandle = GetTraceLoggerHandle(Buffer);
  345. FrsWmiEventTraceFlag = TRUE;
  346. RetSize = 0;
  347. DPRINT1(0, "FrsTraceContextCallback(WMI_ENABLE_EVENTS,0x%08X)\n",
  348. FrsWmiTraceLoggerHandle);
  349. break;
  350. case WMI_DISABLE_EVENTS:
  351. FrsWmiTraceLoggerHandle = (TRACEHANDLE) 0;
  352. FrsWmiEventTraceFlag = FALSE;
  353. RetSize = 0;
  354. DPRINT(0, "FrsWmiTraceContextCallback(WMI_DISABLE_EVENTS)\n");
  355. break;
  356. default:
  357. RetSize = 0;
  358. Status = ERROR_INVALID_PARAMETER;
  359. break;
  360. }
  361. *InOutBufferSize = RetSize;
  362. return Status;
  363. }
  364. ULONG
  365. FrsWmiInitializeTrace(
  366. VOID
  367. )
  368. /*++
  369. Routine Description:
  370. Arguments:
  371. Return Value:
  372. --*/
  373. {
  374. #undef DEBSUB
  375. #define DEBSUB "FrsWmiInitializeTrace:"
  376. ULONG WStatus;
  377. HMODULE hModule;
  378. WCHAR FileName[MAX_PATH + 1];
  379. DWORD nLen = 0;
  380. hModule = GetModuleHandleW(IMAGE_PATH);
  381. if (hModule != NULL) {
  382. nLen = GetModuleFileNameW(hModule, FileName, MAX_PATH);
  383. }
  384. if (nLen == 0) {
  385. wcscpy(FileName, IMAGE_PATH);
  386. }
  387. WStatus = RegisterTraceGuidsW(
  388. FrsWmiTraceControlCallback,
  389. NULL,
  390. & FrsControlGuid,
  391. FrsGuidCount,
  392. FrsTraceGuids,
  393. FileName,
  394. RESOURCE_NAME,
  395. & FrsWmiTraceRegistrationHandle);
  396. if (!WIN_SUCCESS(WStatus)) {
  397. DPRINT4(0, "NTFRS: FrsWmiInitializeTrace(%ws,%ws,%d) returns 0x%08X\n",
  398. FileName, RESOURCE_NAME, FrsGuidCount, WStatus);
  399. }
  400. return WStatus;
  401. }
  402. ULONG
  403. FrsWmiShutdownTrace(
  404. void
  405. )
  406. /*++
  407. Routine Description:
  408. Arguments:
  409. Return Value:
  410. --*/
  411. {
  412. #undef DEBSUB
  413. #define DEBSUB "FrsWmiShutdownTrace:"
  414. ULONG WStatus = ERROR_SUCCESS;
  415. UnregisterTraceGuids(FrsWmiTraceRegistrationHandle);
  416. return WStatus;
  417. }
  418. VOID
  419. FrsWmiTraceEvent(
  420. IN DWORD WmiEventType,
  421. IN DWORD TraceGuid,
  422. IN DWORD rtnStatus
  423. )
  424. /*++
  425. Routine Description:
  426. Arguments:
  427. Return Value:
  428. --*/
  429. {
  430. #undef DEBSUB
  431. #define DEBSUB "FrsWmiTraceEvent:"
  432. struct {
  433. EVENT_TRACE_HEADER TraceHeader;
  434. DWORD Data;
  435. } Wnode;
  436. DWORD WStatus;
  437. if (FrsWmiEventTraceFlag) {
  438. ZeroMemory(&Wnode, sizeof(Wnode));
  439. //
  440. // Set WMI event type
  441. //
  442. Wnode.TraceHeader.Class.Type = (UCHAR) WmiEventType;
  443. Wnode.TraceHeader.GuidPtr = (ULONGLONG) FrsTraceGuids[TraceGuid].Guid;
  444. Wnode.TraceHeader.Size = sizeof(Wnode);
  445. Wnode.TraceHeader.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_GUID_PTR;
  446. WStatus = TraceEvent(FrsWmiTraceLoggerHandle, (PEVENT_TRACE_HEADER) &Wnode);
  447. if (!WIN_SUCCESS(WStatus)) {
  448. DPRINT5(0, "FreWmiTraceEvent(%d,%d,%d) = %d,0x%08X\n",
  449. WmiEventType, TraceGuid, rtnStatus, WStatus, WStatus);
  450. }
  451. }
  452. }
  453. BOOL
  454. WINAPI
  455. MainSigHandler(
  456. IN DWORD Signal
  457. )
  458. /*++
  459. Routine Description:
  460. Handle CTRL_BREAK_EVENT and CTRL_C_EVENT by setting the shutdown event.
  461. Arguments:
  462. Signal - signal received.
  463. Return Value:
  464. Set the ShutDownEvent and return TRUE.
  465. --*/
  466. {
  467. #undef DEBSUB
  468. #define DEBSUB "MainSigHandler:"
  469. //
  470. // ShutDown on signal CTRL_C_EVENT or CTRL_BREAK_EVENT
  471. //
  472. if ((Signal == CTRL_C_EVENT) || (Signal == CTRL_BREAK_EVENT)) {
  473. DPRINT1(0,":S: Signal %s received, shutting down now...\n",
  474. (Signal == CTRL_C_EVENT) ? "CTRL_C_EVENT" : "CTRL_BREAK_EVENT");
  475. FrsScmRequestedShutdown = TRUE;
  476. FrsIsShuttingDown = TRUE;
  477. SetEvent(ShutDownEvent);
  478. return TRUE;
  479. }
  480. DPRINT1(0,":S: Signal %d received, not handled\n", Signal);
  481. return FALSE;
  482. }
  483. ULONG
  484. MainSCCheckPointUpdate(
  485. IN PVOID pCurrentState
  486. )
  487. /*++
  488. Routine Description:
  489. This thread repeatedly calls the Service Controller to update
  490. the checkpoint and reset the timeout value so that the
  491. service controller does not time out waiting for a response.
  492. When called in shutdown path the thread exits after a waiting
  493. a max "ShutDownTimeOut" # of seconds. All the subsystems might
  494. not have shutdown cleanly by this time but we don't want to take
  495. for ever to shutdown. This value is picked up from the registry.
  496. Arguments:
  497. pCurrentState - Pointer to the value of the current state of
  498. the service. Depending on this value the
  499. function either waits to shutdown or startup.
  500. Return Value:
  501. Exits with STATUS_UNSUCCESSFUL
  502. --*/
  503. {
  504. #undef DEBSUB
  505. #define DEBSUB "MainSCCheckPointUpdate:"
  506. ULONG Timeout = ShutDownTimeOut;
  507. DWORD CheckPoint = 1;
  508. DWORD WStatus = ERROR_SUCCESS;
  509. DWORD Ret = 0;
  510. if (pCurrentState && *(DWORD *)pCurrentState == SERVICE_STOP_PENDING) {
  511. //
  512. // Thread is called in the shutdown path to make sure that FRS exits
  513. //
  514. while (Timeout) {
  515. DPRINT2(0, ":S: EXIT COUNTDOWN AT T-%d CheckPoint = %x\n", Timeout, CheckPoint);
  516. DEBUG_FLUSH();
  517. if (Timeout < 5) {
  518. Sleep(Timeout * 1000);
  519. Timeout = 0;
  520. } else {
  521. Sleep(5 * 1000);
  522. //
  523. // Update the status every 5 seconds to get the new checkpoint.
  524. //
  525. WStatus = FrsSetServiceStatus(SERVICE_STOP_PENDING, CheckPoint, (ShutDownTimeOut + 5) *1000, NO_ERROR);
  526. if (!WIN_SUCCESS(WStatus)) {
  527. //
  528. // Unable to set the service status. Exit process anyways.
  529. //
  530. break;
  531. }
  532. CheckPoint++;
  533. Timeout -= 5;
  534. }
  535. }
  536. DPRINT(0, ":S: EXIT COUNTDOWN EXPIRED\n");
  537. DEBUG_FLUSH();
  538. EPRINT0(EVENT_FRS_STOPPED_FORCE);
  539. //
  540. // EXIT FOR RESTART
  541. //
  542. // If we are shutting down after taking an assert then don't set the
  543. // service state to stopped. This will cause the service controller to
  544. // restart us if the recorvery option is set. In case of a service controller
  545. // initiated shutwon we want to set the state to stopped so that it does not
  546. // restart us.
  547. //
  548. if (!FrsIsAsserting && FrsScmRequestedShutdown) {
  549. FrsSetServiceStatus(SERVICE_STOPPED, CheckPoint, ShutDownTimeOut*1000, NO_ERROR);
  550. }
  551. ExitProcess(ERROR_NO_SYSTEM_RESOURCES);
  552. FrsFree(pCurrentState);
  553. return ERROR_NO_SYSTEM_RESOURCES;
  554. } else if (pCurrentState && *(DWORD *)pCurrentState == SERVICE_START_PENDING){
  555. //
  556. // Thread is called in the startup path to make sure that
  557. // service controller does not timeout waiting for the
  558. // service to start up.
  559. //
  560. while (TRUE) {
  561. DPRINT1(0, ":S: STARTUP CheckPoint = %x\n",CheckPoint);
  562. Sleep(5 * 1000);
  563. EnterCriticalSection(&ServiceLock);
  564. if (ServiceStatus.dwCurrentState == SERVICE_START_PENDING
  565. && !FrsIsShuttingDown) {
  566. ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  567. ServiceStatus.dwCheckPoint = CheckPoint;
  568. ServiceStatus.dwWaitHint = DEFAULT_STARTUP_TIMEOUT * 1000;
  569. ServiceStatus.dwWin32ExitCode = NO_ERROR;
  570. //
  571. // Update the status every 5 seconds to get the new checkpoint.
  572. //
  573. Ret = SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
  574. CheckPoint++;
  575. if (!Ret) {
  576. //
  577. // Can not set service status. Let the service try to start up
  578. // in the given time. If it does not then the service controller
  579. // time out and stop it.
  580. //
  581. LeaveCriticalSection(&ServiceLock);
  582. break;
  583. }
  584. } else {
  585. //
  586. // Service has either already started or it has moved to another state.
  587. //
  588. LeaveCriticalSection(&ServiceLock);
  589. break;
  590. }
  591. LeaveCriticalSection(&ServiceLock);
  592. }
  593. }
  594. FrsFree(pCurrentState);
  595. return ERROR_SUCCESS;
  596. }
  597. VOID
  598. MainStartShutDown(
  599. VOID
  600. )
  601. /*++
  602. Routine Description:
  603. Shutdown what we can.
  604. Arguments:
  605. None.
  606. Return Value:
  607. None.
  608. --*/
  609. {
  610. #undef DEBSUB
  611. #define DEBSUB "MainStartShutDown:"
  612. ULONGLONG SecondsRunning;
  613. DPRINT(0, ":S: SHUTDOWN IN PROGRESS...\n");
  614. DEBUG_FLUSH();
  615. //
  616. // Do not restart if it was a service control manager requested shutdown.
  617. //
  618. DebugInfo.Restart = FALSE;
  619. if (!FrsScmRequestedShutdown) {
  620. GetSystemTimeAsFileTime((FILETIME *)&SecondsRunning);
  621. SecondsRunning /= (10 * 1000 * 1000);
  622. SecondsRunning -= DebugInfo.StartSeconds;
  623. //
  624. // Restart the service if it was an FRS triggered shutdown, e.g. malloc
  625. // failed or thread create failed, etc.
  626. // Also restart the service after an assertion failure iff the
  627. // service was able to run for some minutes.
  628. //
  629. // Assertion failures during shutdown won't trigger a restart since this
  630. // test is made before shutdown starts.
  631. //
  632. DebugInfo.Restart = !FrsIsAsserting ||
  633. (FrsIsAsserting &&
  634. (DebugInfo.RestartSeconds != 0) &&
  635. (SecondsRunning >= DebugInfo.RestartSeconds));
  636. }
  637. if (DebugInfo.Restart) {
  638. DPRINT(0, ":S: Restart enabled\n");
  639. } else {
  640. DPRINT(0, ":S: Restart disabled\n");
  641. }
  642. }
  643. VOID
  644. MainShutDownComplete(
  645. VOID
  646. )
  647. /*++
  648. Routine Description:
  649. Kick off the exe that will restart the service after a bit
  650. Arguments:
  651. None.
  652. Return Value:
  653. None.
  654. --*/
  655. {
  656. #undef DEBSUB
  657. #define DEBSUB "MainShutDownComplete:"
  658. STARTUPINFO StartUpInfo;
  659. PROCESS_INFORMATION ProcessInformation;
  660. //
  661. // Done with this service
  662. //
  663. DbgPrintAllStats();
  664. //
  665. // Spawn a new exe if needed
  666. //
  667. if (!RunningAsAService && DebugInfo.Restart) {
  668. GetStartupInfo(&StartUpInfo);
  669. if (!CreateProcess(NULL,
  670. DebugInfo.CommandLine,
  671. NULL,
  672. NULL,
  673. FALSE,
  674. 0, // CREATE_NEW_CONSOLE,
  675. NULL,
  676. NULL,
  677. &StartUpInfo,
  678. &ProcessInformation)) {
  679. DPRINT1_WS(0, ":S: ERROR - Spawning %ws :",
  680. DebugInfo.CommandLine, GetLastError());
  681. } else {
  682. DPRINT1(0, ":S: Spawned %ws\n", DebugInfo.CommandLine);
  683. }
  684. }
  685. DPRINT(0,":S: SHUTDOWN COMPLETE\n");
  686. DEBUG_FLUSH();
  687. //
  688. // EXIT FOR RESTART
  689. //
  690. // If restart is desired then simply exit without setting our
  691. // status to SERVICE_STOPPED. The service controller will execute
  692. // our recovery settings which are defaulted to "restart after a
  693. // minute." The exe was restarted above.
  694. //
  695. if (DebugInfo.Restart) {
  696. ExitProcess(ERROR_NO_SYSTEM_RESOURCES);
  697. }
  698. }
  699. ULONG
  700. MainFrsShutDown(
  701. IN PVOID Ignored
  702. )
  703. /*++
  704. Routine Description:
  705. Shutdown the service
  706. Arguments:
  707. Ignored
  708. Return Value:
  709. ERROR_SUCCESS
  710. --*/
  711. {
  712. #undef DEBSUB
  713. #define DEBSUB "MainFrsShutDown:"
  714. DWORD WStatus;
  715. DWORD WaitStatus;
  716. HANDLE ExitThreadHandle;
  717. DWORD ExitThreadId;
  718. PVOID ReplicaKey;
  719. PVOID CxtionKey;
  720. PREPLICA Replica;
  721. PCXTION Cxtion;
  722. DWORD CheckUnjoin;
  723. DWORD LastCheckUnjoin;
  724. DWORD ActiveCoCount, LastCheckActiveCoCount;
  725. PDWORD ServiceWaitState = NULL;
  726. //
  727. // How long is shutdown allowed to take?
  728. //
  729. CfgRegReadDWord(FKC_SHUTDOWN_TIMEOUT, NULL, 0, &ShutDownTimeOut);
  730. DPRINT1(1,":S: Using %d as ShutDownTimeOut\n", ShutDownTimeOut);
  731. //
  732. // Wait for a shutdown event
  733. //
  734. do {
  735. //
  736. // If present, flush the log file every 30 seconds
  737. //
  738. if (DebugInfo.LogFILE) {
  739. WaitStatus = WaitForSingleObject(ShutDownEvent, (30 * 1000));
  740. } else {
  741. WaitStatus = WaitForSingleObject(ShutDownEvent, INFINITE);
  742. }
  743. DEBUG_FLUSH();
  744. } while (WaitStatus == WAIT_TIMEOUT);
  745. FrsIsShuttingDown = TRUE;
  746. EPRINT0(EVENT_FRS_STOPPING);
  747. //
  748. // How long is shutdown allowed to take? Re-read so longer time can
  749. // be used for debug dumping when necc.
  750. //
  751. CfgRegReadDWord(FKC_SHUTDOWN_TIMEOUT, NULL, 0, &ShutDownTimeOut);
  752. DPRINT1(1,":S: Using %d as ShutDownTimeOut\n", ShutDownTimeOut);
  753. //
  754. // SHUTDOWN
  755. //
  756. MainStartShutDown();
  757. //
  758. // Inform the service controller that we are stopping.
  759. //
  760. // Unless we aren't running as a service, or are
  761. // are running to restart the service, or simply running
  762. // as an exe.
  763. //
  764. if (!FrsIsAsserting) {
  765. FrsSetServiceStatus(SERVICE_STOP_PENDING, 0, ShutDownTimeOut*1000, NO_ERROR);
  766. }
  767. //
  768. // Kick off a thread that exits in a bit
  769. // Allocate memory for data to be passed to another thread.
  770. //
  771. ServiceWaitState = FrsAlloc(sizeof(DWORD));
  772. *ServiceWaitState = SERVICE_STOP_PENDING;
  773. ExitThreadHandle = (HANDLE)CreateThread(NULL,
  774. 10000,
  775. MainSCCheckPointUpdate,
  776. ServiceWaitState,
  777. 0,
  778. &ExitThreadId);
  779. if (!HANDLE_IS_VALID(ExitThreadHandle)) {
  780. ExitProcess(ERROR_NO_SYSTEM_RESOURCES);
  781. }
  782. //
  783. // Minimal shutdown - only the ds polling thread
  784. //
  785. if (!MainInitHasRun) {
  786. DPRINT(1,":S: \tFast shutdown in progress...\n");
  787. //
  788. // ShutDown rpc
  789. //
  790. DPRINT(1,":S: \tShutting down RPC Server...\n");
  791. ShutDownRpc();
  792. DEBUG_FLUSH();
  793. //
  794. // Ask all the threads to exit
  795. //
  796. DPRINT(1,":S: \tShutting down all the threads...\n");
  797. WStatus = ThSupExitThreadGroup(NULL);
  798. DEBUG_FLUSH();
  799. //
  800. // Free the rpc table and princname
  801. //
  802. DPRINT(1,":S: \tFreeing rpc memory...\n");
  803. FrsRpcUnInitialize();
  804. DEBUG_FLUSH();
  805. goto SHUTDOWN_COMPLETE;
  806. }
  807. //
  808. // Shutdown the FRS writer COM object.
  809. //
  810. DPRINT(1,":S: \tShutting down FRS writer component...\n");
  811. ShutDownFrsWriter();
  812. //
  813. // ShutDown the delayed command server; don't let change orders
  814. // sit on the various retry queues.
  815. //
  816. DPRINT(1,":S: \tShutting down Delayed Server...\n");
  817. ShutDownDelCs();
  818. DEBUG_FLUSH();
  819. //
  820. // ShutDown the staging file generator
  821. //
  822. DPRINT(1,":S: \tShutting down Staging File Generator...\n");
  823. ShutDownStageCs();
  824. DEBUG_FLUSH();
  825. //
  826. // ShutDown the staging file fetcher
  827. //
  828. DPRINT(1,":S: \tShutting down Staging File Fetch...\n");
  829. ShutDownFetchCs();
  830. DEBUG_FLUSH();
  831. //
  832. // ShutDown the initial sync controller
  833. //
  834. DPRINT(1,":S: \tShutting down Initial Sync Controller...\n");
  835. ShutDownInitSyncCs();
  836. DEBUG_FLUSH();
  837. //
  838. // ShutDown the staging file installer
  839. //
  840. DPRINT(1,":S: \tShutting down Staging File Install...\n");
  841. ShutDownInstallCs();
  842. DEBUG_FLUSH();
  843. //
  844. // Stop local change orders.
  845. //
  846. // Shutdown can be delayed indefinitely if the journal cs continues
  847. // to add local change orders to the change order accept queue.
  848. //
  849. // The remote change orders were stopped by setting FrsIsShuttingDown
  850. // to TRUE above.
  851. //
  852. ReplicaKey = NULL;
  853. while (Replica = GTabNextDatum(ReplicasByGuid, &ReplicaKey)) {
  854. DPRINT1(4, ":S: Pause journaling on replica %ws\n", Replica->ReplicaName->Name);
  855. if (Replica->pVme) {
  856. JrnlPauseVolume(Replica->pVme, 5000);
  857. }
  858. }
  859. //
  860. // Shutdown the replicas cleanly.
  861. //
  862. // WARN: all of the change orders have to be taken through the retry
  863. // path before shutting down the rest of the system. Otherwise,
  864. // access violations occur in ChgOrdIssueCleanup(). Perhaps we
  865. // should fix ChgOrdIssueCleanup() to handle the case when
  866. // change order accept has exited and cleaned up its tables?
  867. //
  868. CheckUnjoin = 0;
  869. ReplicaKey = NULL;
  870. while (Replica = GTabNextDatum(ReplicasByGuid, &ReplicaKey)) {
  871. LOCK_CXTION_TABLE(Replica);
  872. CxtionKey = NULL;
  873. while (Cxtion = GTabNextDatum(Replica->Cxtions, &CxtionKey)) {
  874. if (CxtionStateIs(Cxtion, CxtionStateUnjoined) ||
  875. CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  876. DPRINT3(0, ":S: %ws\\%ws %s: Unjoin not needed.\n",
  877. Replica->MemberName->Name, Cxtion->Name->Name,
  878. (Cxtion->Inbound) ? "<-" : "->");
  879. } else {
  880. DPRINT4(0, ":S: %ws\\%ws %s: Unjoin (%d cos).\n",
  881. Replica->MemberName->Name, Cxtion->Name->Name,
  882. (Cxtion->Inbound) ? "<-" : "->", Cxtion->ChangeOrderCount);
  883. RcsSubmitReplicaCxtion(Replica, Cxtion, CMD_UNJOIN);
  884. CheckUnjoin += Cxtion->ChangeOrderCount + 1;
  885. }
  886. }
  887. UNLOCK_CXTION_TABLE(Replica);
  888. }
  889. LastCheckUnjoin = 0;
  890. while (CheckUnjoin && CheckUnjoin != LastCheckUnjoin) {
  891. //
  892. // Wait a bit and check again
  893. //
  894. Sleep(5 * 1000);
  895. LastCheckUnjoin = CheckUnjoin;
  896. CheckUnjoin = 0;
  897. ReplicaKey = NULL;
  898. while (Replica = GTabNextDatum(ReplicasByGuid, &ReplicaKey)) {
  899. LOCK_CXTION_TABLE(Replica);
  900. CxtionKey = NULL;
  901. while (Cxtion = GTabNextDatum(Replica->Cxtions, &CxtionKey)) {
  902. if (CxtionStateIs(Cxtion, CxtionStateUnjoined) ||
  903. CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  904. DPRINT3(0, ":S: %ws\\%ws %s: Unjoin successful.\n",
  905. Replica->MemberName->Name, Cxtion->Name->Name,
  906. (Cxtion->Inbound) ? "<-" : "->");
  907. } else if (Cxtion->ChangeOrderCount) {
  908. DPRINT4(0, ":S: %ws\\%ws %s: Unjoining (%d cos).\n",
  909. Replica->MemberName->Name, Cxtion->Name->Name,
  910. (Cxtion->Inbound) ? "<-" : "->",
  911. Cxtion->ChangeOrderCount);
  912. CheckUnjoin += Cxtion->ChangeOrderCount + 1;
  913. } else {
  914. DPRINT4(0, ":S: %ws\\%ws %s: Ignoring (state %s).\n",
  915. Replica->MemberName->Name, Cxtion->Name->Name,
  916. (Cxtion->Inbound) ? "<-" : "->", GetCxtionStateName(Cxtion));
  917. }
  918. }
  919. UNLOCK_CXTION_TABLE(Replica);
  920. }
  921. }
  922. if (CheckUnjoin) {
  923. DPRINT(0, "ERROR - Could not unjoin all cxtions.\n");
  924. }
  925. //
  926. // Now wait until any remaining local Change Orders wind through
  927. // retire or retry for each replica set.
  928. //
  929. ReplicaKey = NULL;
  930. while (Replica = GTabNextDatum(ReplicasByGuid, &ReplicaKey)) {
  931. ActiveCoCount = 0;
  932. LastCheckActiveCoCount = 1;
  933. while (ActiveCoCount != LastCheckActiveCoCount) {
  934. LastCheckActiveCoCount = ActiveCoCount;
  935. if ((Replica->pVme != NULL) &&
  936. (Replica->pVme->ActiveInboundChangeOrderTable != NULL)) {
  937. ActiveCoCount = GhtCountEntries(Replica->pVme->ActiveInboundChangeOrderTable);
  938. if (ActiveCoCount == 0) {
  939. break;
  940. }
  941. DPRINT2(0, ":S: Waiting for %d active inbound change orders to finish up for %ws.\n",
  942. ActiveCoCount, Replica->MemberName->Name);
  943. Sleep(5*1000);
  944. }
  945. }
  946. if (ActiveCoCount != 0) {
  947. DPRINT2(0, ":S: ERROR - %d active inbound change orders were not cleaned up for %ws.\n",
  948. ActiveCoCount, Replica->MemberName->Name);
  949. } else {
  950. DPRINT1(0, ":S: All active inbound change orders finished for %ws.\n",
  951. Replica->MemberName->Name);
  952. }
  953. }
  954. //
  955. // ShutDown the replica control command server
  956. //
  957. DPRINT(1,":S: \tShutting down Replica Server...\n");
  958. RcsShutDownReplicaCmdServer();
  959. DEBUG_FLUSH();
  960. //
  961. // ShutDown the send command server
  962. //
  963. DPRINT(1,":S: \tShutting down Comm Server...\n");
  964. SndCsShutDown();
  965. DEBUG_FLUSH();
  966. //
  967. // ShutDown rpc
  968. //
  969. DPRINT(1,":S: \tShutting down RPC Server...\n");
  970. ShutDownRpc();
  971. DEBUG_FLUSH();
  972. //
  973. // ShutDown the waitable timer server
  974. //
  975. DPRINT(1,":S: \tShutting down Waitable Timer Server...\n");
  976. ShutDownWait();
  977. DEBUG_FLUSH();
  978. //
  979. // ShutDown the outbound log processor
  980. //
  981. //
  982. // NOPE; the database server requires the outbound log
  983. // processor when shutting down. The database server will
  984. // shutdown the outbound log processor when its done.
  985. //
  986. // DPRINT(1,"\tShutting down Outbound Log Processor...\n");
  987. // DEBUG_FLUSH();
  988. // ShutDownOutLog();
  989. //
  990. // ShutDown the database server
  991. //
  992. DPRINT(1,":S: \tShutting down the Database Server...\n");
  993. DEBUG_FLUSH();
  994. DbsShutDown();
  995. //
  996. // Wakeup any command server waiting on another command server to start
  997. //
  998. if (HANDLE_IS_VALID(DataBaseEvent)) {
  999. SetEvent(DataBaseEvent);
  1000. }
  1001. if (HANDLE_IS_VALID(JournalEvent)) {
  1002. SetEvent(JournalEvent);
  1003. }
  1004. if (HANDLE_IS_VALID(ChgOrdEvent)) {
  1005. SetEvent(ChgOrdEvent);
  1006. }
  1007. if (HANDLE_IS_VALID(CommEvent)) {
  1008. SetEvent(CommEvent);
  1009. }
  1010. if (HANDLE_IS_VALID(ReplicaEvent)) {
  1011. SetEvent(ReplicaEvent);
  1012. }
  1013. //
  1014. // Wakeup the thread that polls the ds
  1015. //
  1016. if (HANDLE_IS_VALID(DsPollEvent)) {
  1017. SetEvent(DsPollEvent);
  1018. }
  1019. //
  1020. // Wakeup any thread waiting on the thread that polls the ds
  1021. //
  1022. if (HANDLE_IS_VALID(DsShutDownComplete)) {
  1023. SetEvent(DsShutDownComplete);
  1024. }
  1025. //
  1026. // Ask all the threads to exit
  1027. //
  1028. DPRINT(1,":S: \tShutting down all the threads...\n");
  1029. WStatus = ThSupExitThreadGroup(NULL);
  1030. DEBUG_FLUSH();
  1031. //
  1032. // We can't uninitialize the subsystems because some thread
  1033. // may still be active and referencing the data structs.
  1034. //
  1035. if (WIN_SUCCESS(WStatus)) {
  1036. //
  1037. // Free the active replica set stuff
  1038. //
  1039. DPRINT(1,":S: \tFreeing replica sets...\n");
  1040. RcsFrsUnInitializeReplicaCmdServer();
  1041. DEBUG_FLUSH();
  1042. //
  1043. // Free the rpc handle cache
  1044. //
  1045. DPRINT(1,":S: \tFreeing rpc handles...\n");
  1046. SndCsUnInitialize();
  1047. DEBUG_FLUSH();
  1048. //
  1049. // Free the stage table
  1050. //
  1051. DPRINT(1,":S: \tFreeing stage table...\n");
  1052. FrsStageCsUnInitialize();
  1053. DEBUG_FLUSH();
  1054. //
  1055. // Free the rpc table and princname
  1056. //
  1057. DPRINT(1,":S: \tFreeing rpc memory...\n");
  1058. FrsRpcUnInitialize();
  1059. DEBUG_FLUSH();
  1060. }
  1061. #if DBG
  1062. //
  1063. // DEBUG PRINTS
  1064. //
  1065. DPRINT(1,":S: \tDumping Vme Filter Table...\n");
  1066. JrnlDumpVmeFilterTable();
  1067. DEBUG_FLUSH();
  1068. #endif DBG
  1069. SHUTDOWN_COMPLETE:
  1070. //
  1071. // We can't free resources because some thread may still be
  1072. // active and referencing them.
  1073. //
  1074. if (WIN_SUCCESS(WStatus)) {
  1075. //
  1076. //
  1077. // Free resources in main
  1078. //
  1079. DPRINT(1,":S: \tFreeing main resources...\n");
  1080. DEBUG_FLUSH();
  1081. FrsFree(WorkingPath);
  1082. FrsFree(DbLogPath);
  1083. FrsFree(JetPath);
  1084. FrsFree(JetFile);
  1085. FrsFree(JetFileCompact);
  1086. FrsFree(JetSys);
  1087. FrsFree(JetTemp);
  1088. FrsFree(JetLog);
  1089. FrsFree(JetPathA);
  1090. FrsFree(JetFileA);
  1091. FrsFree(JetFileCompactA);
  1092. FrsFree(JetSysA);
  1093. FrsFree(JetTempA);
  1094. FrsFree(JetLogA);
  1095. GTabFreeTable(StagingAreaTable, FrsFree);
  1096. GTabFreeTable(ReparseTagTable, FrsFreeType);
  1097. //
  1098. // Uninitialize the memory allocation subsystem
  1099. //
  1100. DPRINT(1,":S: \tShutting down the memory allocation subsystem...\n");
  1101. DEBUG_FLUSH();
  1102. FrsUnInitializeMemAlloc();
  1103. }
  1104. //
  1105. // Report an event
  1106. //
  1107. if (FrsIsAsserting) {
  1108. EPRINT0(EVENT_FRS_STOPPED_ASSERT);
  1109. } else {
  1110. EPRINT0(EVENT_FRS_STOPPED);
  1111. }
  1112. //
  1113. // Check the restart action.
  1114. //
  1115. MainShutDownComplete();
  1116. //
  1117. // DONE
  1118. //
  1119. if (!FrsIsAsserting && FrsScmRequestedShutdown) {
  1120. SetEvent(ShutDownComplete);
  1121. FrsSetServiceStatus(SERVICE_STOPPED, 0, ShutDownTimeOut*1000, NO_ERROR);
  1122. }
  1123. ExitProcess(STATUS_SUCCESS);
  1124. return STATUS_SUCCESS;
  1125. }
  1126. DWORD
  1127. MainMustInit(
  1128. IN INT ArgC,
  1129. IN PWCHAR *ArgV
  1130. )
  1131. /*++
  1132. Routine Description:
  1133. Initialize anything necessary for shutdown and logging errors.
  1134. Arguments:
  1135. ArgC - From main
  1136. ArgV - From main
  1137. Return Value:
  1138. Win32 Error Status
  1139. --*/
  1140. {
  1141. #undef DEBSUB
  1142. #define DEBSUB "MainMustInit:"
  1143. DWORD WStatus;
  1144. ULONG Len;
  1145. PWCHAR Severity;
  1146. HANDLE ShutDownThreadHandle;
  1147. DWORD ShutDownThreadId;
  1148. //
  1149. // Several lower level functions aren't prepared to dynamically allocate
  1150. // the needed storage so to help mitigate this we use the BigPath crock.
  1151. //
  1152. WCHAR BigPath[8*MAX_PATH + 1];
  1153. //
  1154. // FIRST, SETUP THE "MUST HAVE" VARIABLES, EVENTS, SERVICES...
  1155. //
  1156. //
  1157. // Synchronizes access to pValidPartnerTableStruct.
  1158. // see definition of pValidPartnerTableStruct for more info.
  1159. //
  1160. INITIALIZE_CRITICAL_SECTION(&CritSec_pValidPartnerTableStruct);
  1161. //
  1162. // Synchronizes access to the Old ValidPartnerTableStruct List.
  1163. // OldValidPartnerTableStructListHead
  1164. //
  1165. INITIALIZE_CRITICAL_SECTION(&OldValidPartnerTableStructListHeadLock);
  1166. //
  1167. // Synchronizes access between DsCs and SysVol Promotion when
  1168. // initializing other the rest of the service (MainInit()).
  1169. //
  1170. INITIALIZE_CRITICAL_SECTION(&MainInitLock);
  1171. //
  1172. // Enable event logging
  1173. //
  1174. //InitializeEventLog();
  1175. //EPRINT0(EVENT_FRS_STARTING);
  1176. //
  1177. // Backup/Restore privileges
  1178. //
  1179. if (!FrsSetupPrivileges()) {
  1180. WStatus = GetLastError();
  1181. DPRINT_WS(0, ":S: ERROR - FrsSetupPrivileges()", WStatus);
  1182. return WStatus;
  1183. }
  1184. DEBUG_FLUSH();
  1185. //
  1186. // Get this Machine's name.
  1187. //
  1188. DPRINT1(0, ":S: Computer name is %ws\n", ComputerName);
  1189. //
  1190. // Get this Machine's DNS name.
  1191. //
  1192. Len = ARRAY_SZ(BigPath);
  1193. BigPath[0] = L'\0';
  1194. if (!GetComputerNameEx(ComputerNameDnsFullyQualified, BigPath, &Len)) {
  1195. WStatus = GetLastError();
  1196. DPRINT1_WS(0, "ERROR - Cannot get the computer's DNS name; using %ws\n",
  1197. ComputerName, WStatus);
  1198. ComputerDnsName = FrsWcsDup(ComputerName);
  1199. } else {
  1200. ComputerDnsName = FrsWcsDup(BigPath);
  1201. }
  1202. DPRINT1(0, "Computer's DNS name is %ws\n", ComputerDnsName);
  1203. DEBUG_FLUSH();
  1204. if (!RunningAsAService) {
  1205. //
  1206. // We need the event log service to log errors, warnings, notes, ...
  1207. //
  1208. EventLogIsRunning = FrsWaitService(ComputerName, L"EventLog", 1000, 10000);
  1209. if (!EventLogIsRunning) {
  1210. return ERROR_SERVICE_NOT_ACTIVE;
  1211. }
  1212. //
  1213. // We need the rpc endpoint mapper
  1214. //
  1215. RpcssIsRunning = FrsWaitService(ComputerName, L"rpcss", 1000, 10000);
  1216. if (!RpcssIsRunning) {
  1217. return ERROR_SERVICE_NOT_ACTIVE;
  1218. }
  1219. }
  1220. //
  1221. // Signaled when shutdown is desired
  1222. //
  1223. ShutDownEvent = FrsCreateEvent(TRUE, FALSE);
  1224. //
  1225. // Signaled when shutdown has completed
  1226. //
  1227. ShutDownComplete = FrsCreateEvent(TRUE, FALSE);
  1228. //
  1229. // Signaled when database has started
  1230. //
  1231. DataBaseEvent = FrsCreateEvent(TRUE, FALSE);
  1232. //
  1233. // Signaled when journal has started
  1234. //
  1235. JournalEvent = FrsCreateEvent(TRUE, FALSE);
  1236. //
  1237. // Signaled when change order accept has started
  1238. //
  1239. ChgOrdEvent = FrsCreateEvent(TRUE, FALSE);
  1240. //
  1241. // Signaled when replica has started
  1242. //
  1243. ReplicaEvent = FrsCreateEvent(TRUE, FALSE);
  1244. //
  1245. // Signaled when comm has started
  1246. //
  1247. CommEvent = FrsCreateEvent(TRUE, FALSE);
  1248. //
  1249. // Used to poll the ds
  1250. //
  1251. DsPollEvent = FrsCreateEvent(TRUE, FALSE);
  1252. //
  1253. // Set when the thread that polls the Ds has shut down
  1254. //
  1255. DsShutDownComplete = FrsCreateEvent(TRUE, FALSE);
  1256. //
  1257. // Used to signal the completion of backup operation.
  1258. //
  1259. FrsThawEvent = FrsCreateEvent(TRUE, FALSE);
  1260. //
  1261. // Event to signal that there are no installs in
  1262. // progress.
  1263. //
  1264. FrsNoInstallsInProgressEvent = FrsCreateEvent(TRUE, FALSE);
  1265. //
  1266. // register signal handlers after creating events and initializing
  1267. // the critical sections!
  1268. //
  1269. if (!RunningAsAService) {
  1270. DPRINT(0, "Setting CTRL_C_EVENT and CTRL_BREAK_EVENT handlers.\n");
  1271. if(!SetConsoleCtrlHandler(MainSigHandler, TRUE)) {
  1272. DPRINT_WS(0, "SetConsoleCtrlHandler() failed:", GetLastError());
  1273. }
  1274. }
  1275. //
  1276. // Get the path to the DB file and the DB Logs.
  1277. //
  1278. CfgRegReadString(FKC_WORKING_DIRECTORY, NULL, 0, &WorkingPath);
  1279. if (WorkingPath == NULL) {
  1280. DPRINT(0, ":S: Must have the working directory in the registry. Aborting\n");
  1281. return ERROR_INVALID_PARAMETER;
  1282. }
  1283. CfgRegReadString(FKC_DBLOG_DIRECTORY, NULL, 0, &DbLogPath);
  1284. //
  1285. // Create the working directory and the DB log dir (optional)
  1286. //
  1287. FRS_WCSLWR(WorkingPath);
  1288. DPRINT1(0, ":S: Working Directory is %ws\n", WorkingPath);
  1289. WStatus = FrsCreateDirectory(WorkingPath);
  1290. CLEANUP_WS(0, ":S: Can't create working dir:", WStatus, CLEAN_UP);
  1291. if (DbLogPath != NULL) {
  1292. FRS_WCSLWR(DbLogPath);
  1293. DPRINT1(0, ":S: DB Log Path provided is %ws\n", DbLogPath);
  1294. WStatus = FrsCreateDirectory(DbLogPath);
  1295. CLEANUP_WS(0, ":S: Can't create debug log dir:", WStatus, CLEAN_UP);
  1296. }
  1297. //
  1298. // Restrict access to the database working directory
  1299. //
  1300. WStatus = FrsRestrictAccessToFileOrDirectory(WorkingPath, NULL,
  1301. FALSE, // do not inherit acls from parent.
  1302. TRUE); // push acls to children.
  1303. DPRINT1_WS(0, ":S: WARN - Failed to restrict access to %ws (IGNORED);",
  1304. WorkingPath, WStatus);
  1305. WStatus = ERROR_SUCCESS;
  1306. //
  1307. // Restrict access to the database log directory (optional)
  1308. //
  1309. if (DbLogPath != NULL) {
  1310. WStatus = FrsRestrictAccessToFileOrDirectory(DbLogPath, NULL,
  1311. FALSE, // do not inherit acls from parent.
  1312. TRUE);// push acls to children.
  1313. DPRINT1_WS(0, ":S: WARN - Failed to restrict access to %ws (IGNORED);",
  1314. DbLogPath, WStatus);
  1315. WStatus = ERROR_SUCCESS;
  1316. }
  1317. //
  1318. // Create the database path
  1319. // WARN: FrsDsInitializeHardWired() may alter JetPath
  1320. //
  1321. JetPath = FrsWcsPath(WorkingPath, JET_DIR);
  1322. //
  1323. // Initialize the path to the inifile.
  1324. //
  1325. #ifdef DS_FREE
  1326. IniFileName = FrsWcsPath(WorkingPath, L"frsconfig.txt");
  1327. #endif DS_FREE
  1328. //
  1329. // Initialize the hardwired config stuff
  1330. // WARN: FrsDsInitializeHardWired() may alter JetPath
  1331. //
  1332. INITIALIZE_HARD_WIRED();
  1333. //
  1334. // Create the database paths and file (UNICODE and ASCII)
  1335. // Jet uses the ASCII versions
  1336. //
  1337. FRS_WCSLWR(JetPath); // for wcsstr()
  1338. JetFile = FrsWcsPath(JetPath, JET_FILE);
  1339. JetFileCompact = FrsWcsPath(JetPath, JET_FILE_COMPACT);
  1340. JetSys = FrsWcsPath(JetPath, JET_SYS);
  1341. JetTemp = FrsWcsPath(JetPath, JET_TEMP);
  1342. if (DbLogPath != NULL) {
  1343. JetLog = FrsWcsDup(DbLogPath);
  1344. } else {
  1345. JetLog = FrsWcsPath(JetPath, JET_LOG);
  1346. }
  1347. //
  1348. // Jet can't handle wide char strings
  1349. //
  1350. JetPathA = FrsWtoA(JetPath);
  1351. JetFileA = FrsWtoA(JetFile);
  1352. JetFileCompactA = FrsWtoA(JetFileCompact);
  1353. JetSysA = FrsWtoA(JetSys);
  1354. JetTempA = FrsWtoA(JetTemp);
  1355. JetLogA = FrsWtoA(JetLog);
  1356. DPRINT2(4, ":S: JetPath : %ws (%s in ASCII)\n", JetPath, JetPathA);
  1357. DPRINT2(4, ":S: JetFile : %ws (%s in ASCII)\n", JetFile, JetFileA);
  1358. DPRINT2(4, ":S: JetFileCompact: %ws (%s in ASCII)\n", JetFileCompact, JetFileCompactA);
  1359. DPRINT2(4, ":S: JetSys : %ws (%s in ASCII)\n", JetSys, JetSysA);
  1360. DPRINT2(4, ":S: JetTemp : %ws (%s in ASCII)\n", JetTemp, JetTempA);
  1361. DPRINT2(4, ":S: JetLog : %ws (%s in ASCII)\n", JetLog, JetLogA);
  1362. //
  1363. // Create the database directories under workingpath\JET_DIR
  1364. //
  1365. WStatus = FrsCreateDirectory(JetPath);
  1366. CLEANUP_WS(0, ":S: Can't create JetPath dir:", WStatus, CLEAN_UP);
  1367. WStatus = FrsCreateDirectory(JetSys);
  1368. CLEANUP_WS(0, ":S: Can't create JetSys dir:", WStatus, CLEAN_UP);
  1369. WStatus = FrsCreateDirectory(JetTemp);
  1370. CLEANUP_WS(0, ":S: Can't create JetTemp dir:", WStatus, CLEAN_UP);
  1371. WStatus = FrsCreateDirectory(JetLog);
  1372. CLEANUP_WS(0, ":S: Can't create JetLog dir:", WStatus, CLEAN_UP);
  1373. //
  1374. // Initialize the subsystem used for managing threads
  1375. // (needed for an orderly shutdown)
  1376. //
  1377. ThSupInitialize();
  1378. //
  1379. // This thread responds to the ShutDownEvent and insures
  1380. // an orderly shutdown when run as either a service or an exe.
  1381. //
  1382. ShutDownThreadHandle = (HANDLE)CreateThread(NULL,
  1383. 0,
  1384. MainFrsShutDown,
  1385. NULL,
  1386. 0,
  1387. &ShutDownThreadId);
  1388. if (!HANDLE_IS_VALID(ShutDownThreadHandle)) {
  1389. WStatus = GetLastError();
  1390. CLEANUP_WS(0, ":S: Can't create shutdown thread:", WStatus, CLEAN_UP);
  1391. }
  1392. DbgCaptureThreadInfo2(L"Shutdown", MainFrsShutDown, ShutDownThreadId);
  1393. //
  1394. // The rpc server may reference this table as soon as the rpc
  1395. // interfaces are registered. Make sure it exists early in the
  1396. // startup.
  1397. //
  1398. ReplicasByGuid = GTabAllocTable();
  1399. //
  1400. // The staging area table is referenced early in the startup threads
  1401. //
  1402. StagingAreaTable = GTabAllocTable();
  1403. INITIALIZE_CRITICAL_SECTION(&StagingAreaCleanupLock);
  1404. //
  1405. // Initialize necessary tables.
  1406. //
  1407. ReparseTagTable = GTabAllocNumberTable();
  1408. CompressionTable = GTabAllocTable();
  1409. //
  1410. // This table is used to keep contexts across multiple calls from by
  1411. // info APIs. Table is only initialized once.
  1412. //
  1413. FrsInfoContextTable = GTabAllocNumberTable();
  1414. if (!DebugInfo.DisableCompression) {
  1415. DPRINT(0, "Staging file COMPRESSION support is enabled.\n");
  1416. //
  1417. // The Compression table is inited from the registry. Add the guids for the
  1418. // compression formats that we support.
  1419. //
  1420. GTabInsertEntryNoLock(CompressionTable, (PVOID)&FrsGuidCompressionFormatLZNT1, (GUID*)&FrsGuidCompressionFormatLZNT1, NULL);
  1421. } else {
  1422. DPRINT(0, "Staging file COMPRESSION support is disabled.\n");
  1423. }
  1424. //
  1425. // Size of buffer used during directory enumeration
  1426. //
  1427. CfgRegReadDWord(FKC_ENUMERATE_DIRECTORY_SIZE, NULL, 0, &EnumerateDirectorySizeInBytes);
  1428. DPRINT1(4, ":S: Registry Param - Enumerate Directory Buffer Size in Bytes: %d\n",
  1429. EnumerateDirectorySizeInBytes);
  1430. //
  1431. // Default File and Directory filter lists.
  1432. //
  1433. // The compiled in default is only used if no value is supplied in
  1434. // EITHER the DS or the Registry.
  1435. // The table below shows how the final filter is formed.
  1436. //
  1437. // value Value
  1438. // supplied supplied Resulting filter string Used
  1439. // in DS in Registry
  1440. // No No DEFAULT_xxx_FILTER_LIST
  1441. // No Yes Value from registry
  1442. // Yes No Value from DS
  1443. // Yes Yes Value from DS + Value from registry
  1444. //
  1445. RegistryFileExclFilterList = NULL;
  1446. CfgRegReadString(FKC_FILE_EXCL_FILTER_LIST, NULL, 0, &RegistryFileExclFilterList);
  1447. RegistryDirExclFilterList = NULL;
  1448. CfgRegReadString(FKC_DIR_EXCL_FILTER_LIST, NULL, 0, &RegistryDirExclFilterList);
  1449. DPRINT1(4, ":S: Registry Param - File Filter List: %ws\n",
  1450. (RegistryFileExclFilterList) ? RegistryFileExclFilterList : L"Null");
  1451. DPRINT1(4, ":S: Registry Param - Directory Filter Exclusion List: %ws\n",
  1452. (RegistryDirExclFilterList) ? RegistryDirExclFilterList : L"Null");
  1453. //
  1454. // Inclusion filters were added very late (7/13/99) so a single file
  1455. // ~clbcatq.* could be made to replicate. This is a reg only key.
  1456. //
  1457. // Add the File Inclusion Filter List Value to the Reg key
  1458. // "HKLM\System\CurrentControlSet\Services\NtFrs\Parameters"
  1459. //
  1460. // If the value already exists then preserve it.
  1461. //
  1462. CfgRegWriteString(FKC_FILE_INCL_FILTER_LIST,
  1463. NULL,
  1464. FRS_RKF_FORCE_DEFAULT_VALUE | FRS_RKF_KEEP_EXISTING_VALUE,
  1465. 0);
  1466. RegistryFileInclFilterList = NULL;
  1467. CfgRegReadString(FKC_FILE_INCL_FILTER_LIST, NULL, 0, &RegistryFileInclFilterList);
  1468. RegistryDirInclFilterList = NULL;
  1469. CfgRegReadString(FKC_DIR_INCL_FILTER_LIST, NULL, 0, &RegistryDirInclFilterList);
  1470. DPRINT1(4, ":S: Registry Param - File Filter Inclusion List: %ws\n",
  1471. (RegistryFileInclFilterList) ? RegistryFileInclFilterList : L"Null");
  1472. DPRINT1(4, ":S: Registry Param - Directory Filter Inclusion List: %ws\n",
  1473. (RegistryDirInclFilterList) ? RegistryDirInclFilterList : L"Null");
  1474. //
  1475. // Mutual Authentication. Update registry value as needed.
  1476. //
  1477. CfgRegCheckEnable(FKC_FRS_MUTUAL_AUTHENTICATION_IS,
  1478. NULL,
  1479. 0,
  1480. &MutualAuthenticationIsEnabled,
  1481. &MutualAuthenticationIsEnabledAndRequired);
  1482. // WStatus = ConfigCheckEnabledWithUpdate(FRS_CONFIG_SECTION,
  1483. // FRS_MUTUAL_AUTHENTICATION_IS,
  1484. // FRS_IS_DEFAULT_ENABLED,
  1485. // &MutualAuthenticationIsEnabled);
  1486. //
  1487. // if (!MutualAuthenticationIsEnabled) {
  1488. // DPRINT_WS(0, "WARN - Mutual authentication is not enabled", WStatus);
  1489. // } else {
  1490. // DPRINT(4, "Mutual authentication is enabled\n");
  1491. // }
  1492. //
  1493. // Initialize the FRS backup writer COM interface.
  1494. //
  1495. DPRINT(4, "About to initialize the Frs Writer component\n");
  1496. WStatus = InitializeFrsWriter();
  1497. if (!WIN_SUCCESS(WStatus)) {
  1498. DPRINT1(1,"WARN - Can not initialize the Frs Writer component, WStatus = %d\n", WStatus);
  1499. }
  1500. //
  1501. // Initialize the Perfmon server
  1502. //
  1503. InitializePerfmonServer();
  1504. //
  1505. // Create registry keys for checking access to RPC calls
  1506. //
  1507. FrsRpcInitializeAccessChecks();
  1508. //
  1509. // Register the RPC interfaces
  1510. //
  1511. if (!FrsRpcInitialize()) {
  1512. return RPC_S_CANT_CREATE_ENDPOINT;
  1513. }
  1514. return ERROR_SUCCESS;
  1515. CLEAN_UP:
  1516. return WStatus;
  1517. }
  1518. VOID
  1519. MainInit(
  1520. VOID
  1521. )
  1522. /*++
  1523. Routine Description:
  1524. Initialize anything necessary to run the service
  1525. Arguments:
  1526. None.
  1527. Return Value:
  1528. None.
  1529. --*/
  1530. {
  1531. #undef DEBSUB
  1532. #define DEBSUB "MainInit:"
  1533. EnterCriticalSection(&MainInitLock);
  1534. //
  1535. // No need to initialize twice
  1536. //
  1537. if (MainInitHasRun) {
  1538. LeaveCriticalSection(&MainInitLock);
  1539. return;
  1540. }
  1541. //
  1542. // SETUP THE INFRASTRUCTURE
  1543. //
  1544. //
  1545. // Reset our start time (in minutes). The service is not restarted
  1546. // unless this invocation ran long enough before taking an assert.
  1547. //
  1548. // 100-nsecs / (10 (microsecs) * 1000 (msecs) * 1000 (secs) * 60 (min)
  1549. //
  1550. GetSystemTimeAsFileTime((FILETIME *)&DebugInfo.StartSeconds);
  1551. DebugInfo.StartSeconds /= (10 * 1000 * 1000);
  1552. //
  1553. // Fetch the staging file limit
  1554. //
  1555. CfgRegReadDWord(FKC_STAGING_LIMIT, NULL, 0, &StagingLimitInKb);
  1556. DPRINT1(4, ":S: Staging limit is: %d KB\n", StagingLimitInKb);
  1557. //
  1558. // Put the default value in registry if there is no key present.
  1559. //
  1560. CfgRegWriteDWord(FKC_STAGING_LIMIT,
  1561. NULL,
  1562. FRS_RKF_FORCE_DEFAULT_VALUE | FRS_RKF_KEEP_EXISTING_VALUE,
  1563. 0);
  1564. //
  1565. // Get Max number of replica sets allowed.
  1566. //
  1567. CfgRegReadDWord(FKC_MAX_NUMBER_REPLICA_SETS, NULL, 0, &MaxNumberReplicaSets);
  1568. //
  1569. // Get Max number of Jet database sessions allowed.
  1570. //
  1571. CfgRegReadDWord(FKC_MAX_NUMBER_JET_SESSIONS, NULL, 0, &MaxNumberJetSessions);
  1572. //
  1573. // Get outstanding CO qutoa limit on outbound connections.
  1574. //
  1575. CfgRegReadDWord(FKC_OUT_LOG_CO_QUOTA, NULL, 0, &MaxOutLogCoQuota);
  1576. //
  1577. // Get boolean to tell us to preserve file object IDs
  1578. // -- See Bug 352250 for why this is a risky thing to do.
  1579. CfgRegReadDWord(FKC_PRESERVE_FILE_OID, NULL, 0, &PreserveFileOID);
  1580. //
  1581. // Get number of days for retry timeouts
  1582. //
  1583. CfgRegReadDWord(FKC_MAX_CO_RETRY_TIMEOUT_MINUTES, NULL, 0, &MaxCoRetryTimeoutMinutes);
  1584. //
  1585. // Get maximum count for retry timeouts
  1586. //
  1587. CfgRegReadDWord(FKC_MAX_CO_RETRY_TIMEOUT_COUNT, NULL, 0, &MaxCoRetryTimeoutCount);
  1588. //
  1589. // Get state of outlog cleanup lock.
  1590. //
  1591. CfgRegReadDWord(FKC_LOCKED_OUTLOG_CLEANUP, NULL, 0, &LockedOutlogCleanup);
  1592. //
  1593. // Get the service long name for use in error messages.
  1594. //
  1595. ServiceLongName = FrsGetResourceStr(IDS_SERVICE_LONG_NAME);
  1596. //
  1597. // Initialize the Delayed command server. This command server
  1598. // is really a timeout queue that the other command servers use
  1599. // to retry or check the state of previously issued commands that
  1600. // have an indeterminate completion time.
  1601. //
  1602. // WARN: MUST BE FIRST -- Some command servers may use this
  1603. // command server during their initialization.
  1604. //
  1605. WaitInitialize();
  1606. FrsDelCsInitialize();
  1607. //
  1608. // SETUP THE COMM LAYER
  1609. //
  1610. //
  1611. // Initialize the low level comm subsystem
  1612. //
  1613. CommInitializeCommSubsystem();
  1614. //
  1615. // Initialize the Send command server. The receive command server
  1616. // starts when we register our RPC interface.
  1617. //
  1618. SndCsInitialize();
  1619. //
  1620. // SETUP THE SUPPORT COMMAND SERVERS
  1621. //
  1622. //
  1623. // Staging file fetcher
  1624. //
  1625. FrsFetchCsInitialize();
  1626. //
  1627. // Initial Sync Controller
  1628. //
  1629. InitSyncCsInitialize();
  1630. //
  1631. // Staging file installer
  1632. //
  1633. FrsInstallCsInitialize();
  1634. //
  1635. // Staging file generator
  1636. //
  1637. FrsStageCsInitialize();
  1638. //
  1639. // outbound log processor
  1640. //
  1641. OutLogInitialize();
  1642. //
  1643. // LAST, KICK OFF REPLICATION
  1644. //
  1645. //
  1646. // MUST PRECEED DATABASE AND DS INITIALIZATION
  1647. //
  1648. // The DS command server and the Database command server depend on
  1649. // the replica control initialization.
  1650. //
  1651. // Initialize the replica control command server
  1652. //
  1653. RcsInitializeReplicaCmdServer();
  1654. //
  1655. // Actually, we can start the database at any time after the delayed
  1656. // command server and the replica control command server. But its
  1657. // a good idea to fail sooner than later to make cleanup more predictable.
  1658. //
  1659. DbsInitialize();
  1660. //
  1661. // Free up memory by reducing our working set size
  1662. //
  1663. SetProcessWorkingSetSize(ProcessHandle, (SIZE_T)-1, (SIZE_T)-1);
  1664. MainInitHasRun = TRUE;
  1665. LeaveCriticalSection(&MainInitLock);
  1666. }
  1667. VOID
  1668. MainMinimumInit(
  1669. VOID
  1670. )
  1671. /*++
  1672. Routine Description:
  1673. Initialize anything necessary to run the service
  1674. Arguments:
  1675. None.
  1676. Return Value:
  1677. TRUE - No problems
  1678. FALSE - Can't start service
  1679. --*/
  1680. {
  1681. #undef DEBSUB
  1682. #define DEBSUB "MainMinimumInit:"
  1683. //
  1684. // Setup the infrastructure
  1685. //
  1686. DbgMinimumInit();
  1687. //
  1688. // Check some NT to WIN error translations
  1689. //
  1690. FRS_ASSERT(WIN_NOT_IMPLEMENTED(FrsSetLastNTError(STATUS_NOT_IMPLEMENTED)));
  1691. FRS_ASSERT(WIN_SUCCESS(FrsSetLastNTError(STATUS_SUCCESS)));
  1692. FRS_ASSERT(WIN_ACCESS_DENIED(FrsSetLastNTError(STATUS_ACCESS_DENIED)));
  1693. FRS_ASSERT(WIN_INVALID_PARAMETER(FrsSetLastNTError(STATUS_INVALID_PARAMETER)));
  1694. FRS_ASSERT(WIN_NOT_FOUND(FrsSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND)));
  1695. //
  1696. // Initialize the DS command server
  1697. //
  1698. FrsDsInitialize();
  1699. //
  1700. // Free up memory by reducing our working set size
  1701. //
  1702. SetProcessWorkingSetSize(ProcessHandle, (SIZE_T)-1, (SIZE_T)-1);
  1703. }
  1704. PWCHAR *
  1705. MainConvertArgV(
  1706. DWORD ArgC,
  1707. PCHAR *ArgV
  1708. )
  1709. /*++
  1710. Routine Description:
  1711. Convert short char ArgV into wide char ArgV
  1712. Arguments:
  1713. ArgC - From main
  1714. ArgV - From main
  1715. Return Value:
  1716. Address of the new ArgV
  1717. --*/
  1718. {
  1719. #undef DEBSUB
  1720. #define DEBSUB "MainConvertArgV:"
  1721. PWCHAR *wideArgV;
  1722. wideArgV = FrsAlloc((ArgC + 1) * sizeof(PWCHAR));
  1723. wideArgV[ArgC] = NULL;
  1724. while (ArgC-- >= 1) {
  1725. wideArgV[ArgC] = FrsAlloc((strlen(ArgV[ArgC]) + 1) * sizeof(WCHAR));
  1726. wsprintf(wideArgV[ArgC], L"%hs", ArgV[ArgC]);
  1727. FRS_WCSLWR(wideArgV[ArgC]);
  1728. }
  1729. return wideArgV;
  1730. }
  1731. VOID
  1732. MainServiceHandler(
  1733. IN DWORD ControlCode
  1734. )
  1735. /*++
  1736. Routine Description:
  1737. Service handler. Called by the service controller runtime
  1738. Arguments:
  1739. ControlCode
  1740. Return Value:
  1741. None.
  1742. --*/
  1743. {
  1744. #undef DEBSUB
  1745. #define DEBSUB "MainServiceHandler:"
  1746. DPRINT1(0, ":S: Received control code %d from Service Controller\n",ControlCode);
  1747. switch (ControlCode) {
  1748. case SERVICE_CONTROL_STOP:
  1749. case SERVICE_CONTROL_SHUTDOWN:
  1750. DPRINT1(0, ":S: Service controller requests shutdown in %d seconds...\n",
  1751. ShutDownTimeOut);
  1752. FrsSetServiceStatus(SERVICE_STOP_PENDING, 0, ShutDownTimeOut * 1000, NO_ERROR);
  1753. FrsScmRequestedShutdown = TRUE;
  1754. FrsIsShuttingDown = TRUE;
  1755. SetEvent(ShutDownEvent);
  1756. return;
  1757. case SERVICE_CONTROL_PAUSE:
  1758. case SERVICE_CONTROL_CONTINUE:
  1759. DPRINT(0, ":S: SERVICE PAUSE/CONTINUE IS NOT IMPLEMENTED\n");
  1760. return;
  1761. case SERVICE_CONTROL_INTERROGATE:
  1762. return;
  1763. default:
  1764. DPRINT2(0, ":S: Handler for service %ws does not understand 0x%x\n",
  1765. SERVICE_NAME, ControlCode);
  1766. }
  1767. return;
  1768. }
  1769. VOID
  1770. WINAPI
  1771. MainRunningAsAService(
  1772. IN DWORD ArgC,
  1773. IN PWCHAR *ArgV
  1774. )
  1775. /*++
  1776. Routine Description:
  1777. Main routine when running as a service
  1778. Arguments:
  1779. ArgC - Ignored
  1780. ArgV - Ignored
  1781. Return Value:
  1782. None.
  1783. --*/
  1784. {
  1785. #undef DEBSUB
  1786. #define DEBSUB "MainRunningAsAService:"
  1787. HANDLE StartupThreadHandle;
  1788. DWORD StartupThreadId;
  1789. DWORD WStatus;
  1790. PDWORD ServiceWaitState = NULL;
  1791. DPRINT(0, "Running as a service\n");
  1792. //
  1793. // Register our handlers
  1794. //
  1795. ServiceStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, MainServiceHandler);
  1796. if (!ServiceStatusHandle) {
  1797. DPRINT1_WS(0, ":S: ERROR - No ServiceStatusHandle for %ws;",
  1798. SERVICE_NAME, GetLastError());
  1799. ServiceStatus.dwCurrentState = SERVICE_STOPPED;
  1800. ServiceStatus.dwWin32ExitCode = ERROR_PROCESS_ABORTED;
  1801. ServiceStatus.dwWaitHint = DEFAULT_SHUTDOWN_TIMEOUT * 1000;
  1802. return;
  1803. }
  1804. if (!FrsIsShuttingDown) {
  1805. FrsSetServiceStatus(SERVICE_START_PENDING,
  1806. 0,
  1807. DEFAULT_STARTUP_TIMEOUT * 1000,
  1808. NO_ERROR);
  1809. }
  1810. //
  1811. // Kick off a thread that updates the checkpoint and
  1812. // keeps the service controller from timing out.
  1813. // Allocate memory for data to be passed to another thread.
  1814. //
  1815. ServiceWaitState = FrsAlloc(sizeof(DWORD));
  1816. *ServiceWaitState = SERVICE_START_PENDING;
  1817. StartupThreadHandle = (HANDLE)CreateThread(NULL,
  1818. 0,
  1819. MainSCCheckPointUpdate,
  1820. ServiceWaitState,
  1821. 0,
  1822. &StartupThreadId);
  1823. if (!HANDLE_IS_VALID(StartupThreadHandle)) {
  1824. //
  1825. // Not a fatal error. It is OK to not update the checkpoint.
  1826. //
  1827. DPRINT_WS(4,":S: ERROR - Could not start thread to update startup checkpoint.", GetLastError());
  1828. }
  1829. //
  1830. // Finish rest of debug input
  1831. //
  1832. DbgMustInit(ArgC, WideArgV);
  1833. //
  1834. // Critical initialization
  1835. //
  1836. DPRINT1(4, "ArgC = %d\n", ArgC);
  1837. WStatus = MainMustInit(ArgC, WideArgV);
  1838. if (FRS_SUCCESS(WStatus)) {
  1839. //
  1840. // Necessary initialization
  1841. //
  1842. MainMinimumInit();
  1843. if (!FrsIsShuttingDown) {
  1844. //
  1845. // The core service has started.
  1846. //
  1847. FrsSetServiceStatus(SERVICE_RUNNING,
  1848. 0,
  1849. DEFAULT_STARTUP_TIMEOUT * 1000,
  1850. NO_ERROR);
  1851. //
  1852. // Init the service restart action if service fails.
  1853. //
  1854. FrsSetServiceFailureAction();
  1855. }
  1856. } else {
  1857. //
  1858. // Initialization failed; service can't start
  1859. //
  1860. DPRINT_WS(0, ":S: MainMustInit failed;", WStatus);
  1861. FrsSetServiceStatus(SERVICE_STOPPED,
  1862. 0,
  1863. DEFAULT_SHUTDOWN_TIMEOUT * 1000,
  1864. ERROR_PROCESS_ABORTED);
  1865. }
  1866. return;
  1867. }
  1868. ULONG
  1869. MainNotRunningAsAService(
  1870. IN DWORD ArgC,
  1871. IN PWCHAR *ArgV
  1872. )
  1873. /*++
  1874. Routine Description:
  1875. Main routine when not running as a service
  1876. Arguments:
  1877. ArgC - Ignored
  1878. ArgV - Ignored
  1879. Return Value:
  1880. Win32 status
  1881. --*/
  1882. {
  1883. #undef DEBSUB
  1884. #define DEBSUB "MainNotRunningAsAService:"
  1885. ULONG WStatus;
  1886. DPRINT(0, "Not running as a service\n");
  1887. //
  1888. // Finish rest of debug input
  1889. //
  1890. DbgMustInit(ArgC, WideArgV);
  1891. //
  1892. // Critical initialization
  1893. //
  1894. DPRINT1(4, "ArgC = %d\n", ArgC);
  1895. WStatus = MainMustInit(ArgC, WideArgV);
  1896. if (!FRS_SUCCESS(WStatus)) {
  1897. DPRINT_WS(0, ":S: MainMustInit failed;", WStatus);
  1898. ExitProcess(ERROR_NO_SYSTEM_RESOURCES);
  1899. }
  1900. //
  1901. // Necessary initialization
  1902. //
  1903. MainMinimumInit();
  1904. #if 0
  1905. //
  1906. // Kick off the test thread and forget about it
  1907. //
  1908. if (!ThSupCreateThread(L"TestThread", NULL, FrsTest, NULL)) {
  1909. DPRINT(0, ":S: Could not create FrsTest\n");
  1910. }
  1911. #endif
  1912. //
  1913. // Wait for shutdown
  1914. //
  1915. DPRINT(0, ":S: Waiting for shutdown event.\n");
  1916. WStatus = WaitForSingleObject(ShutDownEvent, INFINITE);
  1917. CHECK_WAIT_ERRORS(0, WStatus, 1, ACTION_CONTINUE);
  1918. DPRINT(0, ":S: Waiting for shutdown complete event.\n");
  1919. WStatus = WaitForSingleObject(ShutDownComplete, INFINITE);
  1920. CHECK_WAIT_ERRORS(0, WStatus, 1, ACTION_CONTINUE);
  1921. if (WIN_SUCCESS(WStatus)) {
  1922. DPRINT(0, ":S: ShutDownComplete event signalled.\n");
  1923. }
  1924. return WStatus;
  1925. }
  1926. ULONG
  1927. _cdecl
  1928. main(
  1929. IN INT ArgC,
  1930. IN PCHAR ArgV[]
  1931. )
  1932. /*++
  1933. Routine Description:
  1934. Main runs as either a service or an exe.
  1935. Arguments:
  1936. ArgC
  1937. ArgV
  1938. Return Value:
  1939. ERROR_SUCCESS - No problems
  1940. Otherwise - Something went wrong
  1941. --*/
  1942. {
  1943. #undef DEBSUB
  1944. #define DEBSUB "main:"
  1945. DWORD Len;
  1946. ULONG WStatus;
  1947. HRESULT hr;
  1948. SERVICE_TABLE_ENTRY ServiceTableEntry[] = {
  1949. { SERVICE_NAME, MainRunningAsAService },
  1950. { NULL, NULL }
  1951. };
  1952. //
  1953. // Process Handle
  1954. //
  1955. ProcessHandle = GetCurrentProcess();
  1956. //
  1957. // Disable any DPRINTs until we can init the debug component.
  1958. //
  1959. DebugInfo.Disabled = TRUE;
  1960. //
  1961. // Adjust the defaults for some tunable params.
  1962. //
  1963. CfgRegAdjustTuningDefaults();
  1964. //
  1965. // Get this Machine's name.
  1966. //
  1967. Len = MAX_COMPUTERNAME_LENGTH + 2;
  1968. ComputerName[0] = UNICODE_NULL;
  1969. GetComputerNameW(ComputerName, &Len);
  1970. ComputerName[Len] = UNICODE_NULL;
  1971. //
  1972. // Initialize the memory allocation subsystem
  1973. //
  1974. FrsInitializeMemAlloc();
  1975. //
  1976. // Perform as much work as possible in WCHAR
  1977. //
  1978. WideArgV = MainConvertArgV(ArgC, ArgV);
  1979. //
  1980. // Find out if we are running as a service or as an .exe
  1981. //
  1982. RunningAsAService = !FrsSearchArgv(ArgC, WideArgV, L"notservice", NULL);
  1983. //
  1984. // Synchronizes access between the shutdown thread and the
  1985. // service controller.
  1986. //
  1987. INITIALIZE_CRITICAL_SECTION(&ServiceLock);
  1988. //
  1989. // Initialize the debug lock
  1990. //
  1991. INITIALIZE_CRITICAL_SECTION(&DebugInfo.Lock);
  1992. INITIALIZE_CRITICAL_SECTION(&DebugInfo.DbsOutOfSpaceLock);
  1993. //
  1994. // Enable event logging
  1995. //
  1996. InitializeEventLog();
  1997. //
  1998. // This event log will not show up in the debug
  1999. // logs since it is written before debug logs are
  2000. // initialized. We do this because DbgInitLogTraceFile
  2001. // can produce a event log and we want to see the
  2002. // FRS starting event log before any other event
  2003. // logs.
  2004. //
  2005. EPRINT0(EVENT_FRS_STARTING);
  2006. //
  2007. // Init the debug trace log.
  2008. //
  2009. DbgInitLogTraceFile(ArgC, WideArgV);
  2010. WStatus = ERROR_SUCCESS;
  2011. try {
  2012. try {
  2013. if (RunningAsAService) {
  2014. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  2015. if (FAILED(hr)) {
  2016. DPRINT1(1,L"CoInitializeEx failed with hresult 0x%08lx\n", hr);
  2017. }
  2018. // initialize COM security
  2019. if (SUCCEEDED(hr)) {
  2020. hr = CoInitializeSecurity(
  2021. NULL, // sd
  2022. -1, // cAuthSvc
  2023. NULL, // asAuthSvc
  2024. NULL, // pReserved1
  2025. RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // dwAuthnLevel
  2026. RPC_C_IMP_LEVEL_IDENTIFY, // dwImpLevel
  2027. NULL, // pAuthList
  2028. EOAC_NONE, // dwCapabilities
  2029. NULL // pReserved3
  2030. );
  2031. if (FAILED(hr)) {
  2032. DPRINT1(1,L"CoInitializeSecurity failed with hresult 0x%08lx\n", hr);
  2033. CoUninitialize();
  2034. }
  2035. }
  2036. //
  2037. // RUNNING AS A SERVICE
  2038. //
  2039. if (!StartServiceCtrlDispatcher(ServiceTableEntry)) {
  2040. WStatus = GetLastError();
  2041. DPRINT1_WS(0, "Could not start dispatcher for service %ws;",
  2042. SERVICE_NAME, WStatus);
  2043. }
  2044. if (SUCCEEDED(hr)) {
  2045. CoUninitialize();
  2046. }
  2047. } else {
  2048. //
  2049. // NOT A SERVICE
  2050. //
  2051. MainNotRunningAsAService(ArgC, WideArgV);
  2052. }
  2053. } except (FrsException(GetExceptionInformation())) {
  2054. }
  2055. } finally {
  2056. if (AbnormalTermination()) {
  2057. WStatus = ERROR_INVALID_ACCESS;
  2058. }
  2059. }
  2060. return WStatus;
  2061. }