windows-nt/Source/XPSP1/NT/ds/netapi/svcimgs/ntrepl/ntfrsutl/ntfrsutl.c
2020-09-26 16:20:57 +08:00

453 lines
13 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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 <ntreppch.h>
#pragma hdrstop
#include <frs.h>
#include <ntfrsapi.h>
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 ComputerName;
BOOL SetInterval;
//
// Initialize the input parameters
//
LongInterval = 0;
ShortInterval = 0;
UseShortInterval = 0;
ComputerName = 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 (ComputerName) {
fprintf(stderr, "Multiple computer names are not allowed\n");
Usage(1);
}
ComputerName = 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(ComputerName,
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(ComputerName,
&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
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 ComputerName = NULL;
if (argc > 2) {
ComputerName = Argv[2];
}
do {
WStatus = NtFrsApi_InfoW(ComputerName,
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);
} else if (!_wcsicmp(Argv[1], L"/?")) {
Usage(0);
} else {
fprintf(stderr, "Don't understand %ws\n", Argv[1]);
}
exit(0);
}