/*++ Copyright (c) 1997-1999 Microsoft Corporation Module Name: ntfrsutl.c Abstract: This is a utility program to help debug File Replication Service. It dumps the internal tables, thread and memory information. It runs on local as well as remote server. It uses RPC to communicate with the service. Author: Sudarshan Chitre 12-Aug-1999 Environment User mode, winnt32 --*/ #include #pragma hdrstop #include #include VOID Win32ToMsg ( IN PWCHAR Prefix, IN DWORD WindowsErrorCode ) /*++ Routine Description: Translate a error code into a error message using FormatMessage() and print to stderr. If no message is available, the error code is printed in decimal and hex. Arguments: Prefix - prefix to error message WStatus - Standard win32 error code. Return Value: None. --*/ { DWORD NumChar; PWCHAR Buffer; // // Use the system formatter for standard error codes // NumChar = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, WindowsErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &Buffer, 0, NULL ); if (NumChar) { fprintf(stderr, "%ws %ws\n", Prefix, Buffer); } else { fprintf(stderr, "%ws Status %d (0x%08x)\n", Prefix, WindowsErrorCode, WindowsErrorCode); } LocalFree( Buffer ); } VOID Usage( IN DWORD ExitStatus ) /*++ Routine Description: Print usage and exit Arguments: ExitStatus - exits with this status Return Value: Exit(ExitStatus) --*/ { printf("Ntfrsutl dumps the internal tables, thread and memory information\n"); printf("for the ntfrs service.It runs against local as well as remote server.\n\n"); printf("Note : To access the internal information, the logged in user should\n"); printf(" have the required access on the following registry keys on the\n"); printf(" target server.\n\n"); printf(" HKLM\\System\\CCS\\Services\\Ntfrs\\Parameters\\Access Checks\\\n"); printf(" Get Internal Information : Full control\n"); printf(" Get Ds Polling Interval : Read\n"); printf(" Set Ds Polling Interval : Full Control\n\n"); printf("ntfrsutl [idtable | configtable | inlog | outlog] [computer]\n"); printf("\t = enumerate the service's idtable/configtable/inlog/outlog \n"); printf("\tcomputer = talk to the NtFrs service on this machine.\n"); printf("\n"); printf("ntfrsutl [memory|threads|stage] [computer]\n"); printf("\t = list the service's memory usage\n"); printf("\tcomputer = talk to the NtFrs service on this machine.\n"); printf("\n"); printf("ntfrsutl ds [computer]\n"); printf("\t = list the service's view of the DS\n"); printf("\tcomputer = talk to the NtFrs service on this machine.\n"); printf("\n"); printf("ntfrsutl sets [computer]\n"); printf("\t = list the active replica sets\n"); printf("\tcomputer = talk to the NtFrs service on this machine.\n"); printf("\n"); printf("ntfrsutl version [computer]\n"); printf("\t = list the api and service versions\n"); printf("\tcomputer = talk to the NtFrs service on this machine.\n"); printf("\n"); printf("ntfrsutl poll [/quickly[=[N]]] [/slowly[=[N]]] [/now] [computer]\n"); printf("\t = list the current polling intervals.\n"); printf("\tnow = Poll now.\n"); printf("\tquickly = Poll quickly until stable configuration retrieved.\n"); printf("\tquickly= = Poll quickly every default minutes.\n"); printf("\tquickly=N = Poll quickly every N minutes.\n"); printf("\tslowly = Poll slowly until stable configuration retrieved.\n"); printf("\tslowly= = Poll slowly every default minutes.\n"); printf("\tslowly=N = Poll slowly every N minutes.\n"); printf("\tcomputer = talk to the NtFrs service on this machine.\n"); printf("\n"); exit(ExitStatus); } PWCHAR * ConvertArgv( DWORD argc, PCHAR *argv ) /*++ Routine Description: Convert short char argv into wide char argv Arguments: argc - From main argv - From main Return Value: Address of the new argv --*/ { PWCHAR *wideargv; wideargv = LocalAlloc(LMEM_FIXED, (argc + 1) * sizeof(PWCHAR)); if (wideargv == NULL) { fprintf(stderr, "Can't get memory; Win32 Status %d\n", GetLastError()); exit(1); } wideargv[argc] = NULL; while (argc-- >= 1) { wideargv[argc] = LocalAlloc(LMEM_FIXED, (strlen(argv[argc]) + 1) * sizeof(WCHAR)); if (wideargv[argc] == NULL) { fprintf(stderr, "Can't get memory; Win32 Status %d\n", GetLastError()); exit(1); } wsprintf(wideargv[argc], L"%hs", argv[argc]); FRS_WCSLWR(wideargv[argc]); } return wideargv; } VOID ProcessPoll( IN DWORD argc, IN PWCHAR *Argv ) /*++ Routine Description: Process the command line for the subcommand poll. Arguments: argc Argv Return Value: Exits with 0 if everything went okay. Otherwise, 1. --*/ { DWORD WStatus; DWORD i; ULONG LongInterval; ULONG ShortInterval; ULONG UseShortInterval; ULONG Interval; DWORD ComputerLen; PWCHAR LocalComputerName; BOOL SetInterval; // // Initialize the input parameters // LongInterval = 0; ShortInterval = 0; UseShortInterval = 0; LocalComputerName = NULL; SetInterval = FALSE; for (i = 2; i < argc; ++i) { // // Process options for poll // // // Not a parameter; must be the computer name // if (*Argv[i] != L'/' && *Argv[i] != L'-') { if (LocalComputerName) { fprintf(stderr, "Multiple computer names are not allowed\n"); Usage(1); } LocalComputerName = Argv[i]; // // /? // } else if (wcsstr(Argv[i] + 1, L"?") == Argv[i] + 1) { Usage(0); // // /quickly // } else if (!_wcsnicmp(Argv[i], L"/quickly", 8)) { SetInterval = TRUE; UseShortInterval = 1; if (*(Argv[i] + 8) != L'\0') { if (*(Argv[i] + 8) != L'=') { fprintf(stderr, "Don't understand %ws\n", Argv[i]); Usage(1); } if (*(Argv[i] + 9) == L'\0') { ShortInterval = NTFRSAPI_DEFAULT_SHORT_INTERVAL; } else { ShortInterval = wcstoul(Argv[i] + 9, NULL, 10); } if (ShortInterval < NTFRSAPI_MIN_INTERVAL || ShortInterval > NTFRSAPI_MAX_INTERVAL) { fprintf(stderr, "Interval must be between %d and %d\n", NTFRSAPI_MIN_INTERVAL, NTFRSAPI_MAX_INTERVAL); Usage(1); } } // // /slowly // } else if (!_wcsnicmp(Argv[i], L"/slowly", 7)) { SetInterval = TRUE; if (*(Argv[i] + 7) != L'\0') { if (*(Argv[i] + 7) != L'=') { fprintf(stderr, "Don't understand %ws\n", Argv[i]); Usage(1); } if (*(Argv[i] + 8) == L'\0') { LongInterval = NTFRSAPI_DEFAULT_LONG_INTERVAL; } else { LongInterval = wcstoul(Argv[i] + 8, NULL, 10); } if (LongInterval < NTFRSAPI_MIN_INTERVAL || LongInterval > NTFRSAPI_MAX_INTERVAL) { fprintf(stderr, "Interval must be between %d and %d\n", NTFRSAPI_MIN_INTERVAL, NTFRSAPI_MAX_INTERVAL); Usage(1); } } // // /now // } else if (!_wcsnicmp(Argv[i], L"/now", 4)) { SetInterval = TRUE; if (*(Argv[i] + 4) != L'\0') { fprintf(stderr, "Don't understand %ws\n", Argv[i]); Usage(1); } // // Don't understand // } else { fprintf(stderr, "Don't understand %ws\n", Argv[i]); Usage(1); } } if (SetInterval) { // // Set the interval and initiate a new polling cycle // WStatus = NtFrsApi_Set_DsPollingIntervalW(LocalComputerName, UseShortInterval, LongInterval, ShortInterval); if (!WIN_SUCCESS(WStatus)) { Win32ToMsg(L"Can't set interval:", WStatus); exit(1); } } else { // // Get the current polling cycles // WStatus = NtFrsApi_Get_DsPollingIntervalW(LocalComputerName, &Interval, &LongInterval, &ShortInterval); if (!WIN_SUCCESS(WStatus)) { Win32ToMsg(L"Can't get intervals:", WStatus); exit(1); } printf("Current Interval: %6d minutes\n", Interval); printf("Short Interval : %6d minutes\n", ShortInterval); printf("Long Interval : %6d minutes\n", LongInterval); } exit(0); } VOID ProcessWriterCommand( IN DWORD argc, IN PWCHAR *Argv, IN ULONG Command ) /*++ Routine Description: Make calls to freeze and thaw. Arguments: Command - command to send to the FRS service. Return Value: Exits with 0 if everything went okay. Otherwise, 1. --*/ { DWORD WStatus; PWCHAR LocalComputerName = NULL; if (argc > 2) { LocalComputerName = Argv[2]; } WStatus = NtFrsApi_WriterCommand(LocalComputerName, Command); if (!WIN_SUCCESS(WStatus)) { Win32ToMsg(L"Can't call writer APIs", WStatus); exit(1); } exit(0); } VOID ProcessDump( IN DWORD argc, IN PWCHAR *Argv, IN DWORD TypeOfInformation ) /*++ Routine Description: Dump bunches of stuff Arguments: argc Argv TypeOfInformation Return Value: Exits with 0 if everything went okay. Otherwise, 1. --*/ { DWORD WStatus; PCHAR Line; BOOL FirstTime = TRUE; PVOID Info = NULL; PWCHAR LocalComputerName = NULL; if (argc > 2) { LocalComputerName = Argv[2]; } do { WStatus = NtFrsApi_InfoW(LocalComputerName, TypeOfInformation, 0, &Info); if (!WIN_SUCCESS(WStatus)) { fprintf(stderr, "ERROR NtFrsApi_InfoW() Error %d\n", WStatus); NtFrsApi_InfoFreeW(&Info); exit(1); } if (Info) { if (!FirstTime) { printf("===== THE FOLLOWING INFO MAY BE INCONSISTENT DUE TO REFETCH =====\n"); } FirstTime = FALSE; Line = NULL; do { WStatus = NtFrsApi_InfoLineW(Info, &Line); if (!WIN_SUCCESS(WStatus)) { fprintf(stderr, "ERROR NtFrsApi_InfoLineW() Error %d\n", WStatus); NtFrsApi_InfoFreeW(&Info); exit(1); } if (Line) { printf("%s", Line); } } while (Line); } } while (Info); exit(0); } VOID _cdecl main( IN DWORD argc, IN PCHAR *argv ) /*++ Routine Description: Process the command line. Arguments: argc argv Return Value: Exits with 0 if everything went okay. Otherwise, 1. --*/ { PWCHAR *Argv; // // Print usage and exit // if (argc == 1) { Usage(0); } // // Use wide char parameters // Argv = ConvertArgv(argc, argv); // // Find the subcommand // if (!wcscmp(Argv[1], L"poll")) { ProcessPoll(argc, Argv); } else if (!_wcsicmp(Argv[1], L"version")) { ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_VERSION); } else if (!_wcsicmp(Argv[1], L"sets")) { ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_SETS); } else if (!_wcsicmp(Argv[1], L"ds")) { ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_DS); } else if (!_wcsicmp(Argv[1], L"memory")) { ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_MEMORY); } else if (!_wcsicmp(Argv[1], L"idtable")) { ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_IDTABLE); } else if (!_wcsicmp(Argv[1], L"configtable")) { ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_CONFIGTABLE); } else if (!_wcsicmp(Argv[1], L"inlog")) { ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_INLOG); } else if (!_wcsicmp(Argv[1], L"outlog")) { ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_OUTLOG); } else if (!_wcsicmp(Argv[1], L"threads")) { ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_THREADS); } else if (!_wcsicmp(Argv[1], L"stage")) { ProcessDump(argc, Argv, NTFRSAPI_INFO_TYPE_STAGE); } #if 0 else if (!_wcsicmp(Argv[1], L"freeze")) { ProcessWriterCommand(argc, Argv, NTFRSAPI_WRITER_COMMAND_FREEZE); } else if (!_wcsicmp(Argv[1], L"thaw")) { ProcessWriterCommand(argc, Argv, NTFRSAPI_WRITER_COMMAND_THAW); } #endif else if (!_wcsicmp(Argv[1], L"/?")) { Usage(0); } else { fprintf(stderr, "Don't understand %ws\n", Argv[1]); } exit(0); }