1 /*-
2  ***********************************************************************
3  *
4  * $Id: ftimes.c,v 1.62 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 #ifdef USE_EMBEDDED_PERL
15 /*-
16  ***********************************************************************
17  *
18  * Glue code for embedded Perl (taken from perlembed.pod).
19  *
20  ***********************************************************************
21  */
22 EXTERN_C void xs_init (pTHX);
23 EXTERN_C void boot_DynaLoader (pTHX_ CV *cv);
24 
25 EXTERN_C void
xs_init(pTHX)26 xs_init(pTHX)
27 {
28   char               *pcFile = __FILE__;
29 
30   newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, pcFile);
31 }
32 #endif
33 
34 /*-
35  ***********************************************************************
36  *
37  * Global variables
38  *
39  ***********************************************************************
40  */
41 static FTIMES_PROPERTIES *gpsProperties;
42 
43 #ifdef WINNT
44 HINSTANCE             NtdllHandle;
45 NQIF                  NtdllNQIF;
46 #endif
47 
48 /*-
49  ***********************************************************************
50  *
51  * Main
52  *
53  ***********************************************************************
54  */
55 int
main(int iArgumentCount,char * ppcArgumentVector[])56 main(int iArgumentCount, char *ppcArgumentVector[])
57 {
58   const char          acRoutine[] = "Main()";
59   char                aacLocalError[2][MESSAGE_SIZE];
60   FTIMES_PROPERTIES  *psProperties;
61   int                 iError;
62 
63   aacLocalError[0][0] = aacLocalError[1][0] = 0;
64 
65   iError = FTimesBootstrap(aacLocalError[1]);
66   if (iError != ER_OK)
67   {
68     snprintf(aacLocalError[0], MESSAGE_SIZE, "%s: %s", acRoutine, aacLocalError[1]);
69     ErrorHandler(XER_BootStrap, aacLocalError[0], ERROR_CRITICAL);
70   }
71   psProperties = FTimesGetPropertiesReference();
72 
73   iError = FTimesProcessArguments(psProperties, iArgumentCount, ppcArgumentVector, aacLocalError[1]);
74   if (iError != ER_OK)
75   {
76     snprintf(aacLocalError[0], MESSAGE_SIZE, "%s: %s", acRoutine, aacLocalError[1]);
77     ErrorHandler(XER_ProcessArguments, aacLocalError[0], ERROR_CRITICAL);
78   }
79 
80   iError = FTimesFinalize(psProperties, aacLocalError[1]);
81   if (iError != ER_OK)
82   {
83     snprintf(aacLocalError[0], MESSAGE_SIZE, "%s: %s", acRoutine, aacLocalError[1]);
84     ErrorHandler(XER_Finalize, aacLocalError[0], ERROR_CRITICAL);
85   }
86 
87   if (psProperties->iLastRunModeStage > 0)
88   {
89     iError = FTimesStagesLoop(psProperties, aacLocalError[1]);
90     if (iError != ER_OK)
91     {
92       snprintf(aacLocalError[0], MESSAGE_SIZE, "%s: %s", acRoutine, aacLocalError[1]);
93       ErrorHandler(iError, aacLocalError[0], ERROR_CRITICAL);
94     }
95   }
96 
97   iError = FTimesFinalStage(psProperties, aacLocalError[1]);
98   if (iError != ER_OK)
99   {
100     snprintf(aacLocalError[0], MESSAGE_SIZE, "%s: %s", acRoutine, aacLocalError[1]);
101     ErrorHandler(XER_FinalStage, aacLocalError[0], ERROR_CRITICAL);
102   }
103 
104   return XER_OK;
105 }
106 
107 
108 /*-
109  ***********************************************************************
110  *
111  * FTimesBootstrap
112  *
113  ***********************************************************************
114  */
115 int
FTimesBootstrap(char * pcError)116 FTimesBootstrap(char *pcError)
117 {
118   const char          acRoutine[] = "FTimesBootstrap()";
119   char                acLocalError[MESSAGE_SIZE] = "";
120   FTIMES_PROPERTIES  *psProperties;
121 #ifdef WINNT
122   char               *pcMessage;
123   int                 iError;
124 #endif
125 
126   /*-
127    *********************************************************************
128    *
129    * Require certain truths. If these tests produce an error, there is
130    * something wrong with the code.
131    *
132    *********************************************************************
133    */
134   if (DECODE_FIELD_COUNT != MaskGetTableLength(MASK_RUNMODE_TYPE_CMP))
135   {
136     snprintf(pcError, MESSAGE_SIZE, "%s: DecodeFieldCount/CmpMaskTableSize mismatch!: %d != %d", acRoutine, DECODE_FIELD_COUNT, MaskGetTableLength(MASK_RUNMODE_TYPE_CMP));
137     return ER;
138   }
139 
140   if (DECODE_FIELD_COUNT != DecodeGetTableLength())
141   {
142     snprintf(pcError, MESSAGE_SIZE, "%s: DecodeFieldCount/DecodeTableSize mismatch!: %d != %d", acRoutine, DECODE_FIELD_COUNT, DecodeGetTableLength());
143     return ER;
144   }
145 
146   if (FTIMES_MAX_LINE != DECODE_MAX_LINE)
147   {
148     snprintf(pcError, MESSAGE_SIZE, "%s: FTimesMaxLine/DecodeMaxLine mismatch!: %d != %d", acRoutine, FTIMES_MAX_LINE, DECODE_MAX_LINE);
149     return ER;
150   }
151 
152   if (FTIMES_MAX_LINE != CMP_MAX_LINE)
153   {
154     snprintf(pcError, MESSAGE_SIZE, "%s: FTimesMaxLine/CmpMaxLine mismatch!: %d != %d", acRoutine, FTIMES_MAX_LINE, CMP_MAX_LINE);
155     return ER;
156   }
157 
158   /*-
159    *********************************************************************
160    *
161    * Setup the Message Handler's output stream.
162    *
163    *********************************************************************
164    */
165   MessageSetOutputStream(stderr);
166 
167 #ifdef WINNT
168   /*-
169    *********************************************************************
170    *
171    * Suppress critical-error-handler message boxes.
172    *
173    *********************************************************************
174    */
175   SetErrorMode(SEM_FAILCRITICALERRORS);
176 
177   /*-
178    *********************************************************************
179    *
180    * Put stdout/stderr in binary mode to prevent CRLF mappings.
181    *
182    *********************************************************************
183    */
184   iError = _setmode(_fileno(stdout), _O_BINARY);
185   if (iError == -1)
186   {
187     snprintf(pcError, MESSAGE_SIZE, "%s: _setmode(): stdout: %s", acRoutine, strerror(errno));
188     return ER;
189   }
190 
191   iError = _setmode(_fileno(stderr), _O_BINARY);
192   if (iError == -1)
193   {
194     snprintf(pcError, MESSAGE_SIZE, "%s: _setmode(): stderr: %s", acRoutine, strerror(errno));
195     return ER;
196   }
197 
198   /*-
199    *********************************************************************
200    *
201    * Load NT's native library, if necessary.
202    *
203    *********************************************************************
204    */
205   if (NtdllHandle == NULL)
206   {
207     NtdllHandle = LoadLibrary("NTdll.dll");
208     if (NtdllHandle == NULL)
209     {
210       ErrorFormatWinxError(GetLastError(), &pcMessage);
211       snprintf(pcError, MESSAGE_SIZE, "%s: LoadLibrary(): Library = [NTdll.dll]: %s", acRoutine, pcMessage);
212       return ER;
213     }
214   }
215 
216   if (NtdllNQIF == NULL)
217   {
218     NtdllNQIF = (NQIF) GetProcAddress(NtdllHandle, "NtQueryInformationFile");
219     if (NtdllNQIF == NULL)
220     {
221       FreeLibrary(NtdllHandle);
222       ErrorFormatWinxError(GetLastError(), &pcMessage);
223       snprintf(pcError, MESSAGE_SIZE, "%s: GetProcAddress(): Routine = [NtQueryInformationFile]: %s", acRoutine, pcMessage);
224       return ER;
225     }
226   }
227 #endif
228 #ifdef USE_SSL
229   SslBoot();
230 #endif
231 
232   psProperties = FTimesNewProperties(acLocalError);
233   if (psProperties == NULL)
234   {
235     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
236     return ER;
237   }
238   FTimesSetPropertiesReference(psProperties);
239 
240   return ER_OK;
241 }
242 
243 
244 /*-
245  ***********************************************************************
246  *
247  * FTimesFinalize
248  *
249  ***********************************************************************
250  */
251 int
FTimesFinalize(FTIMES_PROPERTIES * psProperties,char * pcError)252 FTimesFinalize(FTIMES_PROPERTIES *psProperties, char *pcError)
253 {
254   const char          acRoutine[] = "FTimesFinalize()";
255   char                acLocalError[MESSAGE_SIZE] = "";
256   int                 iError = 0;
257 #ifdef USE_EMBEDDED_PERL
258   char               *pacArgumentVector[] = { "", "-e", "0" };
259   char              **ppcArgumentVector = pacArgumentVector;
260   int                 iArgumentCount = 3;
261   int                 iPerlStatus = 0;
262   char                acScriptHandler[] =
263 "\n\
264 use strict; use warnings;\n\
265 \n\
266 ######################################################################\n\
267 #\n\
268 # Redefine CORE::GLOBAL::exit() so that any calls to exit() made from\n\
269 # within Perl scripts or modules won't cause the interpreter to exit,\n\
270 # which would, in turn, cause ftimes to exit as well.\n\
271 #\n\
272 ######################################################################\n\
273 \n\
274 package main;\n\
275 \n\
276 use subs qw(CORE::GLOBAL::exit);\n\
277 \n\
278 sub CORE::GLOBAL::exit { die(qq(ExitCode='$_[0]'\\n)); }\n\
279 \n\
280 ######################################################################\n\
281 #\n\
282 # Embed::Persistent\n\
283 #\n\
284 ######################################################################\n\
285 \n\
286 package Embed::Persistent;\n\
287 \n\
288 use Symbol qw(delete_package);\n\
289 \n\
290 our %hMTimeDeltas;\n\
291 \n\
292 ######################################################################\n\
293 #\n\
294 # EvalScript\n\
295 #\n\
296 ######################################################################\n\
297 \n\
298 sub EvalScript\n\
299 {\n\
300   my ($sScript, @aArgumentVector) = @_;\n\
301 \n\
302   my $sPackageName = LoadScript($sScript);\n\
303   if (!defined($sPackageName))\n\
304   {\n\
305     return undef; # NOTE: $@ is set by LoadScript().\n\
306   }\n\
307 \n\
308   eval { $sPackageName->Worker(@ARGV=@aArgumentVector); };\n\
309   if ($@) # NOTE: $@ becomes ERRSV over in C land.\n\
310   {\n\
311     $@ =~ s/[\\t\\r\\n]+/ /g; $@ =~ s/\\s+/ /g; $@ =~ s/^\\s+//; $@ =~ s/\\s+$//;\n\
312     if ($@ =~ /^ExitCode='(\\d+)'/)\n\
313     {\n\
314       $@ = undef; # The script used the approved exit mechanism (i.e., it called exit() with an integer value), so clear the eval error.\n\
315       return int($1); # Cast the return value as an integer so that it's handled correctly over in C land.\n\
316     }\n\
317     return undef; # This script didn't use the approved exit mechanism or failed for some other reason.\n\
318   }\n\
319 \n\
320   return 0; # The script ran without error, but didn't use the approved exit mechanism.\n\
321 }\n\
322 \n\
323 \n\
324 ######################################################################\n\
325 #\n\
326 # GetPackageName\n\
327 #\n\
328 ######################################################################\n\
329 \n\
330 sub GetPackageName\n\
331 {\n\
332   my $sString = (defined($_[0]) && length($_[0]) > 0) ? $_[0] : qq(anonymous);\n\
333 \n\
334   my @aPackageElements = qw(Embed Persistent);\n\
335   foreach my $sElement (split('/', $sString))\n\
336   {\n\
337     next unless (defined($sElement) && length($sElement) > 0);\n\
338     $sElement =~ s/([^0-9A-Za-z])/sprintf(qq(_%02x_), unpack('C', $1))/seg;\n\
339     $sElement =~ s/^([0-9])/sprintf(qq(_%02x_), unpack('C', $1))/seg;\n\
340     push(@aPackageElements, $sElement);\n\
341   }\n\
342 \n\
343   return join(qq(::), @aPackageElements);\n\
344 }\n\
345 \n\
346 \n\
347 ######################################################################\n\
348 #\n\
349 # LoadScript\n\
350 # \n\
351 ######################################################################\n\
352 \n\
353 sub LoadScript\n\
354 {\n\
355   my ($sScript) = @_;\n\
356   if (!defined($sScript))\n\
357   {\n\
358     $@ = qq(script not defined);\n\
359     return undef;\n\
360   }\n\
361   my @aPackageElements = qw(Embed Persistent);\n\
362   foreach my $sElement (split(/\\//, $sScript))\n\
363   {\n\
364     next unless (defined($sElement) && length($sElement) > 0);\n\
365     $sElement =~ s/([^0-9A-Za-z])/sprintf(qq(_%02x_), unpack('C', $1))/seg;\n\
366     $sElement =~ s/^(\\d)/sprintf(qq(_%02x_), unpack('C', $1))/seg;\n\
367     push(@aPackageElements, $sElement);\n\
368   }\n\
369   my $sPackageName = join(qq(::), @aPackageElements);\n\
370 \n\
371   if (!-f $sScript || !-r _)\n\
372   {\n\
373     $@ = qq(script does not exist, is not regular, or is unreadable);\n\
374     return undef;\n\
375   }\n\
376   my $sMTimeDelta = -M $sScript;\n\
377 \n\
378   if (!defined($hMTimeDeltas{$sPackageName}{'MTimeDelta'}) || $hMTimeDeltas{$sPackageName}{'MTimeDelta'} > $sMTimeDelta)\n\
379   {\n\
380     delete_package($sPackageName) if (defined($hMTimeDeltas{$sPackageName}{'MTimeDelta'}));\n\
381     local *FH;\n\
382     if (!open(FH, $sScript))\n\
383     {\n\
384       $@ = qq(script could not be opened ($!));\n\
385       return undef;\n\
386     }\n\
387     my $sScriptSource;\n\
388     while (my $sLine = <FH>)\n\
389     {\n\
390       last if ($sLine =~ /__(?:DATA|END)__/o);\n\
391       $sScriptSource .= $sLine;\n\
392     }\n\
393     close(FH);\n\
394     eval qq # Convert the script into a worker subroutine within its own unique package.\n\
395     {\n\
396       package $sPackageName;\n\
397       sub Worker\n\
398       {\n\
399         $sScriptSource;\n\
400       }\n\
401     };\n\
402     if ($@)\n\
403     {\n\
404       $@ =~ s/[\\t\\r\\n]+/ /g; $@ =~ s/\\s+/ /g; $@ =~ s/^\\s+//; $@ =~ s/\\s+$//;\n\
405       return undef;\n\
406     }\n\
407     $hMTimeDeltas{$sPackageName}{'MTimeDelta'} = $sMTimeDelta;\n\
408   }\n\
409 \n\
410   return $sPackageName;\n\
411 }\n\
412 \n\
413 1;\n\
414 ";
415 #endif
416 
417   /*-
418    *********************************************************************
419    *
420    * Seed the random number generator, and generate a nonce.
421    *
422    *********************************************************************
423    */
424   TimeGetTimeValue(&psProperties->tvSRGEpoch);
425   iError = SeedRandom((unsigned long) psProperties->tvJobEpoch.tv_usec, (unsigned long) psProperties->tvSRGEpoch.tv_usec, acLocalError);
426   if (iError != ER_OK)
427   {
428     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
429     return ER;
430   }
431 
432   psProperties->pcNonce = MakeNonce(acLocalError);
433   if (psProperties->pcNonce == NULL)
434   {
435     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
436     return ER;
437   }
438 
439 #ifdef USE_EMBEDDED_PERL
440 if (RUN_MODE_IS_SET(FTIMES_DIGMADMAP, psProperties->iRunMode))
441 {
442   /*-
443    *********************************************************************
444    *
445    * Initialize the Perl interpreter.
446    *
447    *********************************************************************
448    */
449   PERL_SYS_INIT(&iArgumentCount, &ppcArgumentVector);
450   psProperties->psMyPerl = perl_alloc();
451   if (psProperties->psMyPerl == NULL)
452   {
453     snprintf(pcError, MESSAGE_SIZE, "%s: perl_alloc(): Unable to allocate a Perl interpreter.\n", acRoutine);
454     return ER;
455   }
456   PL_perl_destruct_level = 1; /* Setting this to 1 makes everything squeaky clean according to perlembed. */
457   perl_construct(psProperties->psMyPerl);
458   iPerlStatus = perl_parse(psProperties->psMyPerl, xs_init, iArgumentCount, ppcArgumentVector, NULL);
459   if (iPerlStatus != 0)
460   {
461     snprintf(pcError, MESSAGE_SIZE, "%s: perl_parse(): Failed to initialize the Perl interpreter.", acRoutine);
462     return ER;
463   }
464 
465   /*-
466    *********************************************************************
467    *
468    * Initialize the script handler.
469    *
470    *********************************************************************
471    */
472   eval_sv(newSVpv(acScriptHandler, 0), G_KEEPERR);
473   if (SvTRUE(ERRSV))
474   {
475     snprintf(pcError, MESSAGE_SIZE, "%s: eval_sv(): Failed to initialize the Perl script handler (%s).", acRoutine, SvPV_nolen(ERRSV));
476     return ER;
477   }
478 }
479 #endif
480 
481 #ifdef USE_EMBEDDED_PYTHON
482 if (RUN_MODE_IS_SET(FTIMES_DIGMADMAP, psProperties->iRunMode))
483 {
484   /*-
485    *********************************************************************
486    *
487    * Initialize the Python interpreter. Note that a failure inside this
488    * function pollutes stderr and ultimately leads to abort() by way of
489    * Py_FatalError(). It would be better if we could catch these errors
490    * and then decide how to handle them on our own.
491    *
492    *********************************************************************
493    */
494   Py_InitializeEx(0);
495 
496   /*-
497    *********************************************************************
498    *
499    * Obtain references to the main module and its associated dictionary.
500    *
501    *********************************************************************
502    */
503   psProperties->psPythonMain = PyImport_AddModule("__main__");
504   if (psProperties->psPythonMain == NULL)
505   {
506     snprintf(pcError, MESSAGE_SIZE, "%s: PyImport_AddModule(): Failed to obtain a reference to the main module.", acRoutine);
507     return ER;
508   }
509   psProperties->psPyGlobals = PyModule_GetDict(psProperties->psPythonMain);
510   if (psProperties->psPyGlobals == NULL)
511   {
512     snprintf(pcError, MESSAGE_SIZE, "%s: PyModule_GetDict(): Failed to obtain a reference to the dictionary associated with the main module.", acRoutine);
513     return ER;
514   }
515 }
516 #endif
517 
518   return ER_OK;
519 }
520 
521 
522 /*-
523  ***********************************************************************
524  *
525  * FTimesFreeProperties
526  *
527  ***********************************************************************
528  */
529 void
FTimesFreeProperties(FTIMES_PROPERTIES * psProperties)530 FTimesFreeProperties(FTIMES_PROPERTIES *psProperties)
531 {
532   if (psProperties != NULL)
533   {
534     DecodeFreeSnapshotContext(psProperties->psBaselineContext);
535     DecodeFreeSnapshotContext(psProperties->psSnapshotContext);
536 #ifdef USE_SSL
537     SslFreeProperties(psProperties->psSslProperties);
538 #endif
539     if (psProperties->pcNonce)
540     {
541       free(psProperties->pcNonce);
542     }
543     OptionsFreeOptionsContext(psProperties->psOptionsContext);
544     free(psProperties);
545   }
546 }
547 
548 
549 /*-
550  ***********************************************************************
551  *
552  * FTimesNewProperties
553  *
554  ***********************************************************************
555  */
556 FTIMES_PROPERTIES *
FTimesNewProperties(char * pcError)557 FTimesNewProperties(char *pcError)
558 {
559   const char          acRoutine[] = "FTimesNewProperties()";
560   char                acLocalError[MESSAGE_SIZE] = "";
561   char               *pcValue = NULL;
562   FTIMES_PROPERTIES  *psProperties;
563 
564   /*
565    *********************************************************************
566    *
567    * Allocate and clear memory for the properties structure.
568    *
569    *********************************************************************
570    */
571   psProperties = (FTIMES_PROPERTIES *) calloc(sizeof(FTIMES_PROPERTIES), 1);
572   if (psProperties == NULL)
573   {
574     snprintf(pcError, MESSAGE_SIZE, "%s: calloc(): %s", acRoutine, strerror(errno));
575     return NULL;
576   }
577 
578   /*-
579    *********************************************************************
580    *
581    * Initialize variables that require a non-zero value.
582    *
583    *********************************************************************
584    */
585   TimeGetTimeValue(&psProperties->tvJobEpoch);
586   psProperties->dStartTime = (double) psProperties->tvJobEpoch.tv_sec + (double) psProperties->tvJobEpoch.tv_usec * 0.000001;
587   psProperties->tStartTime = TimeGetTime(psProperties->acStartDate, psProperties->acStartTime, psProperties->acStartZone, psProperties->acDateTime);
588   memcpy(psProperties->acRunDateTime, psProperties->acDateTime, FTIMES_TIME_SIZE);
589 
590   /*
591    *********************************************************************
592    *
593    * Initialize function pointers.
594    *
595    *********************************************************************
596    */
597   psProperties->piDevelopMapOutput = DevelopNoOutput;
598 
599   /*-
600    *********************************************************************
601    *
602    * Initialize LogLevel variable.
603    *
604    *********************************************************************
605    */
606   psProperties->iLogLevel = MESSAGE_LANDMARK;
607   MessageSetLogLevel(psProperties->iLogLevel);
608 
609   /*-
610    *********************************************************************
611    *
612    * Initialize NewLine variable.
613    *
614    *********************************************************************
615    */
616 #ifdef WIN32
617   strncpy(psProperties->acNewLine, CRLF, NEWLINE_LENGTH);
618 #else
619   strncpy(psProperties->acNewLine, LF, NEWLINE_LENGTH);
620 #endif
621 
622   /*-
623    *********************************************************************
624    *
625    * Initialize Pid variable.
626    *
627    *********************************************************************
628    */
629   snprintf(psProperties->acPid, FTIMES_PID_SIZE, "%d", (int) getpid());
630 
631   /*-
632    *********************************************************************
633    *
634    * Initialize RunType variable.
635    *
636    *********************************************************************
637    */
638   strncpy(psProperties->acRunType, "baseline", RUNTYPE_BUFSIZE);
639 
640   /*-
641    *********************************************************************
642    *
643    * Initialize EnableRecursion variable.
644    *
645    *********************************************************************
646    */
647   psProperties->bEnableRecursion = TRUE;
648 
649   /*-
650    *********************************************************************
651    *
652    * Initialize Analyze*Size variables.
653    *
654    *********************************************************************
655    */
656   psProperties->iAnalyzeBlockSize = AnalyzeGetBlockSize();
657   psProperties->iAnalyzeCarrySize = AnalyzeGetCarrySize();
658 #ifdef USE_XMAGIC
659   psProperties->iAnalyzeStepSize = AnalyzeGetStepSize();
660 #endif
661 
662   /*-
663    *********************************************************************
664    *
665    * Initialize baseline context.
666    *
667    *********************************************************************
668    */
669   psProperties->psBaselineContext = DecodeNewSnapshotContext(acLocalError);
670   if (psProperties->psBaselineContext == NULL)
671   {
672     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
673     FTimesFreeProperties(psProperties);
674     return NULL;
675   }
676 
677   /*-
678    *********************************************************************
679    *
680    * Initialize snapshot context.
681    *
682    *********************************************************************
683    */
684   psProperties->psSnapshotContext = DecodeNewSnapshotContext(acLocalError);
685   if (psProperties->psSnapshotContext == NULL)
686   {
687     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
688     FTimesFreeProperties(psProperties);
689     return NULL;
690   }
691 
692 #ifdef USE_SSL
693   /*-
694    *********************************************************************
695    *
696    * Initialize SSL properties.
697    *
698    *********************************************************************
699    */
700   psProperties->psSslProperties = SslNewProperties(acLocalError);
701   if (psProperties->psSslProperties == NULL)
702   {
703     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
704     FTimesFreeProperties(psProperties);
705     return NULL;
706   }
707 #endif
708 
709   /*-
710    *********************************************************************
711    *
712    * Initialize TempDirectory variable.
713    *
714    *********************************************************************
715    */
716 #ifdef WIN32
717   pcValue = FTimesGetEnvValue("TEMP");
718 #else
719   pcValue = FTimesGetEnvValue("TMPDIR");
720 #endif
721   if (pcValue == NULL)
722   {
723     pcValue = FTimesGetEnvValue("TMP");
724   }
725   if (pcValue == NULL || strlen(pcValue) > sizeof(psProperties->acTempDirectory) - 1)
726   {
727     pcValue = FTIMES_TEMP_DIRECTORY;
728   }
729   strncpy(psProperties->acTempDirectory, pcValue, sizeof(psProperties->acTempDirectory));
730 
731   /*-
732    *********************************************************************
733    *
734    * Initialize MemoryMapEnable variable -- it should be on by default.
735    * Next, check the environment to see if it should be disabled.
736    *
737    *********************************************************************
738    */
739   psProperties->iMemoryMapEnable = 1;
740   pcValue = FTimesGetEnvValue("FTIMES_MMAP_ENABLE");
741   if (pcValue != NULL && strlen(pcValue) == 1 && (pcValue[0] == '0' || pcValue[0] == 'N' || pcValue[0] == 'n'))
742   {
743     psProperties->iMemoryMapEnable = 0;
744   }
745 
746   /*-
747    *********************************************************************
748    *
749    * Initialize the output's MD5 hash.
750    *
751    *********************************************************************
752    */
753   MD5Alpha(&psProperties->sOutFileHashContext);
754 
755   return psProperties;
756 }
757 
758 
759 /*-
760  ***********************************************************************
761  *
762  * FTimesOptionHandler
763  *
764  ***********************************************************************
765  */
766 int
FTimesOptionHandler(OPTIONS_TABLE * psOption,char * pcValue,FTIMES_PROPERTIES * psProperties,char * pcError)767 FTimesOptionHandler(OPTIONS_TABLE *psOption, char *pcValue, FTIMES_PROPERTIES *psProperties, char *pcError)
768 {
769   const char          acRoutine[] = "FTimesOptionHandler()";
770   char                acLocalError[MESSAGE_SIZE] = "";
771   int                 iError = 0;
772   int                 iLength = 0;
773 
774   iLength = (pcValue == NULL) ? 0 : strlen(pcValue);
775 
776   switch (psOption->iId)
777   {
778   case OPT_LogLevel:
779     iError = SupportSetLogLevel(pcValue, &psProperties->iLogLevel, acLocalError);
780     if (iError != ER_OK)
781     {
782       snprintf(pcError, MESSAGE_SIZE, "%s: option=[%s]: Argument (%s) does not pass muster (%s).", acRoutine, psOption->atcFullName, pcValue, acLocalError);
783       return ER;
784     }
785     break;
786   case OPT_MagicFile:
787     if (iLength < 1 || iLength > FTIMES_MAX_PATH - 1)
788     {
789       snprintf(pcError, MESSAGE_SIZE, "%s: option=[%s]: Argument length must be in the range [1-%d].", acRoutine, psOption->atcFullName, FTIMES_MAX_PATH - 1);
790       return ER;
791     }
792     strncpy(psProperties->acMagicFileName, pcValue, FTIMES_MAX_PATH);
793     break;
794   case OPT_MemoryMapEnable:
795     if (strcasecmp(pcValue, "1") == 0 || strcasecmp(pcValue, "Y") == 0)
796     {
797       psProperties->iMemoryMapEnable = 1;
798     }
799     else if (strcasecmp(pcValue, "0") == 0 || strcasecmp(pcValue, "N") == 0)
800     {
801       psProperties->iMemoryMapEnable = 0;
802     }
803     else
804     {
805       snprintf(pcError, MESSAGE_SIZE, "%s: option=[%s]: Argument (%s) does not pass muster. Use one of \"Y\" or \"N\".", acRoutine, psOption->atcFullName, pcValue);
806       return ER;
807     }
808     break;
809   case OPT_NamesAreCaseInsensitive:
810     psProperties->psSnapshotContext->iNamesAreCaseInsensitive = 1;
811     psProperties->psBaselineContext->iNamesAreCaseInsensitive = 1;
812     break;
813   case OPT_StrictTesting:
814     psProperties->iTestLevel = FTIMES_TEST_STRICT;
815     break;
816   default:
817     snprintf(pcError, MESSAGE_SIZE, "%s: Invalid option ID (%d). This should not happen.", acRoutine, psOption->iId);
818     return ER;
819     break;
820   }
821 
822   return ER_OK;
823 }
824 
825 
826 /*-
827  ***********************************************************************
828  *
829  * FTimesProcessArguments
830  *
831  ***********************************************************************
832  */
833 int
FTimesProcessArguments(FTIMES_PROPERTIES * psProperties,int iArgumentCount,char * ppcArgumentVector[],char * pcError)834 FTimesProcessArguments(FTIMES_PROPERTIES *psProperties, int iArgumentCount, char *ppcArgumentVector[], char *pcError)
835 {
836   const char          acRoutine[] = "FTimesProcessArguments()";
837   char                acLocalError[MESSAGE_SIZE] = "";
838   char               *pcBaseline = NULL;
839   char               *pcConfigFile = NULL;
840   char               *pcMask = NULL;
841   char               *pcMode = NULL;
842   char               *pcSnapshot = NULL;
843   int                 iError = 0;
844   int                 iOperandCount = 0;
845   OPTIONS_CONTEXT    *psOptionsContext = NULL;
846   static OPTIONS_TABLE asCfgtestOptions[] =
847   {
848     { OPT_StrictTesting, "-s", "--StrictTesting", 0, 0, 0, 0, FTimesOptionHandler },
849   };
850   static OPTIONS_TABLE asCompareOptions[] =
851   {
852     { OPT_LogLevel, "-l", "--LogLevel", 0, 0, 1, 0, FTimesOptionHandler },
853     { OPT_MemoryMapEnable, "", "--MemoryMapEnable", 0, 0, 1, 0, FTimesOptionHandler },
854     { OPT_NamesAreCaseInsensitive, "", "--NamesAreCaseInsensitive", 0, 0, 0, 0, FTimesOptionHandler },
855   };
856   static OPTIONS_TABLE asDecodeOptions[] =
857   {
858     { OPT_LogLevel, "-l", "--LogLevel", 0, 0, 1, 0, FTimesOptionHandler },
859   };
860   static OPTIONS_TABLE asDigOptions[] =
861   {
862     { OPT_LogLevel, "-l", "--LogLevel", 0, 0, 1, 0, FTimesOptionHandler },
863   };
864   static OPTIONS_TABLE asGetOptions[] =
865   {
866     { OPT_LogLevel, "-l", "--LogLevel", 0, 0, 1, 0, FTimesOptionHandler },
867   };
868   static OPTIONS_TABLE asMadOptions[] =
869   {
870     { OPT_LogLevel, "-l", "--LogLevel", 0, 0, 1, 0, FTimesOptionHandler },
871     { OPT_MagicFile, "", "--MagicFile", 0, 0, 1, 0, FTimesOptionHandler },
872   };
873   static OPTIONS_TABLE asMapOptions[] =
874   {
875     { OPT_LogLevel, "-l", "--LogLevel", 0, 0, 1, 0, FTimesOptionHandler },
876     { OPT_MagicFile, "", "--MagicFile", 0, 0, 1, 0, FTimesOptionHandler },
877   };
878 
879   psProperties->pcProgram = ppcArgumentVector[0];
880 
881   if (iArgumentCount < 2)
882   {
883     FTimesUsage();
884   }
885 
886   /*-
887    *********************************************************************
888    *
889    * Initialize the options context.
890    *
891    *********************************************************************
892    */
893   psOptionsContext = OptionsNewOptionsContext(iArgumentCount, ppcArgumentVector, acLocalError);
894   if (psOptionsContext == NULL)
895   {
896     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
897     return ER;
898   }
899   psProperties->psOptionsContext = psOptionsContext;
900 
901   /*-
902    *********************************************************************
903    *
904    * Determine the run mode.
905    *
906    *********************************************************************
907    */
908   psProperties->pcRunModeArgument = OptionsGetFirstArgument(psOptionsContext);
909   if (psProperties->pcRunModeArgument == NULL)
910   {
911     FTimesUsage();
912   }
913   else
914   {
915     if (strcmp(psProperties->pcRunModeArgument, "--cfgtest") == 0)
916     {
917       psProperties->iRunMode = FTIMES_CFGTEST;
918       //
919       OptionsSetOptions(psOptionsContext, asCfgtestOptions, (sizeof(asCfgtestOptions) / sizeof(asCfgtestOptions[0])));
920       //
921       psProperties->piRunModeFinalStage = PropertiesTestFile;
922     }
923     else if (strcmp(psProperties->pcRunModeArgument, "--compare") == 0)
924     {
925       psProperties->iRunMode = FTIMES_CMPMODE;
926       //
927       OptionsSetOptions(psOptionsContext, asCompareOptions, (sizeof(asCompareOptions) / sizeof(asCompareOptions[0])));
928       //
929       strcpy(psProperties->acDataType, FTIMES_CMPDATA);
930       //
931       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "CmpModeInitialize");
932       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_Initialize;
933       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = CmpModeInitialize;
934       //
935       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "CmpModeCheckDependencies");
936       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_CheckDependencies;
937       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = CmpModeCheckDependencies;
938       //
939       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "CmpModeFinalize");
940       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_Finalize;
941       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = CmpModeFinalize;
942       //
943       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "CmpModeWorkHorse");
944       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_WorkHorse;
945       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = CmpModeWorkHorse;
946       //
947       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "CmpModeFinishUp");
948       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_FinishUp;
949       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = CmpModeFinishUp;
950       //
951       psProperties->piRunModeFinalStage = CmpModeFinalStage;
952     }
953     else if (strcmp(psProperties->pcRunModeArgument, "--decode") == 0 || strcmp(psProperties->pcRunModeArgument, "--decoder") == 0)
954     {
955       psProperties->iRunMode = FTIMES_DECODER;
956       //
957       OptionsSetOptions(psOptionsContext, asDecodeOptions, (sizeof(asDecodeOptions) / sizeof(asDecodeOptions[0])));
958       //
959       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "DecoderInitialize");
960       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_Initialize;
961       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = DecoderInitialize;
962       //
963       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "DecoderCheckDependencies");
964       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_CheckDependencies;
965       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = DecoderCheckDependencies;
966       //
967       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "DecoderFinalize");
968       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_Finalize;
969       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = DecoderFinalize;
970       //
971       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "DecoderWorkHorse");
972       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_WorkHorse;
973       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = DecoderWorkHorse;
974       //
975       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "DecoderFinishUp");
976       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_FinishUp;
977       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = DecoderFinishUp;
978       //
979       psProperties->piRunModeFinalStage = DecoderFinalStage;
980     }
981     else if (strncmp(psProperties->pcRunModeArgument, "--dig", 5) == 0)
982     {
983       if (strcmp(psProperties->pcRunModeArgument, "--digauto") == 0)
984       {
985         psProperties->iRunMode = FTIMES_DIGAUTO;
986       }
987       else if (strcmp(psProperties->pcRunModeArgument, "--dig") == 0)
988       {
989         psProperties->iRunMode = FTIMES_DIGMODE;
990       }
991       else if (strcmp(psProperties->pcRunModeArgument, "--digfull") == 0)
992       {
993         psProperties->iRunMode = FTIMES_DIGMODE; /* Note that --digfull is maintained for backwards compatibility. */
994       }
995       else if (strcmp(psProperties->pcRunModeArgument, "--diglean") == 0)
996       {
997         psProperties->iRunMode = FTIMES_DIGMODE; /* Note that --diglean is maintained for backwards compatibility. */
998       }
999       else
1000       {
1001         FTimesUsage();
1002       }
1003       //
1004       OptionsSetOptions(psOptionsContext, asDigOptions, (sizeof(asDigOptions) / sizeof(asDigOptions[0])));
1005       //
1006       strcpy(psProperties->acDataType, FTIMES_DIGDATA);
1007       //
1008       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "DigModeInitialize");
1009       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_Initialize;
1010       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = DigModeInitialize;
1011       //
1012       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "DigModeCheckDependencies");
1013       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_CheckDependencies;
1014       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = DigModeCheckDependencies;
1015       //
1016       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "DigModeFinalize");
1017       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_Finalize;
1018       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = DigModeFinalize;
1019       //
1020       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "DigModeWorkHorse");
1021       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_WorkHorse;
1022       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = DigModeWorkHorse;
1023       //
1024       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "DigModeFinishUp");
1025       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_FinishUp;
1026       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = DigModeFinishUp;
1027       //
1028       psProperties->piRunModeFinalStage = DigModeFinalStage;
1029     }
1030     else if (strcmp(psProperties->pcRunModeArgument, "--get") == 0 || strcmp(psProperties->pcRunModeArgument, "--getmode") == 0)
1031     {
1032       psProperties->iRunMode = FTIMES_GETMODE;
1033       //
1034       OptionsSetOptions(psOptionsContext, asGetOptions, (sizeof(asGetOptions) / sizeof(asGetOptions[0])));
1035       //
1036       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "GetModeInitialize");
1037       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_Initialize;
1038       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = GetModeInitialize;
1039       //
1040       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "GetModeCheckDependencies");
1041       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_CheckDependencies;
1042       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = GetModeCheckDependencies;
1043       //
1044       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "GetModeFinalize");
1045       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_Finalize;
1046       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = GetModeFinalize;
1047       //
1048       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "GetModeWorkHorse");
1049       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_WorkHorse;
1050       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = GetModeWorkHorse;
1051       //
1052       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "GetModeFinishUp");
1053       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_FinishUp;
1054       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = GetModeFinishUp;
1055       //
1056       psProperties->piRunModeFinalStage = GetModeFinalStage;
1057     }
1058     else if (strcmp(psProperties->pcRunModeArgument, "--mad") == 0)
1059     {
1060       psProperties->iRunMode = FTIMES_MADMODE;
1061       //
1062       OptionsSetOptions(psOptionsContext, asMadOptions, (sizeof(asMadOptions) / sizeof(asMadOptions[0])));
1063       //
1064       strcpy(psProperties->acDataType, FTIMES_MADDATA);
1065       //
1066       strcpy(psProperties->acDigRecordPrefix, "dig|");
1067       strcpy(psProperties->acMapRecordPrefix, "map|");
1068       //
1069       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "MadModeInitialize");
1070       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_Initialize;
1071       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = MadModeInitialize;
1072       //
1073       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "MadModeCheckDependencies");
1074       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_CheckDependencies;
1075       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = MadModeCheckDependencies;
1076       //
1077       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "MadModeFinalize");
1078       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_Finalize;
1079       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = MadModeFinalize;
1080       //
1081       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "MadModeWorkHorse");
1082       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_WorkHorse;
1083       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = MadModeWorkHorse;
1084       //
1085       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "MadModeFinishUp");
1086       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_FinishUp;
1087       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = MadModeFinishUp;
1088       //
1089       psProperties->piRunModeFinalStage = MadModeFinalStage;
1090     }
1091     else if (strncmp(psProperties->pcRunModeArgument, "--map", 5) == 0)
1092     {
1093       if (strcmp(psProperties->pcRunModeArgument, "--mapauto") == 0)
1094       {
1095         psProperties->iRunMode = FTIMES_MAPAUTO;
1096       }
1097       else if (strcmp(psProperties->pcRunModeArgument, "--map") == 0)
1098       {
1099         psProperties->iRunMode = FTIMES_MAPMODE;
1100       }
1101       else if (strcmp(psProperties->pcRunModeArgument, "--mapfull") == 0)
1102       {
1103         psProperties->iRunMode = FTIMES_MAPMODE; /* Note that --mapfull is maintained for backwards compatibility. */
1104       }
1105       else if (strcmp(psProperties->pcRunModeArgument, "--maplean") == 0)
1106       {
1107         psProperties->iRunMode = FTIMES_MAPMODE; /* Note that --maplean is maintained for backwards compatibility. */
1108       }
1109       else
1110       {
1111         FTimesUsage();
1112       }
1113       //
1114       OptionsSetOptions(psOptionsContext, asMapOptions, (sizeof(asMapOptions) / sizeof(asMapOptions[0])));
1115       //
1116       strcpy(psProperties->acDataType, FTIMES_MAPDATA);
1117       //
1118       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "MapModeInitialize");
1119       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_Initialize;
1120       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = MapModeInitialize;
1121       //
1122       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "MapModeCheckDependencies");
1123       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_CheckDependencies;
1124       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = MapModeCheckDependencies;
1125       //
1126       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "MapModeFinalize");
1127       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_Finalize;
1128       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = MapModeFinalize;
1129       //
1130       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "MapModeWorkHorse");
1131       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_WorkHorse;
1132       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = MapModeWorkHorse;
1133       //
1134       strcpy(psProperties->sRunModeStages[psProperties->iLastRunModeStage].acDescription, "MapModeFinishUp");
1135       psProperties->sRunModeStages[psProperties->iLastRunModeStage].iError = XER_FinishUp;
1136       psProperties->sRunModeStages[psProperties->iLastRunModeStage++].piRoutine = MapModeFinishUp;
1137       //
1138       psProperties->piRunModeFinalStage = MapModeFinalStage;
1139     }
1140     else if (strcmp(psProperties->pcRunModeArgument, "-v") == 0 || strcmp(psProperties->pcRunModeArgument, "--version") == 0)
1141     {
1142       FTimesVersion();
1143     }
1144     else
1145     {
1146       FTimesUsage();
1147     }
1148   }
1149   OptionsSetArgumentType(psOptionsContext, OPTIONS_ARGUMENT_TYPE_MODE);
1150 
1151   /*-
1152    *********************************************************************
1153    *
1154    * Process options.
1155    *
1156    *********************************************************************
1157    */
1158   iError = OptionsProcessOptions(psOptionsContext, (void *) psProperties, acLocalError);
1159   switch (iError)
1160   {
1161   case OPTIONS_ER:
1162     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
1163     return ER;
1164     break;
1165   case OPTIONS_OK:
1166     break;
1167   case OPTIONS_USAGE:
1168   default:
1169     FTimesUsage();
1170     break;
1171   }
1172 
1173   /*-
1174    *********************************************************************
1175    *
1176    * Handle any special cases and/or remaining arguments.
1177    *
1178    *********************************************************************
1179    */
1180   iOperandCount = OptionsGetOperandCount(psOptionsContext);
1181   switch (psProperties->iRunMode)
1182   {
1183   case FTIMES_CFGTEST:
1184     if (iOperandCount != 2)
1185     {
1186       FTimesUsage();
1187     }
1188     pcConfigFile = OptionsGetFirstOperand(psOptionsContext);
1189     if (pcConfigFile == NULL)
1190     {
1191       snprintf(pcError, MESSAGE_SIZE, "%s: Unable to get config file argument.", acRoutine);
1192       return ER;
1193     }
1194     strncpy(psProperties->acConfigFile, pcConfigFile, FTIMES_MAX_PATH);
1195     pcMode = OptionsGetNextOperand(psOptionsContext);
1196     if (pcMode == NULL)
1197     {
1198       snprintf(pcError, MESSAGE_SIZE, "%s: Unable to get mode argument.", acRoutine);
1199       return ER;
1200     }
1201     if (strcasecmp(pcMode, "digauto") == 0)
1202     {
1203       psProperties->iTestRunMode = FTIMES_DIGAUTO;
1204     }
1205     else if
1206     (
1207       strcasecmp(pcMode, "dig") == 0 ||
1208       strcasecmp(pcMode, "digfull") == 0 ||
1209       strcasecmp(pcMode, "diglean") == 0
1210     )
1211     {
1212       psProperties->iTestRunMode = FTIMES_DIGMODE;
1213     }
1214     else if
1215     (
1216       strcasecmp(pcMode, "get") == 0 ||
1217       strcasecmp(pcMode, "getmode") == 0
1218     )
1219     {
1220       psProperties->iTestRunMode = FTIMES_GETMODE;
1221     }
1222     else if (strcasecmp(pcMode, "mad") == 0)
1223     {
1224       psProperties->iTestRunMode = FTIMES_MADMODE;
1225     }
1226     else if
1227     (
1228       strcasecmp(pcMode, "map") == 0 ||
1229       strcasecmp(pcMode, "mapfull") == 0 ||
1230       strcasecmp(pcMode, "maplean") == 0
1231     )
1232     {
1233       psProperties->iTestRunMode = FTIMES_MAPMODE;
1234     }
1235     else
1236     {
1237       snprintf(pcError, MESSAGE_SIZE, "%s: Mode = [%s]: Mode must be one of {dig|digauto|get|mad|map}.", acRoutine, pcMode);
1238       return ER;
1239     }
1240     break;
1241   case FTIMES_CMPMODE:
1242     if (iOperandCount != 3)
1243     {
1244       FTimesUsage();
1245     }
1246     pcMask = OptionsGetFirstOperand(psOptionsContext);
1247     if (pcMask == NULL)
1248     {
1249       snprintf(pcError, MESSAGE_SIZE, "%s: Unable to get mask argument.", acRoutine);
1250       return ER;
1251     }
1252     psProperties->psFieldMask = MaskParseMask(pcMask, MASK_RUNMODE_TYPE_CMP, acLocalError);
1253     if (psProperties->psFieldMask == NULL)
1254     {
1255       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
1256       return ER;
1257     }
1258     pcBaseline = OptionsGetNextOperand(psOptionsContext);
1259     if (pcBaseline == NULL)
1260     {
1261       snprintf(pcError, MESSAGE_SIZE, "%s: Unable to get mask argument.", acRoutine);
1262       return ER;
1263     }
1264     psProperties->psBaselineContext->pcFile = pcBaseline;
1265     pcSnapshot = OptionsGetNextOperand(psOptionsContext);
1266     if (pcSnapshot == NULL)
1267     {
1268       snprintf(pcError, MESSAGE_SIZE, "%s: Unable to get mask argument.", acRoutine);
1269       return ER;
1270     }
1271     psProperties->psSnapshotContext->pcFile = pcSnapshot;
1272     break;
1273   case FTIMES_DECODER:
1274     if (iOperandCount != 1)
1275     {
1276       FTimesUsage();
1277     }
1278     pcSnapshot = OptionsGetNextOperand(psOptionsContext);
1279     if (pcSnapshot == NULL)
1280     {
1281       snprintf(pcError, MESSAGE_SIZE, "%s: Unable to get mask argument.", acRoutine);
1282       return ER;
1283     }
1284     psProperties->psSnapshotContext->pcFile = pcSnapshot;
1285     break;
1286   case FTIMES_DIGAUTO:
1287   case FTIMES_DIGMODE:
1288   case FTIMES_MADMODE:
1289   case FTIMES_MAPMODE:
1290     if (iOperandCount < 1)
1291     {
1292       FTimesUsage();
1293     }
1294     pcConfigFile = OptionsGetFirstOperand(psOptionsContext);
1295     if (pcConfigFile == NULL)
1296     {
1297       snprintf(pcError, MESSAGE_SIZE, "%s: Unable to get config file argument.", acRoutine);
1298       return ER;
1299     }
1300     if (strcmp(pcConfigFile, "-") == 0)
1301     {
1302       strcpy(psProperties->acConfigFile, "-");
1303     }
1304     else
1305     {
1306       iError = SupportExpandPath(pcConfigFile, psProperties->acConfigFile, FTIMES_MAX_PATH, 1, acLocalError);
1307       if (iError != ER_OK)
1308       {
1309         snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
1310         return ER;
1311       }
1312       iError = SupportAddToList(psProperties->acConfigFile, &psProperties->psExcludeList, "Exclude", acLocalError);
1313       if (iError != ER_OK)
1314       {
1315         snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
1316         return ER;
1317       }
1318     }
1319     /* Note: Any remaining operands will be treated as includes. */
1320     break;
1321   case FTIMES_GETMODE:
1322     if (iOperandCount != 1)
1323     {
1324       FTimesUsage();
1325     }
1326     pcConfigFile = OptionsGetFirstOperand(psOptionsContext);
1327     if (pcConfigFile == NULL)
1328     {
1329       snprintf(pcError, MESSAGE_SIZE, "%s: Unable to get config file argument.", acRoutine);
1330       return ER;
1331     }
1332     strncpy(psProperties->acConfigFile, pcConfigFile, FTIMES_MAX_PATH);
1333     break;
1334   case FTIMES_MAPAUTO:
1335     if (iOperandCount < 1)
1336     {
1337       FTimesUsage();
1338     }
1339     pcMask = OptionsGetFirstOperand(psOptionsContext);
1340     if (pcMask == NULL)
1341     {
1342       snprintf(pcError, MESSAGE_SIZE, "%s: Unable to get mask argument.", acRoutine);
1343       return ER;
1344     }
1345     psProperties->psFieldMask = MaskParseMask(pcMask, MASK_RUNMODE_TYPE_MAP, acLocalError);
1346     if (psProperties->psFieldMask == NULL)
1347     {
1348       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
1349       return ER;
1350     }
1351     /* Note: Any remaining operands will be treated as includes. */
1352     break;
1353   default:
1354     FTimesUsage();
1355     break;
1356   }
1357 
1358   /*-
1359    *********************************************************************
1360    *
1361    * If any required arguments are missing, it's an error.
1362    *
1363    *********************************************************************
1364    */
1365   if (OptionsHaveRequiredOptions(psOptionsContext) == 0)
1366   {
1367     FTimesUsage();
1368   }
1369 
1370   return ER_OK;
1371 }
1372 
1373 
1374 /*-
1375  ***********************************************************************
1376  *
1377  * FTimesStagesLoop
1378  *
1379  ***********************************************************************
1380  */
1381 int
FTimesStagesLoop(FTIMES_PROPERTIES * psProperties,char * pcError)1382 FTimesStagesLoop(FTIMES_PROPERTIES *psProperties, char *pcError)
1383 {
1384   const char          acRoutine[] = "FTimesStagesLoop()";
1385   char                acLocalError[MESSAGE_SIZE] = "";
1386   char                acMessage[MESSAGE_SIZE];
1387   int                 i;
1388   int                 iError;
1389 
1390   /*-
1391    *******************************************************************
1392    *
1393    * Display some basic information.
1394    *
1395    *******************************************************************
1396    */
1397   snprintf(acMessage, MESSAGE_SIZE, "Program=%s %s", VersionGetVersion(), psProperties->pcRunModeArgument);
1398   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
1399 
1400   snprintf(acMessage, MESSAGE_SIZE, "SystemOS=%s", SupportGetSystemOS());
1401   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
1402 
1403   snprintf(acMessage, MESSAGE_SIZE, "Hostname=%s", SupportGetHostname());
1404   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
1405 
1406   if (psProperties->tStartTime == ER)
1407   {
1408     snprintf(acMessage, MESSAGE_SIZE, "JobEpoch=NA");
1409   }
1410   else
1411   {
1412     snprintf(acMessage, MESSAGE_SIZE, "JobEpoch=%s %s %s", psProperties->acStartDate, psProperties->acStartTime, psProperties->acStartZone);
1413   }
1414   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
1415 
1416   snprintf(acMessage, MESSAGE_SIZE, "JobPid=%s", psProperties->acPid);
1417   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
1418 
1419 #ifdef UNIX
1420   snprintf(acMessage, MESSAGE_SIZE, "JobUid=%d", (int) getuid());
1421   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
1422 #endif
1423 
1424   snprintf(acMessage, MESSAGE_SIZE, "LogLevel=%d", psProperties->iLogLevel);
1425   MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_INFORMATION, MESSAGE_PROPERTY_STRING, acMessage);
1426 
1427   /*-
1428    *******************************************************************
1429    *
1430    * Loop over the RunMode stages.
1431    *
1432    *******************************************************************
1433    */
1434   for (i = 0; i < psProperties->iLastRunModeStage; i++)
1435   {
1436     if (psProperties->sRunModeStages[i].piRoutine != NULL)
1437     {
1438       snprintf(acMessage, MESSAGE_SIZE, "Stage%d=%s", i + 1, psProperties->sRunModeStages[i].acDescription);
1439       MessageHandler(MESSAGE_QUEUE_IT, MESSAGE_LANDMARK, MESSAGE_LANDMARK_STRING, acMessage);
1440       iError = psProperties->sRunModeStages[i].piRoutine(psProperties, acLocalError);
1441       if (iError != ER_OK)
1442       {
1443         snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
1444         return psProperties->sRunModeStages[i].iError;
1445       }
1446     }
1447   }
1448 
1449   MessageHandler(MESSAGE_FLUSH_IT, MESSAGE_ALWAYSON, NULL, NULL);
1450 
1451   return ER_OK;
1452 }
1453 
1454 
1455 /*-
1456  ***********************************************************************
1457  *
1458  * FTimesFinalStage
1459  *
1460  ***********************************************************************
1461  */
1462 int
FTimesFinalStage(FTIMES_PROPERTIES * psProperties,char * pcError)1463 FTimesFinalStage(FTIMES_PROPERTIES *psProperties, char *pcError)
1464 {
1465   const char          acRoutine[] = "FTimesFinalStage()";
1466   char                acLocalError[MESSAGE_SIZE] = "";
1467   int                 iError;
1468 
1469   /*-
1470    *********************************************************************
1471    *
1472    * Flush the Message Handler, and close the LogFile stream.
1473    *
1474    *********************************************************************
1475    */
1476   if (psProperties->pFileLog && psProperties->pFileLog != stderr)
1477   {
1478     MessageHandler(MESSAGE_FLUSH_IT, MESSAGE_INFORMATION, NULL, NULL);
1479     fclose(psProperties->pFileLog);
1480     psProperties->pFileLog = NULL;
1481   }
1482 
1483   /*-
1484    *********************************************************************
1485    *
1486    * Invoke the RunMode specific routine.
1487    *
1488    *********************************************************************
1489    */
1490   if (psProperties->piRunModeFinalStage)
1491   {
1492     iError = psProperties->piRunModeFinalStage(psProperties, acLocalError);
1493     if (iError != ER_OK)
1494     {
1495       snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
1496       return ER;
1497     }
1498   }
1499 
1500 #ifdef WINNT
1501   /*-
1502    *********************************************************************
1503    *
1504    * Release any library handles.
1505    *
1506    *********************************************************************
1507    */
1508   if (NtdllHandle)
1509   {
1510     FreeLibrary(NtdllHandle);
1511   }
1512 #endif
1513 
1514 #ifdef USE_EMBEDDED_PERL
1515   /*-
1516    *********************************************************************
1517    *
1518    * Release the Perl interpreter.
1519    *
1520    *********************************************************************
1521    */
1522   if (psProperties->psMyPerl != NULL)
1523   {
1524     PL_perl_destruct_level = 1; /* This must be set to 1 since perl_construct() reset it to 0 according to perlembed. */
1525     perl_destruct(psProperties->psMyPerl);
1526     perl_free(psProperties->psMyPerl);
1527     PERL_SYS_TERM();
1528   }
1529 #endif
1530 
1531 #ifdef USE_EMBEDDED_PYTHON
1532   /*-
1533    *********************************************************************
1534    *
1535    * Release the Python interpreter.
1536    *
1537    *********************************************************************
1538    */
1539   Py_XDECREF(psProperties->psPyGlobals);
1540   Py_Finalize();
1541 #endif
1542 
1543   return ER_OK;
1544 }
1545 
1546 
1547 /*-
1548  ***********************************************************************
1549  *
1550  * FTimesUsage
1551  *
1552  ***********************************************************************
1553  */
1554 void
FTimesUsage(void)1555 FTimesUsage(void)
1556 {
1557   fprintf(stderr, "\n");
1558   fprintf(stderr, "Usage: ftimes --cfgtest file mode [-s]\n");
1559   fprintf(stderr, "       ftimes --compare mask baseline snapshot [-l {0-6}]\n");
1560   fprintf(stderr, "       ftimes --decode snapshot [-l {0-6}]\n");
1561   fprintf(stderr, "       ftimes --dig file [-l {0-6}] [target [...]]\n");
1562   fprintf(stderr, "       ftimes --digauto file [-l {0-6}] [target [...]]\n");
1563   fprintf(stderr, "       ftimes --get file [-l {0-6}]\n");
1564   fprintf(stderr, "       ftimes --mad file [-l {0-6}] [target [...]]\n");
1565   fprintf(stderr, "       ftimes --map file [-l {0-6}] [target [...]]\n");
1566   fprintf(stderr, "       ftimes --mapauto mask [-l {0-6}] [target [...]]\n");
1567   fprintf(stderr, "       ftimes {-v|--version}\n");
1568   fprintf(stderr, "\n");
1569   exit(XER_Usage);
1570 }
1571 
1572 
1573 /*-
1574  ***********************************************************************
1575  *
1576  * FTimesVersion
1577  *
1578  ***********************************************************************
1579  */
1580 void
FTimesVersion(void)1581 FTimesVersion(void)
1582 {
1583   fprintf(stdout, "%s\n", VersionGetVersion());
1584   exit(XER_OK);
1585 }
1586 
1587 
1588 /*-
1589  ***********************************************************************
1590  *
1591  * FTimesSetPropertiesReference
1592  *
1593  ***********************************************************************
1594  */
1595 void
FTimesSetPropertiesReference(FTIMES_PROPERTIES * psProperties)1596 FTimesSetPropertiesReference(FTIMES_PROPERTIES *psProperties)
1597 {
1598   gpsProperties = psProperties;
1599   DigSetPropertiesReference(psProperties);
1600 }
1601 
1602 
1603 /*-
1604  ***********************************************************************
1605  *
1606  * FTimesGetEnvValue
1607  *
1608  ***********************************************************************
1609  */
1610 char *
FTimesGetEnvValue(char * pcName)1611 FTimesGetEnvValue(char *pcName)
1612 {
1613 #ifdef WIN32
1614   char               *pcValue = NULL;
1615   DWORD               dwCount = 0;
1616 
1617 #define FTIMES_MAX_ENV_SIZE 32767 /* Source = MSDN documentation for GetEnvironmentVariable() */
1618   pcValue = calloc(FTIMES_MAX_ENV_SIZE, 1);
1619   if (pcValue == NULL)
1620   {
1621     return NULL;
1622   }
1623   dwCount = GetEnvironmentVariable(TEXT(pcName), pcValue, FTIMES_MAX_ENV_SIZE);
1624   return (dwCount == 0 || dwCount > FTIMES_MAX_ENV_SIZE) ? NULL : pcValue;
1625 #else
1626   return getenv(pcName);
1627 #endif
1628 }
1629 
1630 
1631 /*-
1632  ***********************************************************************
1633  *
1634  * FTimesGetPropertiesReference
1635  *
1636  ***********************************************************************
1637  */
1638 FTIMES_PROPERTIES *
FTimesGetPropertiesReference(void)1639 FTimesGetPropertiesReference(void)
1640 {
1641   return gpsProperties;
1642 }
1643 
1644 
1645 /*-
1646  ***********************************************************************
1647  *
1648  * FTimesEraseFiles
1649  *
1650  ***********************************************************************
1651  */
1652 void
FTimesEraseFiles(FTIMES_PROPERTIES * psProperties,char * pcError)1653 FTimesEraseFiles(FTIMES_PROPERTIES *psProperties, char *pcError)
1654 {
1655   const char          acRoutine[] = "FTimesEraseFiles()";
1656   char                acLocalError[MESSAGE_SIZE] = "";
1657   int                 iError;
1658 
1659   iError = SupportEraseFile(psProperties->acLogFileName, acLocalError);
1660   if (iError != ER_OK)
1661   {
1662     snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s]: %s", acRoutine, psProperties->acLogFileName, acLocalError);
1663     ErrorHandler(ER_Warning, pcError, ERROR_WARNING);
1664   }
1665   iError = SupportEraseFile(psProperties->acOutFileName, acLocalError);
1666   if (iError != ER_OK)
1667   {
1668     snprintf(pcError, MESSAGE_SIZE, "%s: File = [%s]: %s", acRoutine, psProperties->acOutFileName, acLocalError);
1669     ErrorHandler(ER_Warning, pcError, ERROR_WARNING);
1670   }
1671 }
1672 
1673 
1674 /*-
1675  ***********************************************************************
1676  *
1677  * MakeNonce
1678  *
1679  ***********************************************************************
1680  */
1681 char *
MakeNonce(char * pcError)1682 MakeNonce(char *pcError)
1683 {
1684   const char          acRoutine[] = "MakeNonce()";
1685   char               *pcNonce = NULL;
1686   unsigned char       a = 0;
1687   unsigned char       b = 0;
1688   unsigned char       c = 0;
1689   unsigned char       d = 0;
1690   long                lValue = 0;
1691 
1692 #ifdef WIN32
1693   lValue = (GetTickCount() << 16) | rand();
1694 #else
1695   lValue = random();
1696 #endif
1697   a = (unsigned char) ((lValue >> 24) & 0xff);
1698   b = (unsigned char) ((lValue >> 16) & 0xff);
1699   c = (unsigned char) ((lValue >>  8) & 0xff);
1700   d = (unsigned char) ((lValue >>  0) & 0xff);
1701   pcNonce = calloc(FTIMES_NONCE_SIZE, 1);
1702   if (pcNonce == NULL)
1703   {
1704     snprintf(pcError, MESSAGE_SIZE, "%s: calloc(): %s", acRoutine, strerror(errno));
1705     return NULL;
1706   }
1707   snprintf(pcNonce, FTIMES_NONCE_SIZE, "%02x%02x%02x%02x", a, b, c, d);
1708   return pcNonce;
1709 }
1710 
1711 
1712 /*-
1713  ***********************************************************************
1714  *
1715  * SeedRandom
1716  *
1717  ***********************************************************************
1718  */
1719 int
SeedRandom(unsigned long ulTime1,unsigned long ulTime2,char * pcError)1720 SeedRandom(unsigned long ulTime1, unsigned long ulTime2, char *pcError)
1721 {
1722   const char          acRoutine[] = "SeedRandom()";
1723 
1724   if (ulTime1 == (unsigned long) ~0 || ulTime2 == (unsigned long) ~0)
1725   {
1726     snprintf(pcError, MESSAGE_SIZE, "%s: Seed values are blatantly abnormal!: Time1 = [%08lx], Time2 = [%08lx]", acRoutine, ulTime1, ulTime2);
1727     return ER;
1728   }
1729 
1730 #ifdef WIN32
1731     srand((unsigned long) (0xE97482AD ^ ((ulTime1 << 16) | (ulTime1 >> 16)) ^ ulTime2 ^ getpid() ^ GetTickCount()));
1732 #else
1733   srandom((unsigned long) (0xE97482AD ^ ((ulTime1 << 16) | (ulTime1 >> 16)) ^ ulTime2 ^ getpid()));
1734 #endif
1735   return ER_OK;
1736 }
1737 
1738 
1739 #ifdef USE_SSL
1740 /*-
1741  ***********************************************************************
1742  *
1743  * SSLCheckDependencies
1744  *
1745  ***********************************************************************
1746  */
1747 int
SSLCheckDependencies(SSL_PROPERTIES * psProperties,char * pcError)1748 SSLCheckDependencies(SSL_PROPERTIES *psProperties, char *pcError)
1749 {
1750   const char          acRoutine[] = "SSLCheckDependencies()";
1751 
1752   if (psProperties->iUseCertificate)
1753   {
1754     if (psProperties->pcPublicCertFile == NULL || psProperties->pcPublicCertFile[0] == 0)
1755     {
1756       snprintf(pcError, MESSAGE_SIZE, "%s: Missing SSLPublicCertFile.", acRoutine);
1757       return ER;
1758     }
1759 
1760     if (psProperties->pcPrivateKeyFile == NULL || psProperties->pcPrivateKeyFile[0] == 0)
1761     {
1762       snprintf(pcError, MESSAGE_SIZE, "%s: Missing SSLPrivateKeyFile.", acRoutine);
1763       return ER;
1764     }
1765   }
1766 
1767   if (psProperties->iVerifyPeerCert)
1768   {
1769     if (psProperties->pcBundledCAsFile == NULL || psProperties->pcBundledCAsFile[0] == 0)
1770     {
1771       snprintf(pcError, MESSAGE_SIZE, "%s: Missing SSLBundledCAsFile.", acRoutine);
1772       return ER;
1773     }
1774 
1775     if (psProperties->pcExpectedPeerCN == NULL || psProperties->pcExpectedPeerCN[0] == 0)
1776     {
1777       snprintf(pcError, MESSAGE_SIZE, "%s: Missing SSLExpectedPeerCN.", acRoutine);
1778       return ER;
1779     }
1780   }
1781 
1782   return ER_OK;
1783 }
1784 #endif
1785