453 lines
13 KiB
C
453 lines
13 KiB
C
|
/*++
|
|||
|
|
|||
|
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);
|
|||
|
}
|