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);
|
||
}
|