// 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 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 // typedef struct PIDList { char PIDItem[11]; 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 // typedef 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 Usage(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" int __cdecl main(int argc, char* argv[]) { 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 '?': Usage(); break; case 'i': // ignore all process that weren't running the whole time bIgnoreTransients= TRUE; break; default: printf("Invalid switch %s\n",argv[iCmdIndex]); Usage(); break; } } else { if( iFileIndex == 0 ) { pszInFile= argv[iCmdIndex]; iFileIndex++; } else if( iFileIndex == 1 ) { pszOutFile= argv[iCmdIndex]; iFileIndex++; } else { printf("Too many files specified\n"); Usage(); } } } // // 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, "a" ); 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[11] = {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,10); // 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; } }