Windows-Server-2003/sdktools/memsnap/sortlog.c

380 lines
10 KiB
C

// sortlog.c
//
// this program sorts memsnap and poolsnap logs into a more readable form
// sorts by pid
// scans the data file one time, inserts record offsets based on PID into linked list
// then writes data into new file in sorted order
// determine whether we have a poolsnap or memsnap log - in pid is equivalent
// to pooltag for our sorting
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <io.h>
#include <stdlib.h>
// definitions
#define RECSIZE 1024 // record size (max line size)
#define MAXTAGSIZE 200 // max length of tag name
#define PIDSIZE (sizeof(HANDLE) << 1) //Buffer size needed to store hex pid
#define DEFAULT_INFILE "memsnap.log"
#define DEFAULT_OUTFILE "memsort.log"
typedef enum _FILE_LOG_TYPES {
MEMSNAPLOG=0,
POOLSNAPLOG,
UNKNOWNLOG
} FILE_LOG_TYPES;
//
// Linked list of unique PID or PoolTag
//
struct PIDList {
char PIDItem[PIDSIZE + 1];
struct RecList* RecordList;
struct PIDList* Next;
DWORD Count; // number of items pointed to by RecordList
};
//
// For each PID or pool tag, we have a linked list of offsets into file of each line
//
struct RecList {
LONG rOffset;
struct RecList* Next;
};
// global data
FILE_LOG_TYPES CurrentFileType= UNKNOWNLOG;
CHAR szHeader[RECSIZE]; // first line of file
BOOL bIgnoreTransients= FALSE; // Ignore tags or processes that aren't in every snapshot
DWORD g_MaxSnapShots= 0; // max snap shots in the file
#define INVALIDOFFSET (-2) /* invalid file offset */
// prototypes
VOID ScanFile(FILE *, struct PIDList *);
VOID WriteFilex(FILE *, FILE *, struct PIDList *);
VOID SortlogUsage(VOID)
{
printf("sortlog [-?] [<logfile>] [<outfile>]\n");
printf("Sorts an outputfile from memsnap.exe/poolsnap.exe in PID/PoolTag order\n");
printf("-? prints this help\n");
printf("-i ignore tags or processes that are not in every snapshot\n");
printf("<logfile> = %s by default\n",DEFAULT_INFILE );
printf("<outfile> = %s by default\n",DEFAULT_OUTFILE);
exit(-1);
}
// CheckPointer
//
// Make sure it is not NULL. Otherwise print error message and exit.
//
VOID CheckPointer( PVOID ptr )
{
if( ptr == NULL ) {
printf("Out of memory\n");
exit(-1);
}
}
#include "tags.c"
#if defined(SORTLOG_INCLUDED)
int __cdecl SortlogMain (int argc, char* argv[])
#else
int __cdecl main (int argc, char* argv[])
#endif
{
FILE* InFile;
FILE* OutFile;
struct PIDList ThePIDList = {0};
CHAR* pszInFile= NULL; // input filename
CHAR* pszOutFile= NULL; // output filename
INT iFileIndex= 0;
INT iCmdIndex; // index into argv
ThePIDList.RecordList = (struct RecList *)LocalAlloc(LPTR, sizeof(struct RecList));
CheckPointer( ThePIDList.RecordList );
ThePIDList.RecordList->rOffset= INVALIDOFFSET;
//
// parse command line
//
for( iCmdIndex=1; iCmdIndex<argc; iCmdIndex++ ) {
CHAR chr;
chr= argv[iCmdIndex][0];
if( (chr=='-') || (chr=='/') ) {
chr= argv[iCmdIndex][1];
switch( chr ) {
case '?':
SortlogUsage();
break;
case 'i': // ignore all process that weren't running the whole time
bIgnoreTransients= TRUE;
break;
default:
printf("Invalid switch %s\n",argv[iCmdIndex]);
SortlogUsage();
break;
}
}
else {
if( iFileIndex == 0 ) {
pszInFile= argv[iCmdIndex];
iFileIndex++;
}
else if( iFileIndex == 1 ) {
pszOutFile= argv[iCmdIndex];
iFileIndex++;
}
else {
printf("Too many files specified\n");
SortlogUsage();
}
}
}
//
// fill in default filenames if some aren't given
//
switch( iFileIndex ) {
case 0:
pszInFile= DEFAULT_INFILE;
pszOutFile= DEFAULT_OUTFILE;
break;
case 1:
pszOutFile= DEFAULT_OUTFILE;
break;
default:
break;
}
//
// open the files
//
InFile= fopen( pszInFile, "r" );
if( InFile == NULL ) {
printf("Error opening input file %s\n",pszInFile);
return( 0 );
}
OutFile= fopen( pszOutFile, "w" );
if( OutFile == NULL ) {
printf("Error opening output file %s\n",pszOutFile);
return( 0 );
}
//
// read in the data and set up the list
//
ScanFile(InFile, &ThePIDList);
//
// write the output file
//
WriteFilex(InFile, OutFile, &ThePIDList);
// close and exit
_fcloseall();
return 0;
}
// read the input file and get the offset to each record in order and put in list
VOID ScanFile(FILE *InFile, struct PIDList *ThePIDList)
{
char inchar = 0;
char inBuff[RECSIZE] = {0};
char PID[PIDSIZE + 1] = {0};
LONG Offset = 0;
BOOL Found = FALSE;
struct PIDList *TmpPIDList;
struct RecList *TmpRecordList;
INT iGarb = 0;
/* initialize temp list pointer */
TmpPIDList = ThePIDList;
/* read to the first newline, check for EOF */
/* determine whether it is a poolsnap or memsnap log */
if ((fscanf(InFile, "%[^\n]", &szHeader)) == EOF)
return;
if (strncmp("Process ID", szHeader, 10) == 0)
CurrentFileType= MEMSNAPLOG;
if (strncmp(" Tag Type", szHeader, 10) == 0)
CurrentFileType= POOLSNAPLOG;
if( CurrentFileType == UNKNOWNLOG )
{
printf("unrecognized log file\n");
return;
}
inBuff[0] = 0;
/* read to the end of file */
while (!feof(InFile)) {
/* record the offset */
Offset = ftell(InFile);
/* if first char == newline, skip to next */
if ((fscanf(InFile, "%[^\n]", inBuff)) == EOF) {
return;
}
/* read past delimiter */
inchar = (char)fgetc(InFile);
// skip if its an empty line
if (strlen(inBuff) == 0) {
continue;
}
//
// Handle tags if this is a tagged line
//
if( inBuff[0] == '!' )
{
ProcessTag( inBuff+1 );
continue;
}
if (3 == sscanf(inBuff, "%2u\\%2u\\%4u", &iGarb, &iGarb, &iGarb)){
continue;
}
/* read the PID */
strncpy(PID,inBuff,PIDSIZE);
// scan list of PIDS, find matching, if no matching, make new one
// keep this list sorted
TmpPIDList = ThePIDList; /* point to top of list */
Found= FALSE;
while( TmpPIDList->Next != 0 ) {
int iComp;
iComp= strcmp( PID, TmpPIDList->PIDItem);
if( iComp == 0 ) { // found
Found= TRUE;
break;
} else { // not found
if( iComp < 0 ) { // exit if we have gone far enough
break;
}
TmpPIDList= TmpPIDList->Next;
}
}
// if matching, append offset to RecordList
// add offset to current PID list
if( Found ) {
TmpPIDList->Count= TmpPIDList->Count + 1;
if( TmpPIDList->Count > g_MaxSnapShots ) g_MaxSnapShots= TmpPIDList->Count;
TmpRecordList= TmpPIDList->RecordList;
// walk to end of list
while( TmpRecordList->Next != 0 ) {
TmpRecordList= TmpRecordList->Next;
}
TmpRecordList->Next= (struct RecList*)LocalAlloc(LPTR, sizeof(struct RecList));
CheckPointer( TmpRecordList->Next );
TmpRecordList->Next->rOffset= Offset;
}
// make new PID list, add new PID, add offset
else {
struct PIDList* pNewPID;
// allocate a new PID,
// copy current PID information to it
// overwrite current PID information with new PID information
// have current PID point to new PID which may point on
pNewPID= (struct PIDList*) LocalAlloc(LPTR, sizeof(struct PIDList));
CheckPointer( pNewPID );
memcpy( pNewPID, TmpPIDList, sizeof(*pNewPID) );
strcpy( TmpPIDList->PIDItem, PID );
TmpPIDList->RecordList= (struct RecList*) LocalAlloc(LPTR, sizeof(struct RecList));
CheckPointer( TmpPIDList->RecordList );
TmpPIDList->RecordList->rOffset= Offset;
TmpPIDList->Next= pNewPID;
TmpPIDList->Count= 1;
}
/* if EOF, return */
/* clear the inBuff */
inBuff[0] = 0;
}
}
// look for the next PID line in the first table
VOID WriteFilex(FILE *InFile, FILE *OutFile, struct PIDList *ThePIDList)
{
struct PIDList *TmpPIDList;
struct RecList *TmpRecordList;
char inBuff[RECSIZE] = {0};
/* initialize temp list pointer */
TmpPIDList = ThePIDList;
/* heading */
fprintf(OutFile,"%s\n",szHeader);
OutputTags( OutFile );
/* while not end of list, write records at offset to end of output file */
while (TmpPIDList != 0) {
TmpRecordList = TmpPIDList->RecordList;
if( (!bIgnoreTransients) || (TmpPIDList->Count == g_MaxSnapShots) ) {
while (TmpRecordList != 0) {
LONG Offset;
Offset= TmpRecordList->rOffset;
if( Offset != INVALIDOFFSET ) {
/* read in record */
if (fseek(InFile, TmpRecordList->rOffset, SEEK_SET) == -1) break;
if (fscanf(InFile, "%[^\n]", inBuff) != 1) break;
/* read out record */
fprintf(OutFile, "%s\n", inBuff);
}
/* get next record */
TmpRecordList = TmpRecordList->Next;
}
/* add a line here */
fputc('\n', OutFile);
}
/* get next record */
TmpPIDList = TmpPIDList->Next;
}
}