1 /*-
2  ***********************************************************************
3  *
4  * $Id: cmpmode.c,v 1.36 2014/07/18 06:40:44 mavrik Exp $
5  *
6  ***********************************************************************
7  *
8  * Copyright 2000-2014 The FTimes Project, All Rights Reserved.
9  *
10  ***********************************************************************
11  */
12 #include "all-includes.h"
13 
14 /*-
15  ***********************************************************************
16  *
17  * CmpModeInitialize
18  *
19  ***********************************************************************
20  */
21 int
CmpModeInitialize(FTIMES_PROPERTIES * psProperties,char * pcError)22 CmpModeInitialize(FTIMES_PROPERTIES *psProperties, char *pcError)
23 {
24   const char          acRoutine[] = "CmpModeInitialize()";
25   char                acLocalError[MESSAGE_SIZE] = "";
26   CMP_PROPERTIES     *psCmpProperties = NULL;
27   int                 iError = 0;
28 
29   /*-
30    *********************************************************************
31    *
32    * Initialize Compare properties.
33    *
34    *********************************************************************
35    */
36   psCmpProperties = CompareNewProperties(acLocalError);
37   if (psCmpProperties == NULL)
38   {
39     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
40     free(psProperties);
41     return ER;
42   }
43   CompareSetPropertiesReference(psCmpProperties);
44 
45   /*-
46    *********************************************************************
47    *
48    * Initialize variables.
49    *
50    *********************************************************************
51    */
52   psProperties->pFileLog = stderr;
53   psProperties->pFileOut = stdout;
54   psCmpProperties->psCompareMask = psProperties->psFieldMask;
55 
56   DecodeBuildFromBase64Table();
57 
58   /*-
59    *********************************************************************
60    *
61    * Set the priority.
62    *
63    *********************************************************************
64    */
65   iError = SupportSetPriority(psProperties, acLocalError);
66   if (iError != ER_OK)
67   {
68     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
69     return iError;
70   }
71 
72   return ER_OK;
73 }
74 
75 
76 /*-
77  ***********************************************************************
78  *
79  * CmpModeCheckDependencies
80  *
81  ***********************************************************************
82  */
83 int
CmpModeCheckDependencies(FTIMES_PROPERTIES * psProperties,char * pcError)84 CmpModeCheckDependencies(FTIMES_PROPERTIES *psProperties, char *pcError)
85 {
86   const char          acRoutine[] = "CmpModeCheckDependencies()";
87 
88   if (psProperties->psFieldMask == NULL)
89   {
90     snprintf(pcError, MESSAGE_SIZE, "%s: Missing FieldMask.", acRoutine);
91     return ER_MissingControl;
92   }
93 
94   if (psProperties->psBaselineContext->pcFile == NULL || psProperties->psBaselineContext->pcFile[0] == 0)
95   {
96     snprintf(pcError, MESSAGE_SIZE, "%s: Missing baseline file.", acRoutine);
97     return ER_MissingControl;
98   }
99 
100   if (psProperties->psSnapshotContext->pcFile == NULL || psProperties->psSnapshotContext->pcFile[0] == 0)
101   {
102     snprintf(pcError, MESSAGE_SIZE, "%s: Missing snapshot file.", acRoutine);
103     return ER_MissingControl;
104   }
105 
106   return ER_OK;
107 }
108 
109 
110 /*-
111  ***********************************************************************
112  *
113  * CmpModeFinalize
114  *
115  ***********************************************************************
116  */
117 int
CmpModeFinalize(FTIMES_PROPERTIES * psProperties,char * pcError)118 CmpModeFinalize(FTIMES_PROPERTIES *psProperties, char *pcError)
119 {
120   const char          acRoutine[] = "CmpModeFinalize()";
121   char                acLocalError[MESSAGE_SIZE] = "";
122   char                acMessage[MESSAGE_SIZE] = { 0 };
123   char               *pcMask = NULL;
124   CMP_PROPERTIES     *psCmpProperties = CompareGetPropertiesReference();
125   int                 iError = 0;
126   int                 iLength = 0;
127   struct stat         statEntry = { 0 };
128 
129   /*-
130    *********************************************************************
131    *
132    * Determine whether or not a backing file will be required. This is
133    * done for two reasons: 1) there's no need to create a backing file
134    * for small baselines and 2) if the backing file size ends up being
135    * zero, attempts to map it can lead to EINVAL errors on some
136    * platforms.
137    *
138    *********************************************************************
139    */
140   if
141   (
142        psProperties->iMemoryMapEnable
143     && (stat(psProperties->psBaselineContext->pcFile, &statEntry) == ER_OK)
144     && ((statEntry.st_mode & S_IFMT) == S_IFREG)
145     && (statEntry.st_size > FTIMES_MIN_MMAP_SIZE)
146   )
147   {
148     psCmpProperties->iMemoryMapFile = 1;
149   }
150 
151   /*-
152    *********************************************************************
153    *
154    * Conditionally initialize the name for a backing file.
155    *
156    *********************************************************************
157    */
158   if (psCmpProperties->iMemoryMapFile)
159   {
160     iLength = strlen(psProperties->acTempDirectory) +
161       strlen(FTIMES_SLASH) +
162       strlen(PROGRAM_NAME) +
163       strlen("_") +
164       strlen("4294967295") +
165       strlen("_") +
166       strlen(psProperties->pcNonce) +
167       strlen(".mmap") +
168       1;
169     psCmpProperties->pcMemoryMapFile = calloc(iLength, 1);
170     if (psCmpProperties->pcMemoryMapFile == NULL)
171     {
172       snprintf(pcError, MESSAGE_SIZE, "%s: calloc(): %s", acRoutine, strerror(errno));
173       return ER;
174     }
175     snprintf(psCmpProperties->pcMemoryMapFile, iLength, "%s%s%s_%ld_%s.mmap",
176       psProperties->acTempDirectory,
177       FTIMES_SLASH,
178       PROGRAM_NAME,
179       (long) psProperties->tvJobEpoch.tv_sec,
180       psProperties->pcNonce
181       );
182   }
183 
184   /*-
185    *********************************************************************
186    *
187    * Establish Log file stream, and update Message Handler.
188    *
189    *********************************************************************
190    */
191   strncpy(psProperties->acLogFileName, "stderr", FTIMES_MAX_PATH);
192   psProperties->pFileLog = stderr;
193 
194   MessageSetNewLine(psProperties->acNewLine);
195   MessageSetOutputStream(psProperties->pFileLog);
196   MessageSetAutoFlush(MESSAGE_AUTO_FLUSH_ON);
197 
198   /*-
199    *******************************************************************
200    *
201    * Establish Out file stream.
202    *
203    *******************************************************************
204    */
205   strncpy(psProperties->acOutFileName, "stdout", FTIMES_MAX_PATH);
206   psProperties->pFileOut = stdout;
207 
208   CompareSetOutputStream(psProperties->pFileOut);
209 
210   /*-
211    *******************************************************************
212    *
213    * Open the baseline, and parse its header.
214    *
215    *******************************************************************
216    */
217   iError = DecodeOpenSnapshot(psProperties->psBaselineContext, acLocalError);
218   if (iError != ER_OK)
219   {
220     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
221     return ER;
222   }
223 
224   /*-
225    *******************************************************************
226    *
227    * Open the snapshot, and parse its header.
228    *
229    *******************************************************************
230    */
231   iError = DecodeOpenSnapshot(psProperties->psSnapshotContext, acLocalError);
232   if (iError != ER_OK)
233   {
234     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
235     return ER;
236   }
237 
238   /*-
239    *******************************************************************
240    *
241    * Finalize the compare mask. Abort if there's nothing to compare.
242    *
243    *******************************************************************
244    */
245   if (psCmpProperties->psCompareMask->ulMask)
246   {
247     psCmpProperties->psCompareMask->ulMask &= psProperties->psBaselineContext->ulFieldMask; /* Remove fields not present in the baseline. */
248     psCmpProperties->psCompareMask->ulMask &= psProperties->psSnapshotContext->ulFieldMask; /* Remove fields not present in the snapshot. */
249     if (psCmpProperties->psCompareMask->ulMask == 0)
250     {
251       snprintf(pcError, MESSAGE_SIZE, "%s: The baseline and snapshot have no fields in common. Only (M)issing and (N)ew changes will be detected.", acRoutine);
252       ErrorHandler(ER_Warning, pcError, ERROR_WARNING);
253     }
254   }
255   else
256   {
257     snprintf(pcError, MESSAGE_SIZE, "%s: No fields were specified in the compare mask. Only (M)issing and (N)ew changes will be detected.", acRoutine);
258     ErrorHandler(ER_Warning, pcError, ERROR_WARNING);
259   }
260 
261   /*-
262    *******************************************************************
263    *
264    * Display properties.
265    *
266    *******************************************************************
267    */
268   snprintf(acMessage, MESSAGE_SIZE, "Baseline=%s", psProperties->psBaselineContext->pcFile);
269   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
270 
271   snprintf(acMessage, MESSAGE_SIZE, "Snapshot=%s", psProperties->psSnapshotContext->pcFile);
272   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
273 
274   snprintf(acMessage, MESSAGE_SIZE, "BaselineCompressed=%s", (psProperties->psBaselineContext->iCompressed) ? "Y" : "N");
275   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
276 
277   snprintf(acMessage, MESSAGE_SIZE, "SnapshotCompressed=%s", (psProperties->psSnapshotContext->iCompressed) ? "Y" : "N");
278   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
279 
280   PropertiesDisplaySettings(psProperties);
281 
282   pcMask = MaskBuildMask(psProperties->psBaselineContext->ulFieldMask, MASK_RUNMODE_TYPE_CMP, acLocalError);
283   if (pcMask == NULL)
284   {
285     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
286     return ER;
287   }
288   snprintf(acMessage, MESSAGE_SIZE, "BaselineFieldMask=%s", pcMask);
289   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
290   free(pcMask);
291 
292   pcMask = MaskBuildMask(psProperties->psSnapshotContext->ulFieldMask, MASK_RUNMODE_TYPE_CMP, acLocalError);
293   if (pcMask == NULL)
294   {
295     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
296     return ER;
297   }
298   snprintf(acMessage, MESSAGE_SIZE, "SnapshotFieldMask=%s", pcMask);
299   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
300   free(pcMask);
301 
302   pcMask = MaskBuildMask(psCmpProperties->psCompareMask->ulMask, MASK_RUNMODE_TYPE_CMP, acLocalError);
303   if (pcMask == NULL)
304   {
305     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
306     return ER;
307   }
308   snprintf(acMessage, MESSAGE_SIZE, "CompareMask=%s", pcMask);
309   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
310   free(pcMask);
311 
312   /*-
313    *******************************************************************
314    *
315    * Write out a header.
316    *
317    *******************************************************************
318    */
319   CompareSetNewLine(psProperties->acNewLine);
320   iError = CompareWriteHeader(psProperties->pFileOut, psProperties->acNewLine, acLocalError);
321   if (iError != ER_OK)
322   {
323     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
324     return iError;
325   }
326 
327   return ER_OK;
328 }
329 
330 
331 /*-
332  ***********************************************************************
333  *
334  * CmpModeWorkHorse
335  *
336  ***********************************************************************
337  */
338 int
CmpModeWorkHorse(FTIMES_PROPERTIES * psProperties,char * pcError)339 CmpModeWorkHorse(FTIMES_PROPERTIES *psProperties, char *pcError)
340 {
341   const char          acRoutine[] = "CmpModeWorkHorse()";
342   char                acLocalError[MESSAGE_SIZE] = "";
343   int                 iError = 0;
344 
345   iError = CompareLoadBaselineData(psProperties->psBaselineContext, acLocalError);
346   if (iError != ER_OK)
347   {
348     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
349     fclose(psProperties->psBaselineContext->pFile);
350     return iError;
351   }
352   fclose(psProperties->psBaselineContext->pFile);
353 
354   iError = CompareEnumerateChanges(psProperties->psBaselineContext, psProperties->psSnapshotContext, acLocalError);
355   if (iError != ER_OK)
356   {
357     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
358     fclose(psProperties->psSnapshotContext->pFile);
359     return iError;
360   }
361   fclose(psProperties->psSnapshotContext->pFile);
362 
363   return ER_OK;
364 }
365 
366 
367 /*-
368  ***********************************************************************
369  *
370  * CmpModeFinishUp
371  *
372  ***********************************************************************
373  */
374 int
CmpModeFinishUp(FTIMES_PROPERTIES * psProperties,char * pcError)375 CmpModeFinishUp(FTIMES_PROPERTIES *psProperties, char *pcError)
376 {
377   char                acMessage[MESSAGE_SIZE] = { 0 };
378 
379   /*-
380    *********************************************************************
381    *
382    * Print output filenames.
383    *
384    *********************************************************************
385    */
386   snprintf(acMessage, MESSAGE_SIZE, "LogFileName=%s", psProperties->acLogFileName);
387   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
388 
389   snprintf(acMessage, MESSAGE_SIZE, "OutFileName=%s", psProperties->acOutFileName);
390   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
391 
392   snprintf(acMessage, MESSAGE_SIZE, "DataType=%s", psProperties->acDataType);
393   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
394 
395   /*-
396    *********************************************************************
397    *
398    * Write out the statistics.
399    *
400    *********************************************************************
401    */
402   snprintf(acMessage, MESSAGE_SIZE, "RecordsAnalyzed=%d", CompareGetRecordCount());
403   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
404 
405   snprintf(acMessage, MESSAGE_SIZE, "ChangedCount=%d", CompareGetChangedCount());
406   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
407 
408   snprintf(acMessage, MESSAGE_SIZE, "MissingCount=%d", CompareGetMissingCount());
409   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
410 
411   snprintf(acMessage, MESSAGE_SIZE, "NewCount=%d", CompareGetNewCount());
412   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
413 
414   snprintf(acMessage, MESSAGE_SIZE, "UnknownCount=%d", CompareGetUnknownCount());
415   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
416 
417   snprintf(acMessage, MESSAGE_SIZE, "CrossedCount=%d", CompareGetCrossedCount());
418   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
419 
420   SupportDisplayRunStatistics(psProperties);
421 
422   return ER_OK;
423 }
424 
425 
426 /*-
427  ***********************************************************************
428  *
429  * CmpModeFinalStage
430  *
431  ***********************************************************************
432  */
433 int
CmpModeFinalStage(FTIMES_PROPERTIES * psProperties,char * pcError)434 CmpModeFinalStage(FTIMES_PROPERTIES *psProperties, char *pcError)
435 {
436   CMP_PROPERTIES     *psCmpProperties = CompareGetPropertiesReference();
437 
438   /*-
439    *********************************************************************
440    *
441    * Conditionally unmap memory and delete the associated file. Since
442    * the program is shutting down and the memory map file is no longer
443    * needed, there's not much point in checking the return values for
444    * these calls.
445    *
446    *********************************************************************
447    */
448   if (psCmpProperties->iMemoryMapFile)
449   {
450 #ifdef WINNT
451     UnmapViewOfFile(psCmpProperties->pvMemoryMap);
452 #else
453     munmap(psCmpProperties->pvMemoryMap, psCmpProperties->iMemoryMapSize);
454 #endif
455     unlink(psCmpProperties->pcMemoryMapFile);
456   }
457 
458   CompareFreeProperties(psCmpProperties);
459 
460   return ER_OK;
461 }
462