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.

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