Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

373 lines
9.8 KiB

  1. // sortlog.c
  2. //
  3. // this program sorts memsnap and poolsnap logs into a more readable form
  4. // sorts by pid
  5. // scans the data file one time, inserts record offsets based on PID into linked list
  6. // then writes data into new file in sorted order
  7. // determine whether we have a poolsnap or memsnap log - in pid is equivalent
  8. // to pooltag for our sorting
  9. #include <windows.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <io.h>
  13. #include <stdlib.h>
  14. // definitions
  15. #define RECSIZE 1024 // record size (max line size)
  16. #define MAXTAGSIZE 200 // max length of tag name
  17. #define DEFAULT_INFILE "memsnap.log"
  18. #define DEFAULT_OUTFILE "memsort.log"
  19. typedef enum _FILE_LOG_TYPES {
  20. MEMSNAPLOG=0,
  21. POOLSNAPLOG,
  22. UNKNOWNLOG
  23. } FILE_LOG_TYPES;
  24. //
  25. // Linked list of unique PID or PoolTag
  26. //
  27. typedef struct PIDList {
  28. char PIDItem[11];
  29. struct RecList* RecordList;
  30. struct PIDList* Next;
  31. DWORD Count; // number of items pointed to by RecordList
  32. };
  33. //
  34. // For each PID or pool tag, we have a linked list of offsets into file of each line
  35. //
  36. typedef struct RecList {
  37. LONG rOffset;
  38. struct RecList* Next;
  39. };
  40. // global data
  41. FILE_LOG_TYPES CurrentFileType= UNKNOWNLOG;
  42. CHAR szHeader[RECSIZE]; // first line of file
  43. BOOL bIgnoreTransients= FALSE; // Ignore tags or processes that aren't in every snapshot
  44. DWORD g_MaxSnapShots= 0; // max snap shots in the file
  45. #define INVALIDOFFSET (-2) /* invalid file offset */
  46. // prototypes
  47. VOID ScanFile(FILE *, struct PIDList *);
  48. VOID WriteFilex(FILE *, FILE *, struct PIDList *);
  49. VOID Usage(VOID)
  50. {
  51. printf("sortlog [-?] [<logfile>] [<outfile>]\n");
  52. printf("Sorts an outputfile from memsnap.exe/poolsnap.exe in PID/PoolTag order\n");
  53. printf("-? prints this help\n");
  54. printf("-i ignore tags or processes that are not in every snapshot\n");
  55. printf("<logfile> = %s by default\n",DEFAULT_INFILE );
  56. printf("<outfile> = %s by default\n",DEFAULT_OUTFILE);
  57. exit(-1);
  58. }
  59. // CheckPointer
  60. //
  61. // Make sure it is not NULL. Otherwise print error message and exit.
  62. //
  63. VOID CheckPointer( PVOID ptr )
  64. {
  65. if( ptr == NULL ) {
  66. printf("Out of memory\n");
  67. exit(-1);
  68. }
  69. }
  70. #include "tags.c"
  71. int __cdecl main(int argc, char* argv[])
  72. {
  73. FILE* InFile;
  74. FILE* OutFile;
  75. struct PIDList ThePIDList = {0};
  76. CHAR* pszInFile= NULL; // input filename
  77. CHAR* pszOutFile= NULL; // output filename
  78. INT iFileIndex= 0;
  79. INT iCmdIndex; // index into argv
  80. ThePIDList.RecordList = (struct RecList *)LocalAlloc(LPTR, sizeof(struct RecList));
  81. CheckPointer( ThePIDList.RecordList );
  82. ThePIDList.RecordList->rOffset= INVALIDOFFSET;
  83. //
  84. // parse command line
  85. //
  86. for( iCmdIndex=1; iCmdIndex<argc; iCmdIndex++ ) {
  87. CHAR chr;
  88. chr= argv[iCmdIndex][0];
  89. if( (chr=='-') || (chr=='/') ) {
  90. chr= argv[iCmdIndex][1];
  91. switch( chr ) {
  92. case '?':
  93. Usage();
  94. break;
  95. case 'i': // ignore all process that weren't running the whole time
  96. bIgnoreTransients= TRUE;
  97. break;
  98. default:
  99. printf("Invalid switch %s\n",argv[iCmdIndex]);
  100. Usage();
  101. break;
  102. }
  103. }
  104. else {
  105. if( iFileIndex == 0 ) {
  106. pszInFile= argv[iCmdIndex];
  107. iFileIndex++;
  108. }
  109. else if( iFileIndex == 1 ) {
  110. pszOutFile= argv[iCmdIndex];
  111. iFileIndex++;
  112. }
  113. else {
  114. printf("Too many files specified\n");
  115. Usage();
  116. }
  117. }
  118. }
  119. //
  120. // fill in default filenames if some aren't given
  121. //
  122. switch( iFileIndex ) {
  123. case 0:
  124. pszInFile= DEFAULT_INFILE;
  125. pszOutFile= DEFAULT_OUTFILE;
  126. break;
  127. case 1:
  128. pszOutFile= DEFAULT_OUTFILE;
  129. break;
  130. default:
  131. break;
  132. }
  133. //
  134. // open the files
  135. //
  136. InFile= fopen( pszInFile, "r" );
  137. if( InFile == NULL ) {
  138. printf("Error opening input file %s\n",pszInFile);
  139. return( 0 );
  140. }
  141. OutFile= fopen( pszOutFile, "a" );
  142. if( OutFile == NULL ) {
  143. printf("Error opening output file %s\n",pszOutFile);
  144. return( 0 );
  145. }
  146. //
  147. // read in the data and set up the list
  148. //
  149. ScanFile(InFile, &ThePIDList);
  150. //
  151. // write the output file
  152. //
  153. WriteFilex(InFile, OutFile, &ThePIDList);
  154. // close and exit
  155. _fcloseall();
  156. return 0;
  157. }
  158. // read the input file and get the offset to each record in order and put in list
  159. VOID ScanFile(FILE *InFile, struct PIDList *ThePIDList)
  160. {
  161. char inchar = 0;
  162. char inBuff[RECSIZE] = {0};
  163. char PID[11] = {0};
  164. LONG Offset = 0;
  165. BOOL Found = FALSE;
  166. struct PIDList *TmpPIDList;
  167. struct RecList *TmpRecordList;
  168. INT iGarb = 0;
  169. /* initialize temp list pointer */
  170. TmpPIDList = ThePIDList;
  171. /* read to the first newline, check for EOF */
  172. /* determine whether it is a poolsnap or memsnap log */
  173. if ((fscanf(InFile, "%[^\n]", &szHeader)) == EOF)
  174. return;
  175. if (strncmp("Process ID", szHeader, 10) == 0)
  176. CurrentFileType= MEMSNAPLOG;
  177. if (strncmp(" Tag Type", szHeader, 10) == 0)
  178. CurrentFileType= POOLSNAPLOG;
  179. if( CurrentFileType == UNKNOWNLOG )
  180. {
  181. printf("unrecognized log file\n");
  182. return;
  183. }
  184. inBuff[0] = 0;
  185. /* read to the end of file */
  186. while (!feof(InFile)) {
  187. /* record the offset */
  188. Offset = ftell(InFile);
  189. /* if first char == newline, skip to next */
  190. if ((fscanf(InFile, "%[^\n]", &inBuff)) == EOF)
  191. return;
  192. /* read past delimiter */
  193. inchar = (char)fgetc(InFile);
  194. // skip if its an empty line
  195. if (strlen(inBuff) == 0) {
  196. continue;
  197. }
  198. //
  199. // Handle tags if this is a tagged line
  200. //
  201. if( inBuff[0] == '!' )
  202. {
  203. ProcessTag( inBuff+1 );
  204. continue;
  205. }
  206. if (3 == sscanf(inBuff, "%2u\\%2u\\%4u", &iGarb, &iGarb, &iGarb)){
  207. continue;
  208. }
  209. /* read the PID */
  210. strncpy(PID,inBuff,10);
  211. // scan list of PIDS, find matching, if no matching, make new one
  212. // keep this list sorted
  213. TmpPIDList = ThePIDList; /* point to top of list */
  214. Found= FALSE;
  215. while( TmpPIDList->Next != 0 ) {
  216. int iComp;
  217. iComp= strcmp( PID, TmpPIDList->PIDItem);
  218. if( iComp == 0 ) { // found
  219. Found= TRUE;
  220. break;
  221. } else { // not found
  222. if( iComp < 0 ) { // exit if we have gone far enough
  223. break;
  224. }
  225. TmpPIDList= TmpPIDList->Next;
  226. }
  227. }
  228. // if matching, append offset to RecordList
  229. // add offset to current PID list
  230. if( Found ) {
  231. TmpPIDList->Count= TmpPIDList->Count + 1;
  232. if( TmpPIDList->Count > g_MaxSnapShots ) g_MaxSnapShots= TmpPIDList->Count;
  233. TmpRecordList= TmpPIDList->RecordList;
  234. // walk to end of list
  235. while( TmpRecordList->Next != 0 ) {
  236. TmpRecordList= TmpRecordList->Next;
  237. }
  238. TmpRecordList->Next= (struct RecList*)LocalAlloc(LPTR, sizeof(struct RecList));
  239. CheckPointer( TmpRecordList->Next );
  240. TmpRecordList->Next->rOffset= Offset;
  241. }
  242. // make new PID list, add new PID, add offset
  243. else {
  244. struct PIDList* pNewPID;
  245. // allocate a new PID,
  246. // copy current PID information to it
  247. // overwrite current PID information with new PID information
  248. // have current PID point to new PID which may point on
  249. pNewPID= (struct PIDList*) LocalAlloc(LPTR, sizeof(struct PIDList));
  250. CheckPointer( pNewPID );
  251. memcpy( pNewPID, TmpPIDList, sizeof(*pNewPID) );
  252. strcpy( TmpPIDList->PIDItem, PID );
  253. TmpPIDList->RecordList= (struct RecList*) LocalAlloc(LPTR, sizeof(struct RecList));
  254. CheckPointer( TmpPIDList->RecordList );
  255. TmpPIDList->RecordList->rOffset= Offset;
  256. TmpPIDList->Next= pNewPID;
  257. TmpPIDList->Count= 1;
  258. }
  259. /* if EOF, return */
  260. /* clear the inBuff */
  261. inBuff[0] = 0;
  262. }
  263. }
  264. // look for the next PID line in the first table
  265. VOID WriteFilex(FILE *InFile, FILE *OutFile, struct PIDList *ThePIDList)
  266. {
  267. struct PIDList *TmpPIDList;
  268. struct RecList *TmpRecordList;
  269. char inBuff[RECSIZE] = {0};
  270. /* initialize temp list pointer */
  271. TmpPIDList = ThePIDList;
  272. /* heading */
  273. fprintf(OutFile,"%s\n",szHeader);
  274. OutputTags( OutFile );
  275. /* while not end of list, write records at offset to end of output file */
  276. while (TmpPIDList != 0) {
  277. TmpRecordList = TmpPIDList->RecordList;
  278. if( (!bIgnoreTransients) || (TmpPIDList->Count == g_MaxSnapShots) ) {
  279. while (TmpRecordList != 0) {
  280. LONG Offset;
  281. Offset= TmpRecordList->rOffset;
  282. if( Offset != INVALIDOFFSET ) {
  283. /* read in record */
  284. if (fseek(InFile, TmpRecordList->rOffset, SEEK_SET) == -1) break;
  285. if (fscanf(InFile, "%[^\n]", &inBuff) != 1) break;
  286. /* read out record */
  287. fprintf(OutFile, "%s\n", &inBuff);
  288. }
  289. /* get next record */
  290. TmpRecordList = TmpRecordList->Next;
  291. }
  292. /* add a line here */
  293. fputc('\n', OutFile);
  294. }
  295. /* get next record */
  296. TmpPIDList = TmpPIDList->Next;
  297. }
  298. }