1 /*-
2  ***********************************************************************
3  *
4  * $Id: digmode.c,v 1.56 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  * DigModeInitialize
18  *
19  ***********************************************************************
20  */
21 int
DigModeInitialize(FTIMES_PROPERTIES * psProperties,char * pcError)22 DigModeInitialize(FTIMES_PROPERTIES *psProperties, char *pcError)
23 {
24   const char          acRoutine[] = "DigModeInitialize()";
25   char                acLocalError[MESSAGE_SIZE] = "";
26   char                acMapItem[FTIMES_MAX_PATH];
27   char               *pcMapItem = NULL;
28   int                 iError = 0;
29 
30   /*-
31    *******************************************************************
32    *
33    * Initialize variables.
34    *
35    *********************************************************************
36    */
37   psProperties->pFileLog = stderr;
38   psProperties->pFileOut = stdout;
39   if (psProperties->iRunMode == FTIMES_DIGAUTO)
40   {
41     psProperties->bAnalyzeDeviceFiles = TRUE;
42     psProperties->bAnalyzeRemoteFiles = TRUE;
43   }
44   psProperties->psFieldMask = MaskParseMask("all", MASK_RUNMODE_TYPE_DIG, acLocalError); /* A mask is required by nph-ftimes.cgi. */
45   if (psProperties->psFieldMask == NULL)
46   {
47     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
48     return ER;
49   }
50   psProperties->bLogDigStrings = TRUE;
51 
52   /*-
53    *******************************************************************
54    *
55    * Read the config file.
56    *
57    *******************************************************************
58    */
59   iError = PropertiesReadFile(psProperties->acConfigFile, psProperties, acLocalError);
60   if (iError != ER_OK)
61   {
62     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
63     return iError;
64   }
65 
66   /*-
67    *********************************************************************
68    *
69    * Set the priority.
70    *
71    *********************************************************************
72    */
73   iError = SupportSetPriority(psProperties, acLocalError);
74   if (iError != ER_OK)
75   {
76     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
77     return iError;
78   }
79 
80   /*-
81    *******************************************************************
82    *
83    * Add any command line items to the Include list.
84    *
85    *******************************************************************
86    */
87   while ((pcMapItem = OptionsGetNextOperand(psProperties->psOptionsContext)) != NULL)
88   {
89     iError = SupportExpandPath(pcMapItem, acMapItem, FTIMES_MAX_PATH, 0, acLocalError);
90     if (iError != ER_OK)
91     {
92       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
93       return iError;
94     }
95 
96     iError = SupportAddToList(acMapItem, &psProperties->psIncludeList, "Include", acLocalError);
97     if (iError != ER_OK)
98     {
99       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
100       return iError;
101     }
102   }
103 
104   /*-
105    *********************************************************************
106    *
107    * LogDir defaults to OutDir.
108    *
109    *********************************************************************
110    */
111   if (psProperties->acLogDirName[0] == 0)
112   {
113     snprintf(psProperties->acLogDirName, FTIMES_MAX_PATH, "%s", psProperties->acOutDirName);
114   }
115 
116   return ER_OK;
117 }
118 
119 
120 /*-
121  ***********************************************************************
122  *
123  * DigModeCheckDependencies
124  *
125  ***********************************************************************
126  */
127 int
DigModeCheckDependencies(FTIMES_PROPERTIES * psProperties,char * pcError)128 DigModeCheckDependencies(FTIMES_PROPERTIES *psProperties, char *pcError)
129 {
130   const char          acRoutine[] = "DigModeCheckDependencies()";
131   int                 iLargestDigString = DigGetMaxStringLength();
132 #ifdef USE_SSL
133   char                acLocalError[MESSAGE_SIZE] = "";
134 #endif
135 
136   /*-
137    *********************************************************************
138    *
139    * There must be at least one dig string defined.
140    *
141    *********************************************************************
142    */
143   if (DigGetStringCount() <= 0)
144   {
145     snprintf(pcError, MESSAGE_SIZE, "%s: Need at least one DigString.", acRoutine);
146     return ER_MissingControl;
147   }
148 
149   /*-
150    *********************************************************************
151    *
152    * The carry size must be less than the block size.
153    *
154    *********************************************************************
155    */
156   if (psProperties->iAnalyzeCarrySize >= psProperties->iAnalyzeBlockSize)
157   {
158     snprintf(pcError, MESSAGE_SIZE, "%s: AnalyzeCarrySize (%d) must be less than AnalyzeBlockSize (%d).", acRoutine, psProperties->iAnalyzeCarrySize, psProperties->iAnalyzeBlockSize);
159     return ER;
160   }
161 
162   /*-
163    *********************************************************************
164    *
165    * The largest normal/nocase dig string must not be larger than the
166    * carry size.
167    *
168    *********************************************************************
169    */
170   if (iLargestDigString > psProperties->iAnalyzeCarrySize)
171   {
172     snprintf(pcError, MESSAGE_SIZE, "%s: The largest DigStringNormal/DigStringNoCase value (%d) must not exceed AnalyzeCarrySize (%d).", acRoutine, iLargestDigString, psProperties->iAnalyzeCarrySize);
173     return ER;
174   }
175 
176 #ifdef USE_XMAGIC
177   /*-
178    *********************************************************************
179    *
180    * If an XMagic dig string was specified, the minimum carry size is
181    * the size of an integer. This limitation is based on the way that
182    * XMagicGetValueOffset() works.
183    *
184    *********************************************************************
185    */
186   if (DigGetSearchList(DIG_STRING_TYPE_XMAGIC, 0) != NULL && psProperties->iAnalyzeCarrySize < sizeof(APP_UI32))
187   {
188     snprintf(pcError, MESSAGE_SIZE, "%s: AnalyzeCarrySize (%d) must be %d or larger when DigStringXMagic values are in use.", acRoutine, psProperties->iAnalyzeCarrySize, (int) sizeof(APP_UI32));
189     return ER;
190   }
191 #endif
192 
193   /*-
194    *********************************************************************
195    *
196    * Check mode-specific properties.
197    *
198    *********************************************************************
199    */
200   if (psProperties->iRunMode == FTIMES_DIGMODE)
201   {
202     if (psProperties->acBaseName[0] == 0)
203     {
204       snprintf(pcError, MESSAGE_SIZE, "%s: Missing BaseName.", acRoutine);
205       return ER_MissingControl;
206     }
207 
208     if (strcmp(psProperties->acBaseName, "-") == 0)
209     {
210       if (psProperties->bURLPutSnapshot)
211       {
212         snprintf(pcError, MESSAGE_SIZE, "%s: Uploads are not allowed when the BaseName is \"-\". Either disable URLPutSnapshot or change the BaseName.", acRoutine);
213         return ER;
214       }
215     }
216     else
217     {
218       if (psProperties->acOutDirName[0] == 0)
219       {
220         snprintf(pcError, MESSAGE_SIZE, "%s: Missing OutDir.", acRoutine);
221         return ER_MissingControl;
222       }
223     }
224 
225     if (psProperties->bURLPutSnapshot && psProperties->psPutURL == NULL)
226     {
227       snprintf(pcError, MESSAGE_SIZE, "%s: Missing URLPutURL.", acRoutine);
228       return ER_MissingControl;
229     }
230 
231     if (psProperties->bURLPutSnapshot && psProperties->psPutURL->pcPath[0] == 0)
232     {
233       snprintf(pcError, MESSAGE_SIZE, "%s: Missing path in URLPutURL.", acRoutine);
234       return ER_MissingControl;
235     }
236 
237 #ifdef USE_SSL
238     if (SSLCheckDependencies(psProperties->psSslProperties, acLocalError) != ER_OK)
239     {
240       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
241       return ER_MissingControl;
242     }
243 #endif
244   }
245 
246   return ER_OK;
247 }
248 
249 
250 /*-
251  ***********************************************************************
252  *
253  * DigModeFinalize
254  *
255  ***********************************************************************
256  */
257 int
DigModeFinalize(FTIMES_PROPERTIES * psProperties,char * pcError)258 DigModeFinalize(FTIMES_PROPERTIES *psProperties, char *pcError)
259 {
260   const char          acRoutine[] = "DigModeFinalize()";
261   char                acLocalError[MESSAGE_SIZE] = "";
262   int                 iError;
263 
264   /*-
265    *********************************************************************
266    *
267    * Enforce privilege requirements, if requested.
268    *
269    *********************************************************************
270    */
271   if (psProperties->bRequirePrivilege)
272   {
273     iError = SupportRequirePrivilege(acLocalError);
274     if (iError != ER_OK)
275     {
276       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
277       return iError;
278     }
279   }
280 
281   /*-
282    *********************************************************************
283    *
284    * Conditionally check the server uplink.
285    *
286    *********************************************************************
287    */
288   if (psProperties->bURLPutSnapshot && psProperties->iRunMode == FTIMES_DIGMODE)
289   {
290     iError = URLPingRequest(psProperties, acLocalError);
291     if (iError != ER_OK)
292     {
293       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
294       return ER_URLPingRequest;
295     }
296   }
297 
298   /*-
299    *********************************************************************
300    *
301    * Set up the Dig engine.
302    *
303    *********************************************************************
304    */
305   AnalyzeEnableDigEngine(psProperties);
306 
307 #ifdef USE_XMAGIC
308   /*-
309    *********************************************************************
310    *
311    * Forceably limit the step size if it's bigger than the block size.
312    *
313    *********************************************************************
314    */
315   if (psProperties->iAnalyzeStepSize > psProperties->iAnalyzeBlockSize)
316   {
317     snprintf(acLocalError, MESSAGE_SIZE, "AnalyzeStepSize (%d) is being reduced to match AnalyzeBlockSize (%d).", psProperties->iAnalyzeStepSize, psProperties->iAnalyzeBlockSize);
318     ErrorHandler(ER_Warning, acLocalError, ERROR_WARNING);
319     psProperties->iAnalyzeStepSize = psProperties->iAnalyzeBlockSize;
320     AnalyzeSetStepSize(psProperties->iAnalyzeStepSize);
321   }
322 #endif
323 
324   /*-
325    *********************************************************************
326    *
327    * If the Include list is NULL, include everything.
328    *
329    *********************************************************************
330    */
331   if (psProperties->psIncludeList == NULL)
332   {
333     psProperties->psIncludeList = SupportIncludeEverything(acLocalError);
334     if (psProperties->psIncludeList == NULL)
335     {
336       snprintf(pcError, MESSAGE_SIZE, "%s: Failed to build a default Include list: %s", acRoutine, acLocalError);
337       return ER_BadHandle;
338     }
339   }
340 
341   /*-
342    *********************************************************************
343    *
344    * Prune the Include list.
345    *
346    *********************************************************************
347    */
348   psProperties->psIncludeList = SupportPruneList(psProperties->psIncludeList, "Include");
349   if (psProperties->psIncludeList == NULL)
350   {
351     snprintf(pcError, MESSAGE_SIZE, "%s: There's nothing left to process in the Include list.", acRoutine);
352     return ER_NothingToDo;
353   }
354 
355   /*-
356    *********************************************************************
357    *
358    * Conditionally check the Include and Exclude lists.
359    *
360    *********************************************************************
361    */
362   if (psProperties->bExcludesMustExist)
363   {
364     iError = SupportCheckList(psProperties->psExcludeList, "Exclude", acLocalError);
365     if (iError != ER_OK)
366     {
367       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
368       return iError;
369     }
370   }
371 
372   if (psProperties->bIncludesMustExist)
373   {
374     iError = SupportCheckList(psProperties->psIncludeList, "Include", acLocalError);
375     if (iError != ER_OK)
376     {
377       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
378       return iError;
379     }
380   }
381 
382   /*-
383    *********************************************************************
384    *
385    * Establish Log file stream, and update Message Handler.
386    *
387    *********************************************************************
388    */
389   if (psProperties->iRunMode == FTIMES_DIGMODE && strcmp(psProperties->acBaseName, "-") != 0)
390   {
391     iError = SupportMakeName(psProperties->acLogDirName, psProperties->acBaseName, psProperties->acBaseNameSuffix, ".log", psProperties->acLogFileName, acLocalError);
392     if (iError != ER_OK)
393     {
394       snprintf(pcError, MESSAGE_SIZE, "%s: Log File: %s", acRoutine, acLocalError);
395       return iError;
396     }
397 
398     iError = SupportAddToList(psProperties->acLogFileName, &psProperties->psExcludeList, "Exclude", acLocalError);
399     if (iError != ER_OK)
400     {
401       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
402       return iError;
403     }
404 
405     psProperties->pFileLog = fopen(psProperties->acLogFileName, "wb+");
406     if (psProperties->pFileLog == NULL)
407     {
408       snprintf(pcError, MESSAGE_SIZE, "%s: LogFile = [%s]: %s", acRoutine, psProperties->acLogFileName, strerror(errno));
409       return ER_fopen;
410     }
411 /* FIXME Remove this #ifdef at some point in the future. */
412 #ifdef WIN32
413     /*-
414      *****************************************************************
415      *
416      * NOTE: The buffer size was explicitly set to prevent binaries
417      * made with Visual Studio 2005 (no service packs) from crashing
418      * when run in lean mode. This problem may have been fixed in
419      * Service Pack 1.
420      *
421      *****************************************************************
422      */
423     setvbuf(psProperties->pFileLog, NULL, _IOLBF, 1024);
424 #else
425     setvbuf(psProperties->pFileLog, NULL, _IOLBF, 0);
426 #endif
427   }
428   else
429   {
430     strncpy(psProperties->acLogFileName, "stderr", FTIMES_MAX_PATH);
431     psProperties->pFileLog = stderr;
432   }
433 
434   MessageSetNewLine(psProperties->acNewLine);
435   MessageSetOutputStream(psProperties->pFileLog);
436   MessageSetAutoFlush(MESSAGE_AUTO_FLUSH_ON);
437 
438   /*-
439    *******************************************************************
440    *
441    * Establish Out file stream.
442    *
443    *******************************************************************
444    */
445   if (psProperties->iRunMode == FTIMES_DIGMODE && strcmp(psProperties->acBaseName, "-") != 0)
446   {
447     iError = SupportMakeName(psProperties->acOutDirName, psProperties->acBaseName, psProperties->acBaseNameSuffix, ".dig", psProperties->acOutFileName, acLocalError);
448     if (iError != ER_OK)
449     {
450       snprintf(pcError, MESSAGE_SIZE, "%s: Out File: %s", acRoutine, acLocalError);
451       return iError;
452     }
453 
454     iError = SupportAddToList(psProperties->acOutFileName, &psProperties->psExcludeList, "Exclude", acLocalError);
455     if (iError != ER_OK)
456     {
457       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
458       return iError;
459     }
460 
461     psProperties->pFileOut = fopen(psProperties->acOutFileName, "wb+");
462     if (psProperties->pFileOut == NULL)
463     {
464       snprintf(pcError, MESSAGE_SIZE, "%s: OutFile = [%s]: %s", acRoutine, psProperties->acOutFileName, strerror(errno));
465       return ER_fopen;
466     }
467 /* FIXME Remove this #ifdef at some point in the future. */
468 #ifdef WIN32
469     /*-
470      *****************************************************************
471      *
472      * NOTE: The buffer size was explicitly set to prevent binaries
473      * made with Visual Studio 2005 (no service packs) from crashing
474      * when run in lean mode. This problem may have been fixed in
475      * Service Pack 1.
476      *
477      *****************************************************************
478      */
479     setvbuf(psProperties->pFileOut, NULL, _IOLBF, 1024);
480 #else
481     setvbuf(psProperties->pFileOut, NULL, _IOLBF, 0);
482 #endif
483   }
484   else
485   {
486     strncpy(psProperties->acOutFileName, "stdout", FTIMES_MAX_PATH);
487     psProperties->pFileOut = stdout;
488   }
489 
490   /*-
491    *********************************************************************
492    *
493    * Display properties.
494    *
495    *********************************************************************
496    */
497   PropertiesDisplaySettings(psProperties);
498 
499   /*-
500    *********************************************************************
501    *
502    * Write out a header.
503    *
504    *********************************************************************
505    */
506   iError = DigWriteHeader(psProperties, acLocalError);
507   if (iError != ER_OK)
508   {
509     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
510     return iError;
511   }
512 
513   return ER_OK;
514 }
515 
516 
517 /*-
518  ***********************************************************************
519  *
520  * DigModeWorkHorse
521  *
522  ***********************************************************************
523  */
524 int
DigModeWorkHorse(FTIMES_PROPERTIES * psProperties,char * pcError)525 DigModeWorkHorse(FTIMES_PROPERTIES *psProperties, char *pcError)
526 {
527   char                acLocalError[MESSAGE_SIZE] = "";
528   FILE_LIST           *psList = NULL;
529 
530   /*-
531    *********************************************************************
532    *
533    * Process the Include list.
534    *
535    *********************************************************************
536    */
537   for (psList = psProperties->psIncludeList; psList != NULL; psList = psList->psNext)
538   {
539     if (SupportMatchExclude(psProperties->psExcludeList, psList->pcRegularPath) == NULL)
540     {
541       MapFile(psProperties, psList->pcRegularPath, acLocalError);
542     }
543   }
544 
545   return ER_OK;
546 }
547 
548 
549 /*-
550  ***********************************************************************
551  *
552  * DigModeFinishUp
553  *
554  ***********************************************************************
555  */
556 int
DigModeFinishUp(FTIMES_PROPERTIES * psProperties,char * pcError)557 DigModeFinishUp(FTIMES_PROPERTIES *psProperties, char *pcError)
558 {
559   char                acMessage[MESSAGE_SIZE];
560   int                 i;
561   int                 iFirst;
562   int                 iIndex;
563   unsigned char       aucFileHash[MD5_HASH_SIZE];
564 
565   /*-
566    *********************************************************************
567    *
568    * Close up the output stream, and complete the file digest.
569    *
570    *********************************************************************
571    */
572   if (psProperties->pFileOut && psProperties->pFileOut != stdout)
573   {
574     fflush(psProperties->pFileOut);
575     fclose(psProperties->pFileOut);
576     psProperties->pFileOut = NULL;
577   }
578 
579   memset(aucFileHash, 0, MD5_HASH_SIZE);
580   MD5Omega(&psProperties->sOutFileHashContext, aucFileHash);
581   MD5HashToHex(aucFileHash, psProperties->acOutFileHash);
582 
583   /*-
584    *********************************************************************
585    *
586    * Print output filenames.
587    *
588    *********************************************************************
589    */
590   snprintf(acMessage, MESSAGE_SIZE, "LogFileName=%s", psProperties->acLogFileName);
591   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
592 
593   snprintf(acMessage, MESSAGE_SIZE, "OutFileName=%s", psProperties->acOutFileName);
594   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
595 
596   snprintf(acMessage, MESSAGE_SIZE, "OutFileHash=%s", psProperties->acOutFileHash);
597   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
598 
599   snprintf(acMessage, MESSAGE_SIZE, "DataType=%s", psProperties->acDataType);
600   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
601 
602   /*-
603    *********************************************************************
604    *
605    * Write out the statistics.
606    *
607    *********************************************************************
608    */
609   snprintf(acMessage, MESSAGE_SIZE, "DirectoriesEncountered=%d", MapGetDirectoryCount());
610   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
611 
612   snprintf(acMessage, MESSAGE_SIZE, "FilesEncountered=%d", MapGetFileCount());
613   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
614 
615 #ifdef UNIX
616   snprintf(acMessage, MESSAGE_SIZE, "SpecialsEncountered=%d", MapGetSpecialCount());
617   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
618 #endif
619 
620 #ifdef WINNT
621   snprintf(acMessage, MESSAGE_SIZE, "StreamsEncountered=%d", MapGetStreamCount());
622   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
623 #endif
624 
625   iIndex = 0;
626   if (psProperties->iLastAnalysisStage > 0)
627   {
628     iIndex = sprintf(&acMessage[iIndex], "AnalysisStages=");
629     for (i = 0, iFirst = 0; i < psProperties->iLastAnalysisStage; i++)
630     {
631       iIndex += sprintf(&acMessage[iIndex], "%s%s", (iFirst++ > 0) ? "," : "", psProperties->asAnalysisStages[i].acDescription);
632     }
633     MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
634 
635     snprintf(acMessage, MESSAGE_SIZE, "ObjectsAnalyzed=%u", AnalyzeGetFileCount());
636     MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
637 
638 #ifdef UNIX
639 #ifdef USE_AP_SNPRINTF
640     snprintf(acMessage, MESSAGE_SIZE, "BytesAnalyzed=%qu", (unsigned long long) AnalyzeGetByteCount());
641     MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
642 #else
643     snprintf(acMessage, MESSAGE_SIZE, "BytesAnalyzed=%llu", (unsigned long long) AnalyzeGetByteCount());
644     MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
645 #endif
646 #endif
647 
648 #ifdef WIN32
649     snprintf(acMessage, MESSAGE_SIZE, "BytesAnalyzed=%I64u", AnalyzeGetByteCount());
650     MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
651 #endif
652   }
653   else
654   {
655     snprintf(acMessage, MESSAGE_SIZE, "AnalysisStages=None");
656     MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
657   }
658 
659   /*-
660    *********************************************************************
661    *
662    * List total number of strings.
663    *
664    *********************************************************************
665    */
666   snprintf(acMessage, MESSAGE_SIZE, "DigStrings=%d", DigGetStringCount());
667   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
668 
669   /*-
670    *********************************************************************
671    *
672    * List total number of strings matched.
673    *
674    *********************************************************************
675    */
676   snprintf(acMessage, MESSAGE_SIZE, "DigStringsMatched=%d", DigGetStringsMatched());
677   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
678 
679   /*-
680    *********************************************************************
681    *
682    * List the number of dig records.
683    *
684    *********************************************************************
685    */
686 #ifdef UNIX
687 #ifdef USE_AP_SNPRINTF
688   snprintf(acMessage, MESSAGE_SIZE, "DigRecords=%qu", (unsigned long long) DigGetTotalMatches());
689 #else
690   snprintf(acMessage, MESSAGE_SIZE, "DigRecords=%llu", (unsigned long long) DigGetTotalMatches());
691 #endif
692 #endif
693 #ifdef WIN32
694   snprintf(acMessage, MESSAGE_SIZE, "DigRecords=%I64u", DigGetTotalMatches());
695 #endif
696   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
697 
698   SupportDisplayRunStatistics(psProperties);
699 
700   return ER_OK;
701 }
702 
703 
704 /*-
705  ***********************************************************************
706  *
707  * DigModeFinalStage
708  *
709  ***********************************************************************
710  */
711 int
DigModeFinalStage(FTIMES_PROPERTIES * psProperties,char * pcError)712 DigModeFinalStage(FTIMES_PROPERTIES *psProperties, char *pcError)
713 {
714   const char          acRoutine[] = "DigModeFinalStage()";
715   char                acLocalError[MESSAGE_SIZE] = "";
716   int                 iError;
717 
718   /*-
719    *********************************************************************
720    *
721    * Conditionally upload the collected data.
722    *
723    *********************************************************************
724    */
725   if (psProperties->bURLPutSnapshot && psProperties->iRunMode == FTIMES_DIGMODE)
726   {
727     iError = URLPutRequest(psProperties, acLocalError);
728     if (iError != ER_OK)
729     {
730       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
731       return ER_URLPutRequest;
732     }
733 
734     if (psProperties->bURLUnlinkOutput)
735     {
736       FTimesEraseFiles(psProperties, pcError);
737     }
738   }
739 
740   return ER_OK;
741 }
742