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