Leaked source code of windows server 2003
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.

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