1 /*****************************************************************************/
2 /* Software Testing Automation Framework (STAF)                              */
3 /* (C) Copyright IBM Corp. 2001, 2004, 2005                                  */
4 /*                                                                           */
5 /* This software is licensed under the Eclipse Public License (EPL) V1.0.    */
6 /*****************************************************************************/
7 
8 #include "STAF.h"
9 #include <map>
10 #include <queue>
11 #include "STAFLogService.h"
12 #include "STAF_fstream.h"
13 #include "STAF_iostream.h"
14 #include "STAFString.h"
15 #include "STAFException.h"
16 #include "STAFRefPtr.h"
17 #include "STAFMutexSem.h"
18 #include "STAFCommandParser.h"
19 #include "STAFServiceInterface.h"
20 #include "STAFTimestamp.h"
21 #include "STAFUtil.h"
22 #include "STAFInternalUtil.h"
23 #include "STAFFileSystem.h"
24 #include "STAFRWSem.h"
25 
26 //#define STAF_DO_TIMING
27 #include "STAFTiming.h"
28 
29 // Note: The handleXXX functions for the Log service behave slightly differently
30 //       from other services.  They parse the input before checking the trust
31 //       of the requester.  This is necessary since requests may be forwarded
32 //       from another system.  These requests may contain RMTMACHINE options,
33 //       which specify the originating system.
34 
35 // Type definitions
36 
37 // The STAFLogFileLocks class represents the necessary locks needed to access
38 // a specific log file.  The static acquireLocks() method is used to obtain
39 // access to the appropriate locks.
40 //
41 // Internally, this class maintains a map of all the locks for "active" logs.
42 // An "active" log is one for which there is a request currently being
43 // processed.  Once no more requests are working on a log, the log is no
44 // longer "active" and is removed from the map.  This is handled by maintaining
45 // a "count" of all requests using the locks for a given log.  When the lock
46 // structure is deleted, the count is decremented, and, if it is zero, the
47 // lock structure is removed from the map.
48 //
49 // This internal mechanism is used so that the map of log locks doesn't continue
50 // to grow, which could lead to resource exhaustion (more likely OS semaphores
51 // than memory).  With this, the map stays very small, which also aids in
52 // performance (of lookups).
53 
54 class STAFLogFileLocks;
55 typedef STAFRefPtr<STAFLogFileLocks> STAFLogFileLocksPtr;
56 
57 class STAFLogFileLocks
58 {
59 public:
60 
61     // This is the method used to get access to the locks for a given
62     // log file.
63     static STAFLogFileLocksPtr acquireLocks(const STAFString &logFile);
64 
65     // DEBUG
66     static void dumpLockData();
67 
68     // The logAccess sem allows general access to the log.
69     // A read lock should be obtained for any general read/write operation.
70     // A write lock should be obtainef for any destructive type of change, such
71     // as a purge/delete
72     STAFRWSemPtr logAccess;
73 
74     // The recordAccess sem allows access to individual records.  You should
75     // acquire this sem before attempting to read or write any log records
76     // from/to the file.
77     // Note: You should already have a logAccess lock before acquiring this lock
78     STAFMutexSemPtr recordAccess;
79 
~STAFLogFileLocks()80     ~STAFLogFileLocks()
81     {
82         releaseLocks(logFile);
83     }
84 
85 private:
86 
87     // This is private so that users must go through acquireLocks()
STAFLogFileLocks(STAFRWSemPtr theLogAccess,STAFMutexSemPtr theRecordAccess,const STAFString & theLogFile)88     STAFLogFileLocks(STAFRWSemPtr theLogAccess,
89                      STAFMutexSemPtr theRecordAccess,
90                      const STAFString &theLogFile) :
91         logAccess(theLogAccess),
92         recordAccess(theRecordAccess),
93         logFile(theLogFile)
94     { /* Do nothing */ }
95 
96     STAFString logFile;
97 
98     // This is private so that is only called by the destructor
99     static void releaseLocks(const STAFString &logFile);
100 
101     // This structure holds the real semaphores and access count
102     struct LogLocks
103     {
LogLocksSTAFLogFileLocks::LogLocks104         LogLocks() : logAccess(new STAFRWSem, STAFRWSemPtr::INIT),
105                      recordAccess(new STAFMutexSem, STAFMutexSemPtr::INIT),
106                      count(1)
107         { /* Do nothing */ }
108 
109         STAFRWSemPtr logAccess;
110         STAFMutexSemPtr recordAccess;
111         unsigned int count;
112     };
113 
114     typedef std::map<STAFString, LogLocks> LogLocksMap;
115 
116     static STAFMutexSem logLocksMutex;
117     static std::map<STAFString, LogLocks> logLocks;
118 };
119 
120 STAFMutexSem STAFLogFileLocks::logLocksMutex;
121 STAFLogFileLocks::LogLocksMap STAFLogFileLocks::logLocks;
122 
dumpLockData()123 void STAFLogFileLocks::dumpLockData()
124 {
125     STAFMutexSemLock lock(logLocksMutex);
126 
127     for (LogLocksMap::iterator iter = logLocks.begin();
128          iter != logLocks.end();
129          ++iter)
130     {
131         cout << iter->first << ": " << iter->second.count << endl;
132     }
133 }
134 
acquireLocks(const STAFString & logFile)135 STAFLogFileLocksPtr STAFLogFileLocks::acquireLocks(const STAFString &logFile)
136 {
137     STAFString logFileName = logFile.toLowerCase();
138     STAFMutexSemLock lock(logLocksMutex);
139 
140     LogLocksMap::iterator iter = logLocks.find(logFileName);
141 
142     if (iter != logLocks.end())
143     {
144         ++iter->second.count;
145 
146         return STAFLogFileLocksPtr(new STAFLogFileLocks(
147                                            iter->second.logAccess,
148                                            iter->second.recordAccess,
149                                            logFileName),
150                                    STAFLogFileLocksPtr::INIT);
151     }
152     else
153     {
154         LogLocks theLogLocks;
155         logLocks[logFileName] = theLogLocks;
156 
157         return STAFLogFileLocksPtr(new STAFLogFileLocks(
158                                            theLogLocks.logAccess,
159                                            theLogLocks.recordAccess,
160                                            logFileName),
161                                    STAFLogFileLocksPtr::INIT);
162     }
163 }
164 
releaseLocks(const STAFString & logFile)165 void STAFLogFileLocks::releaseLocks(const STAFString &logFile)
166 {
167     STAFMutexSemLock lock(logLocksMutex);
168     LogLocksMap::iterator iter = logLocks.find(logFile);
169 
170     if ((iter != logLocks.end()) && (--iter->second.count == 0))
171     {
172         logLocks.erase(iter);
173     }
174 }
175 
176 typedef STAFRefPtr<STAFCommandParser> STAFCommandParserPtr;
177 
178 struct LogServiceData
179 {
180     unsigned int fDebugMode;               // Not used, currently
181     STAFString fName;                      // Registered service name
182     STAFString fShortName;                 // Short service name
183     STAFString fResolveLogMaskString;      // String for resolve log mask
184     STAFString fResolveMessageString;      // String for resolve message var
185     STAFString fRoot;                      // Root of log directory
186     STAFString fRemoteLogServer;           // Name of remote log server
187     STAFString fRemoteLogService;          // Name of remote log service
188     STAFHandlePtr fHandle;                 // Log service's STAF handle
189     unsigned int fDefaultResolveMessage;   // Default for resolving messages
190     unsigned int fMaxRecordSize;           // Maximum log record size
191     unsigned int fDefaultMaxQueryRecords;  // Default maximum records to return
192                                            // on a generic QUERY request
193     unsigned int fUseResolveMessageVar;    // Honor S/S/Log/ResolveMessage
194     unsigned int fRLogMode;                // Are we in RLog mode?
195     STAFCommandParserPtr fParmsParser;
196     STAFCommandParserPtr fLogParser;
197     STAFCommandParserPtr fQueryParser;
198     STAFCommandParserPtr fListParser;
199     STAFCommandParserPtr fDeleteParser;
200     STAFCommandParserPtr fPurgeParser;
201     STAFCommandParserPtr fSetParser;
202     STAFString fDefaultAuthenticator;      // Default Authenticator
203     STAFString fLocalMachineName;
204 
205     // Map Class Definitions for marshalled results
206     STAFMapClassDefinitionPtr fLogRecordClass;
207     STAFMapClassDefinitionPtr fLogRecordLongClass;
208     STAFMapClassDefinitionPtr fQueryStatsClass;
209     STAFMapClassDefinitionPtr fPurgeStatsClass;
210     STAFMapClassDefinitionPtr fListLocalSettingsClass;
211     STAFMapClassDefinitionPtr fListRemoteSettingsClass;
212     STAFMapClassDefinitionPtr fListLogsClass;
213 };
214 
215 struct LogRecord
216 {
LogRecordLogRecord217     LogRecord() : recordFormatID(0), date(0), secondsPastMidnight(0),
218                   logLevel(0), handle(0), recordNumber(0)
219     { /* Do Nothing */ }
220 
LogRecordLogRecord221     LogRecord(unsigned int aDate, unsigned int seconds, unsigned int level,
222               const STAFString &aMachine, const STAFString &aHandleName,
223               STAFHandle_t aHandle, const STAFString(&aUser),
224               const STAFString(&aEndpoint), const STAFString &aMessage)
225         : recordFormatID(0), date(aDate), secondsPastMidnight(seconds),
226           logLevel(level), machine(aMachine), handleName(aHandleName),
227           handle(aHandle), user(aUser), endpoint(aEndpoint), message(aMessage),
228           recordNumber(0)
229     { /* Do Nothing */ }
230 
231     unsigned int recordFormatID;
232     unsigned int date;
233     unsigned int secondsPastMidnight;
234     unsigned int logLevel;
235     STAFString machine;
236     STAFString handleName;
237     STAFHandle_t handle;
238     STAFString user;
239     STAFString endpoint;
240     STAFString message;
241 
242     // Note: Record number is not stored in the logfile
243     unsigned int recordNumber;
244 };
245 
246 
247 typedef std::deque<STAFString> StringList;
248 typedef std::deque<STAFHandle_t> HandleList;
249 typedef struct
250 {
251     unsigned int date;
252     unsigned int seconds;
253 } LogTimestamp;
254 
255 struct LogRecordFilter
256 {
LogRecordFilterLogRecordFilter257     LogRecordFilter() : useLevelMask(false), useFrom(false), useAfter(false),
258                         useBefore(false), useTo(false)
259     { /* Do Nothing */ }
260 
261     StringList contains;
262     StringList cscontains;
263     StringList startswith;
264     StringList csstartswith;
265     StringList qMachines;
266     StringList names;
267     StringList users;
268     StringList endpoints;
269     HandleList qHandles;
270     bool useLevelMask;
271     unsigned int levelMask;
272     bool useFrom;
273     LogTimestamp fromTimestamp;
274     bool useAfter;
275     LogTimestamp afterTimestamp;
276     bool useBefore;
277     LogTimestamp beforeTimestamp;
278     bool useTo;
279     LogTimestamp toTimestamp;
280 };
281 
282 
283 enum ReadLogRecordRC
284 {
285     kReadLogOk = 0,
286     kReadLogEndOfFile = 1,
287     kReadLogInvalidFormat = 2
288 };
289 
290 struct LogStats
291 {
292     unsigned int fatal;
293     unsigned int error;
294     unsigned int warning;
295     unsigned int info;
296     unsigned int trace;
297     unsigned int trace2;
298     unsigned int trace3;
299     unsigned int debug;
300     unsigned int debug2;
301     unsigned int debug3;
302     unsigned int start;
303     unsigned int stop;
304     unsigned int pass;
305     unsigned int fail;
306     unsigned int status;
307     unsigned int user1;
308     unsigned int user2;
309     unsigned int user3;
310     unsigned int user4;
311     unsigned int user5;
312     unsigned int user6;
313     unsigned int user7;
314     unsigned int user8;
315 };
316 
317 // Some global variables
318 
319 static STAFString sHelpMsg;
320 static STAFString sLineSep;
321 static const STAFString sVersionInfo("3.4.2");
322 static const STAFString sZeroOne("01");
323 static const STAFString sOne("1");
324 static const STAFString sLogExt("log");
325 static const STAFString sTmpExt("tmp");
326 static const STAFString sLeftCurly(kUTF8_LCURLY);
327 static const STAFString sSpace(kUTF8_SPACE);
328 static const STAFString sEqual(kUTF8_EQUAL);
329 static const STAFString sSlash(kUTF8_SLASH);
330 static const STAFString sColon(kUTF8_COLON);
331 static const STAFString sSpecSeparator(sColon + sSlash + sSlash);
332 static const STAFString sTimestampSeps("-@");
333 static const STAFString sLocal("LOCAL");
334 static const STAFString sVar("VAR");
335 static const STAFString sResStrResolve("RESOLVE REQUEST ");
336 static const STAFString sString(" STRING ");
337 static const STAFString sTrust("TRUST");
338 static const STAFString sMisc("MISC");
339 static const STAFString sRESOLVE("RESOLVE");
340 static const STAFString sEverythingLogMask("11111111111111111111111111111111");
341 static const STAFString sOldSep(kUTF8_VBAR);
342 static const STAFString sEOLString("RESOLVE STRING {STAF/Config/Sep/Line}");
343 static const STAFString sResMachineString("RESOLVE STRING {STAF/Config/Machine}");
344 static const STAFString sDefAuthString(
345     "RESOLVE STRING {STAF/Config/DefaultAuthenticator}");
346 static const STAFString sListDots("........................................");
347 static const STAFString sSizeEquals("Size=");
348 static const STAFString sGetMachine("GET MACHINE ");
349 static const STAFString sGetUser(" USER ");
350 static const STAFString sMachine("MACHINE ");
351 static const STAFString sLOG("LOG");
352 static const STAFString sQUERY("QUERY");
353 static const STAFString sLIST("LIST");
354 static const STAFString sPURGE("PURGE");
355 static const STAFString sDELETE("DELETE");
356 static const STAFString sHELP("HELP");
357 static const STAFString sSET("SET");
358 static const STAFString sVERSION("VERSION");
359 static const STAFString sGLOBAL("GLOBAL");
360 static const STAFString sMACHINE("MACHINE");
361 static const STAFString sMACHINES("MACHINES");
362 static const STAFString sHANDLE("HANDLE");
363 static const STAFString sHANDLES("HANDLES");
364 static const STAFString sLOGNAME("LOGNAME");
365 static const STAFString sLEVEL("LEVEL");
366 static const STAFString sMESSAGE("MESSAGE");
367 static const STAFString sRESOLVEMESSAGE("RESOLVEMESSAGE");
368 static const STAFString sNORESOLVEMESSAGE("NORESOLVEMESSAGE");
369 static const STAFString sCONTAINS("CONTAINS");
370 static const STAFString sCSCONTAINS("CSCONTAINS");
371 static const STAFString sSTARTSWITH("STARTSWITH");
372 static const STAFString sCSSTARTSWITH("CSSTARTSWITH");
373 static const STAFString sQMACHINE("QMACHINE");
374 static const STAFString sQHANDLE("QHANDLE");
375 static const STAFString sNAME("NAME");
376 static const STAFString sUSER("USER");
377 static const STAFString sENDPOINT("ENDPOINT");
378 static const STAFString sLEVELMASK("LEVELMASK");
379 static const STAFString sFROM("FROM");
380 static const STAFString sAFTER("AFTER");
381 static const STAFString sFROMRECORD("FROMRECORD");
382 static const STAFString sTORECORD("TORECORD");
383 static const STAFString sBEFORE("BEFORE");
384 static const STAFString sTO("TO");
385 static const STAFString sLEVELBITSTRING("LEVELBITSTRING");
386 static const STAFString sFIRST("FIRST");
387 static const STAFString sLAST("LAST");
388 static const STAFString sALL("ALL");
389 static const STAFString sSTATS("STATS");
390 static const STAFString sTOTAL("TOTAL");
391 static const STAFString sLONG("LONG");
392 static const STAFString sCONFIRMALL("CONFIRMALL");
393 static const STAFString sDIRECTORY("DIRECTORY");
394 static const STAFString sRMTMACHINE("RMTMACHINE");
395 static const STAFString sRMTNICKNAME("RMTNICKNAME");
396 static const STAFString sRMTHANDLE("RMTHANDLE");
397 static const STAFString sRMTNAME("RMTNAME");
398 static const STAFString sRMTUSER("RMTUSER");
399 static const STAFString sRMTMACH("RMTMACH");
400 static const STAFString sMAXRECORDSIZE("MAXRECORDSIZE");
401 static const STAFString sDEFAULTMAXQUERYRECORDS("DEFAULTMAXQUERYRECORDS");
402 static const STAFString sENABLERESOLVEMESSAGEVAR("ENABLERESOLVEMESSAGEVAR");
403 static const STAFString sDISABLERESOLVEMESSAGEVAR("DISABLERESOLVEMESSAGEVAR");
404 static const STAFString sSETTINGS("SETTINGS");
405 static const STAFString sENABLEREMOTELOGGING("ENABLEREMOTELOGGING");
406 static const STAFString sREMOTELOGSERVER("REMOTELOGSERVER");
407 static const STAFString sREMOTELOGSERVICE("REMOTELOGSERVICE");
408 static const STAFString sTODAY("TODAY");
409 
410 static const STAFString sFATAL("FATAL");
411 static const STAFString sERROR("ERROR");
412 static const STAFString sWARNING("WARNING");
413 static const STAFString sINFO("INFO");
414 static const STAFString sTRACE("TRACE");
415 static const STAFString sTRACE2("TRACE2");
416 static const STAFString sTRACE3("TRACE3");
417 static const STAFString sDEBUG("DEBUG");
418 static const STAFString sDEBUG2("DEBUG2");
419 static const STAFString sDEBUG3("DEBUG3");
420 static const STAFString sSTART("START");
421 static const STAFString sSTOP("STOP");
422 static const STAFString sPASS("PASS");
423 static const STAFString sFAIL("FAIL");
424 static const STAFString sSTATUS("STATUS");
425 static const STAFString sUSER1("USER1");
426 static const STAFString sUSER2("USER2");
427 static const STAFString sUSER3("USER3");
428 static const STAFString sUSER4("USER4");
429 static const STAFString sUSER5("USER5");
430 static const STAFString sUSER6("USER6");
431 static const STAFString sUSER7("USER7");
432 static const STAFString sUSER8("USER8");
433 
434 static STAFString sFATALPretty("Fatal");
435 static STAFString sERRORPretty("Error");
436 static STAFString sWARNINGPretty("Warning");
437 static STAFString sINFOPretty("Info");
438 static STAFString sTRACEPretty("Trace");
439 static STAFString sTRACE2Pretty("Trace2");
440 static STAFString sTRACE3Pretty("Trace3");
441 static STAFString sDEBUGPretty("Debug");
442 static STAFString sDEBUG2Pretty("Debug2");
443 static STAFString sDEBUG3Pretty("Debug3");
444 static STAFString sSTARTPretty("Start");
445 static STAFString sSTOPPretty("Stop");
446 static STAFString sPASSPretty("Pass");
447 static STAFString sFAILPretty("Fail");
448 static STAFString sSTATUSPretty("Status");
449 static STAFString sUSER1Pretty("User1");
450 static STAFString sUSER2Pretty("User2");
451 static STAFString sUSER3Pretty("User3");
452 static STAFString sUSER4Pretty("User4");
453 static STAFString sUSER5Pretty("User5");
454 static STAFString sUSER6Pretty("User6");
455 static STAFString sUSER7Pretty("User7");
456 static STAFString sUSER8Pretty("User8");
457 static STAFString sUNKNOWNPretty("Unknown");
458 
459 static STAFString sFATALBits  ("00000000000000000000000000000001");
460 static STAFString sERRORBits  ("00000000000000000000000000000010");
461 static STAFString sWARNINGBits("00000000000000000000000000000100");
462 static STAFString sINFOBits   ("00000000000000000000000000001000");
463 static STAFString sTRACEBits  ("00000000000000000000000000010000");
464 static STAFString sTRACE2Bits ("00000000000000000000000000100000");
465 static STAFString sTRACE3Bits ("00000000000000000000000001000000");
466 static STAFString sDEBUGBits  ("00000000000000000000000010000000");
467 static STAFString sDEBUG2Bits ("00000000000000000000000100000000");
468 static STAFString sDEBUG3Bits ("00000000000000000000001000000000");
469 static STAFString sSTARTBits  ("00000000000000000000010000000000");
470 static STAFString sSTOPBits   ("00000000000000000000100000000000");
471 static STAFString sPASSBits   ("00000000000000000001000000000000");
472 static STAFString sFAILBits   ("00000000000000000010000000000000");
473 static STAFString sSTATUSBits ("00000000000000000100000000000000");
474 static STAFString sUSER1Bits  ("00000001000000000000000000000000");
475 static STAFString sUSER2Bits  ("00000010000000000000000000000000");
476 static STAFString sUSER3Bits  ("00000100000000000000000000000000");
477 static STAFString sUSER4Bits  ("00001000000000000000000000000000");
478 static STAFString sUSER5Bits  ("00010000000000000000000000000000");
479 static STAFString sUSER6Bits  ("00100000000000000000000000000000");
480 static STAFString sUSER7Bits  ("01000000000000000000000000000000");
481 static STAFString sUSER8Bits  ("10000000000000000000000000000000");
482 static STAFString sUNKNOWNBits("00000000000000000000000000000000");
483 
484 static const STAFString sUnauthenticatedUser = "none" +
485     sSpecSeparator + "anonymous";
486 
487 static const unsigned int sCurrRecordFormatID = 4;
488 
489 
490 // Prototypes
491 
492 static STAFResultPtr handleLog(STAFServiceRequestLevel30 *, LogServiceData *);
493 static STAFResultPtr handleQuery(STAFServiceRequestLevel30 *, LogServiceData *);
494 static STAFResultPtr handlePurge(STAFServiceRequestLevel30 *, LogServiceData *);
495 static STAFResultPtr handleList(STAFServiceRequestLevel30 *, LogServiceData *);
496 static STAFResultPtr handleDelete(STAFServiceRequestLevel30 *, LogServiceData *);
497 static STAFResultPtr handleSet(STAFServiceRequestLevel30 *, LogServiceData *);
498 static STAFResultPtr handleHelp(STAFServiceRequestLevel30 *, LogServiceData *);
499 static STAFResultPtr handleRemoteLog(STAFServiceRequestLevel30 *,
500                                      LogServiceData *);
501 static STAFResultPtr handleRemoteLogGeneral(STAFServiceRequestLevel30 *,
502                                             LogServiceData *);
503 
504 static bool isValidLogLevel(const STAFString &levelString,
505                             unsigned int &outputLevel);
506 
507 static bool convertLogLevelToUInt(const STAFString &levelString,
508                                   unsigned int &outputLevel);
509 
510 static STAFString &convertLogLevelToString(unsigned int logLevel,
511                                            bool levelAsBits = false);
512 
513 static bool convertLogMaskToUInt(const STAFString &logmaskString,
514                                  unsigned int &logMask);
515 
516 void readUIntFromFile(istream &input, unsigned int &data,
517                      unsigned int length = 4);
518 
519 void writeUIntToFile(ostream &output, unsigned int data,
520                      unsigned int length = 4);
521 
522 void readStringFromFile(istream &input, STAFString &inString);
523 
524 void writeStringToFile(ostream &output, const STAFString &outString);
525 
526 STAFResultPtr resolveStr(STAFServiceRequestLevel30 *pInfo, LogServiceData *pData,
527                          const STAFString &theString);
528 
529 STAFResultPtr resolveOp(STAFServiceRequestLevel30 *pInfo, LogServiceData *pData,
530                         STAFCommandParseResultPtr &parsedResult,
531                         const STAFString &fOption,
532                         unsigned int optionIndex = 1);
533 
534 STAFResultPtr resolveOpLocal(LogServiceData *pData,
535                              STAFCommandParseResultPtr &parsedResult,
536                              const STAFString &fOption,
537                              unsigned int optionIndex = 1);
538 
539 static STAFResultPtr convertStringToUInt(
540     const STAFString &theString,
541     unsigned int &number,
542     const unsigned int minValue = 0,
543     const unsigned int maxValue = UINT_MAX);
544 
545 static STAFResultPtr convertOptionStringToUInt(
546     const STAFString &theString,
547     const STAFString &optionName,
548     unsigned int &number,
549     const unsigned int minValue = 0,
550     const unsigned int maxValue = UINT_MAX);
551 
552 bool generateQueryPurgeDeleteLogFilePath(STAFFSPath &logfilePath,
553      STAFResultPtr &errorResult, STAFServiceRequestLevel30 *pInfo,
554      LogServiceData *pData, STAFCommandParseResultPtr &parsedResult);
555 
556 bool updateQueryPurgeLogFilter(LogRecordFilter &logFilter,
557      STAFResultPtr &errorResult, STAFServiceRequestLevel30 *pInfo,
558      LogServiceData *pData, STAFCommandParseResultPtr &parsedResult);
559 
560 unsigned int readLogRecordFromFile(istream &input, LogRecord &logRecord,
561                                    unsigned int recordNumber);
562 
563 void writeLogRecordToFile(ostream &output, LogRecord &logRecord);
564 
565 void addLogRecordToList(STAFObjectPtr &logList,
566                         STAFMapClassDefinitionPtr &logRecordClass,
567                         const LogRecord &logRecord, bool levelAsBits,
568                         bool longFormat);
569 
570 void printLogRecord(const LogRecord &logRecord);
571 
572 bool logRecordMatchesFilter(const LogRecord &logRecord,
573                             const LogRecordFilter &logFilter,
574                             const STAFString &defaultAuthenticator);
575 
576 void updateLogStats(LogStats &logStats, unsigned int logLevel);
577 
578 void addLogStatsToMap(STAFObjectPtr &queryStatsMap, const LogStats &logStats);
579 
580 static void registerHelpData(LogServiceData *pData, unsigned int errorNumber,
581                              const STAFString &shortInfo,
582                              const STAFString &longInfo);
583 
584 static void unregisterHelpData(LogServiceData *pData, unsigned int errorNumber);
585 
586 
587 // Begin implementation
588 
STAFServiceGetLevelBounds(unsigned int levelID,unsigned int * minimum,unsigned int * maximum)589 STAFRC_t STAFServiceGetLevelBounds(unsigned int levelID,
590                                    unsigned int *minimum,
591                                    unsigned int *maximum)
592 {
593     switch (levelID)
594     {
595         case kServiceInfo:
596         {
597             *minimum = 30;
598             *maximum = 30;
599             break;
600         }
601         case kServiceInit:
602         {
603             *minimum = 30;
604             *maximum = 30;
605             break;
606         }
607         case kServiceAcceptRequest:
608         {
609             *minimum = 30;
610             *maximum = 30;
611             break;
612         }
613         case kServiceTerm:
614         case kServiceDestruct:
615         {
616             *minimum = 0;
617             *maximum = 0;
618             break;
619         }
620         default:
621         {
622             return kSTAFInvalidAPILevel;
623         }
624     }
625 
626     return kSTAFOk;
627 }
628 
629 
STAFServiceConstruct(STAFServiceHandle_t * pServiceHandle,void * pServiceInfo,unsigned int infoLevel,STAFString_t * pErrorBuffer)630 STAFRC_t STAFServiceConstruct(STAFServiceHandle_t *pServiceHandle,
631                               void *pServiceInfo, unsigned int infoLevel,
632                               STAFString_t *pErrorBuffer)
633 {
634     STAFRC_t rc = kSTAFUnknownError;
635 
636     try
637     {
638         if (infoLevel != 30) return kSTAFInvalidAPILevel;
639 
640         STAFServiceInfoLevel30 *pInfo =
641             reinterpret_cast<STAFServiceInfoLevel30 *>(pServiceInfo);
642         LogServiceData data;
643 
644         data.fDebugMode = 0;
645         data.fRLogMode = 0;
646         data.fMaxRecordSize = 100000;
647         data.fDefaultMaxQueryRecords = 100;
648         data.fDefaultResolveMessage = 0;
649         data.fUseResolveMessageVar = 0;
650         data.fRemoteLogService = sLOG;
651         data.fShortName = STAFString(pInfo->name).toUpperCase();
652         data.fName = "STAF/Service/";
653         data.fName += pInfo->name;
654         data.fResolveLogMaskString = sLeftCurly + data.fName + "/Mask}";
655         data.fResolveMessageString = sLeftCurly + data.fName +
656                                      "/ResolveMessage}";
657 
658         // Walk through and verify the config options
659         // Note: The log service does not currently have any options
660 
661         for (unsigned int i = 0; i < pInfo->numOptions; ++i)
662         {
663             STAFString optionError("Invalid option, ");
664             optionError += pInfo->pOptionName[i];
665             *pErrorBuffer = optionError.adoptImpl();
666             return kSTAFServiceConfigurationError;
667         }
668 
669         // Setup parsers
670 
671         // PARMS parser
672 
673         data.fParmsParser = STAFCommandParserPtr(new STAFCommandParser,
674                                                  STAFCommandParserPtr::INIT);
675         data.fParmsParser->addOption(
676             "DIRECTORY",        1, STAFCommandParser::kValueRequired);
677         data.fParmsParser->addOption(
678             "ENABLEREMOTELOGGING", 1, STAFCommandParser::kValueNotAllowed);
679         data.fParmsParser->addOption(
680             "REMOTELOGSERVER",  1, STAFCommandParser::kValueRequired);
681         data.fParmsParser->addOption(
682             "REMOTELOGSERVICE", 1, STAFCommandParser::kValueRequired);
683         data.fParmsParser->addOption(
684             "MAXRECORDSIZE",    1, STAFCommandParser::kValueRequired);
685         data.fParmsParser->addOption(
686             "DEFAULTMAXQUERYRECORDS", 1, STAFCommandParser::kValueRequired);
687         data.fParmsParser->addOption(
688             "RESOLVEMESSAGE",   1, STAFCommandParser::kValueNotAllowed);
689         data.fParmsParser->addOption(
690             "NORESOLVEMESSAGE", 1, STAFCommandParser::kValueNotAllowed);
691         data.fParmsParser->addOption(
692             "ENABLERESOLVEMESSAGEVAR",  1, STAFCommandParser::kValueNotAllowed);
693         data.fParmsParser->addOption(
694             "DISABLERESOLVEMESSAGEVAR", 1, STAFCommandParser::kValueNotAllowed);
695 
696         data.fParmsParser->addOptionGroup(
697             "NORESOLVEMESSAGE RESOLVEMESSAGE", 0, 1);
698         data.fParmsParser->addOptionGroup(
699             "ENABLERESOLVEMESSAGEVAR " "DISABLERESOLVEMESSAGEVAR", 0, 1);
700         data.fParmsParser->addOptionGroup(
701             "ENABLEREMOTELOGGING DIRECTORY", 0, 1);
702         data.fParmsParser->addOptionGroup(
703             "ENABLEREMOTELOGGING MAXRECORDSIZE", 0, 1);
704         data.fParmsParser->addOptionGroup(
705             "ENABLEREMOTELOGGING DEFAULTMAXQUERYRECORDS", 0, 1);
706         data.fParmsParser->addOptionGroup(
707             "ENABLEREMOTELOGGING RESOLVEMESSAGE", 0, 1);
708         data.fParmsParser->addOptionGroup(
709             "ENABLEREMOTELOGGING NORESOLVEMESSAGE", 0, 1);
710         data.fParmsParser->addOptionGroup(
711             "ENABLEREMOTELOGGING ENABLERESOLVEMESSAGEVAR", 0, 1);
712         data.fParmsParser->addOptionGroup(
713             "ENABLEREMOTELOGGING DISABLERESOLVEMESSAGEVAR", 0, 1);
714 
715         data.fParmsParser->addOptionNeed("REMOTELOGSERVER REMOTELOGSERVICE",
716                                          "ENABLEREMOTELOGGING");
717         data.fParmsParser->addOptionNeed("ENABLEREMOTELOGGING",
718                                          "REMOTELOGSERVER");
719 
720         // LOG parser
721 
722         data.fLogParser = STAFCommandParserPtr(new STAFCommandParser,
723                                                STAFCommandParserPtr::INIT);
724         data.fLogParser->addOption(
725             "LOG",              1, STAFCommandParser::kValueNotAllowed);
726         data.fLogParser->addOption(
727             "GLOBAL",           1, STAFCommandParser::kValueNotAllowed);
728         data.fLogParser->addOption(
729             "MACHINE",          1, STAFCommandParser::kValueNotAllowed);
730         data.fLogParser->addOption(
731             "HANDLE",           1, STAFCommandParser::kValueNotAllowed);
732         data.fLogParser->addOption(
733             "LOGTYPE",          1, STAFCommandParser::kValueRequired);
734         data.fLogParser->addOption(
735             "LOGNAME",          1, STAFCommandParser::kValueRequired);
736         data.fLogParser->addOption(
737             "LEVEL",            1, STAFCommandParser::kValueRequired);
738         data.fLogParser->addOption(
739             "MESSAGE",          1, STAFCommandParser::kValueRequired);
740         data.fLogParser->addOption(
741             "RESOLVEMESSAGE",   1, STAFCommandParser::kValueNotAllowed);
742         data.fLogParser->addOption(
743             "NORESOLVEMESSAGE", 1, STAFCommandParser::kValueNotAllowed);
744         data.fLogParser->addOption(
745             "RMTMACHINE",       1, STAFCommandParser::kValueRequired);
746         data.fLogParser->addOption(
747             "RMTNICKNAME",      1, STAFCommandParser::kValueRequired);
748         data.fLogParser->addOption(
749             "RMTNAME",          1, STAFCommandParser::kValueRequired);
750         data.fLogParser->addOption(
751             "RMTHANDLE",        1, STAFCommandParser::kValueRequired);
752         data.fLogParser->addOption(
753             "RMTUSER",          1, STAFCommandParser::kValueRequired);
754         data.fLogParser->addOption(
755             "RMTMACH",          1, STAFCommandParser::kValueRequired);
756 
757         data.fLogParser->addOptionGroup("LOG", 1, 1);
758         data.fLogParser->addOptionGroup("LEVEL", 1, 1);
759         data.fLogParser->addOptionGroup("MESSAGE", 1, 1);
760         data.fLogParser->addOptionGroup("GLOBAL MACHINE HANDLE LOGTYPE", 1, 1);
761         data.fLogParser->addOptionGroup("LOGNAME", 1, 1);
762         data.fLogParser->addOptionGroup("RESOLVEMESSAGE NORESOLVEMESSAGE",
763                                         0, 1);
764 
765         data.fLogParser->addOptionNeed("RMTMACHINE", "RMTUSER");
766         data.fLogParser->addOptionNeed(
767             "RMTNAME RMTHANDLE RMTUSER RMTMACH RMTNICKNAME", "RMTMACHINE");
768 
769         // QUERY parser
770 
771         data.fQueryParser = STAFCommandParserPtr(new STAFCommandParser,
772                                                  STAFCommandParserPtr::INIT);
773         data.fQueryParser->addOption(
774             "QUERY",            1, STAFCommandParser::kValueNotAllowed);
775         data.fQueryParser->addOption(
776             "GLOBAL",           1, STAFCommandParser::kValueNotAllowed);
777         data.fQueryParser->addOption(
778             "MACHINE",          1, STAFCommandParser::kValueRequired);
779         data.fQueryParser->addOption(
780             "HANDLE",           1, STAFCommandParser::kValueRequired);
781         data.fQueryParser->addOption(
782             "LOGNAME",          1, STAFCommandParser::kValueRequired);
783         data.fQueryParser->addOption(
784             "LEVELMASK",        1, STAFCommandParser::kValueRequired);
785         data.fQueryParser->addOption(
786             "QMACHINE",         0, STAFCommandParser::kValueRequired);
787         data.fQueryParser->addOption(
788             "QHANDLE",          0, STAFCommandParser::kValueRequired);
789         data.fQueryParser->addOption(
790             "NAME",             0, STAFCommandParser::kValueRequired);
791         data.fQueryParser->addOption(
792             "USER",             0, STAFCommandParser::kValueRequired);
793         data.fQueryParser->addOption(
794             "ENDPOINT",         0, STAFCommandParser::kValueRequired);
795         data.fQueryParser->addOption(
796             "FIRST",            1, STAFCommandParser::kValueRequired);
797         data.fQueryParser->addOption(
798             "LAST",             1, STAFCommandParser::kValueRequired);
799         data.fQueryParser->addOption(
800             "ALL",              1, STAFCommandParser::kValueNotAllowed);
801         data.fQueryParser->addOption(
802             "TOTAL",            1, STAFCommandParser::kValueNotAllowed);
803         data.fQueryParser->addOption(
804             "STATS",            1, STAFCommandParser::kValueNotAllowed);
805         data.fQueryParser->addOption(
806             "LONG",            1, STAFCommandParser::kValueNotAllowed);
807         data.fQueryParser->addOption(
808             "CONTAINS",         0, STAFCommandParser::kValueRequired);
809         data.fQueryParser->addOption(
810             "CSCONTAINS",       0, STAFCommandParser::kValueRequired);
811         data.fQueryParser->addOption(
812             "STARTSWITH",       0, STAFCommandParser::kValueRequired);
813         data.fQueryParser->addOption(
814             "CSSTARTSWITH",     0, STAFCommandParser::kValueRequired);
815         data.fQueryParser->addOption(
816             "LEVELBITSTRING",   1, STAFCommandParser::kValueNotAllowed);
817         data.fQueryParser->addOption(
818             "FROM",             1, STAFCommandParser::kValueRequired);
819         data.fQueryParser->addOption(
820             "AFTER",            1, STAFCommandParser::kValueRequired);
821         data.fQueryParser->addOption(
822             "BEFORE",           1, STAFCommandParser::kValueRequired);
823         data.fQueryParser->addOption(
824             "TO",               1, STAFCommandParser::kValueRequired);
825         data.fQueryParser->addOption(
826             "FROMRECORD",       1, STAFCommandParser::kValueRequired);
827         data.fQueryParser->addOption(
828             "TORECORD",         1, STAFCommandParser::kValueRequired);
829         data.fQueryParser->addOption(
830             "RMTMACHINE",       1, STAFCommandParser::kValueRequired);
831         data.fQueryParser->addOption(
832             "RMTUSER",          1, STAFCommandParser::kValueRequired);
833 
834         data.fQueryParser->addOptionGroup("QUERY", 1, 1);
835         data.fQueryParser->addOptionGroup("GLOBAL MACHINE", 1, 1);
836         data.fQueryParser->addOptionGroup("LOGNAME", 1, 1);
837         data.fQueryParser->addOptionGroup("FROM AFTER", 0, 1);
838         data.fQueryParser->addOptionGroup("BEFORE TO", 0, 1);
839         data.fQueryParser->addOptionGroup("FIRST LAST ALL", 0, 1);
840         data.fQueryParser->addOptionGroup("TOTAL STATS LONG", 0, 1);
841 
842         data.fQueryParser->addOptionNeed("HANDLE", "MACHINE");
843         data.fQueryParser->addOptionNeed("RMTMACHINE", "RMTUSER");
844         data.fQueryParser->addOptionNeed("RMTUSER", "RMTMACHINE");
845 
846         // PURGE parser
847 
848         data.fPurgeParser = STAFCommandParserPtr(new STAFCommandParser,
849                                                  STAFCommandParserPtr::INIT);
850         data.fPurgeParser->addOption(
851             "PURGE",            1, STAFCommandParser::kValueNotAllowed);
852         data.fPurgeParser->addOption(
853             "GLOBAL",           1, STAFCommandParser::kValueNotAllowed);
854         data.fPurgeParser->addOption(
855             "MACHINE",          1, STAFCommandParser::kValueRequired);
856         data.fPurgeParser->addOption(
857             "HANDLE",           1, STAFCommandParser::kValueRequired);
858         data.fPurgeParser->addOption(
859             "LOGNAME",          1, STAFCommandParser::kValueRequired);
860         data.fPurgeParser->addOption(
861             "LEVELMASK",        1, STAFCommandParser::kValueRequired);
862         data.fPurgeParser->addOption(
863             "QMACHINE",         0, STAFCommandParser::kValueRequired);
864         data.fPurgeParser->addOption(
865             "QHANDLE",          0, STAFCommandParser::kValueRequired);
866         data.fPurgeParser->addOption(
867             "NAME",             0, STAFCommandParser::kValueRequired);
868         data.fPurgeParser->addOption(
869             "USER",             0, STAFCommandParser::kValueRequired);
870         data.fPurgeParser->addOption(
871             "ENDPOINT",         0, STAFCommandParser::kValueRequired);
872         data.fPurgeParser->addOption(
873             "FIRST",            1, STAFCommandParser::kValueRequired);
874         data.fPurgeParser->addOption(
875             "LAST",             1, STAFCommandParser::kValueRequired);
876         data.fPurgeParser->addOption(
877             "CONTAINS",         0, STAFCommandParser::kValueRequired);
878         data.fPurgeParser->addOption(
879             "CSCONTAINS",       0, STAFCommandParser::kValueRequired);
880         data.fPurgeParser->addOption(
881             "STARTSWITH",       0, STAFCommandParser::kValueRequired);
882         data.fPurgeParser->addOption(
883             "CSSTARTSWITH",     0, STAFCommandParser::kValueRequired);
884         data.fPurgeParser->addOption(
885             "FROM",             1, STAFCommandParser::kValueRequired);
886         data.fPurgeParser->addOption(
887             "AFTER",            1, STAFCommandParser::kValueRequired);
888         data.fPurgeParser->addOption(
889             "BEFORE",           1, STAFCommandParser::kValueRequired);
890         data.fPurgeParser->addOption(
891             "TO",               1, STAFCommandParser::kValueRequired);
892         data.fPurgeParser->addOption(
893             "FROMRECORD",       1, STAFCommandParser::kValueRequired);
894         data.fPurgeParser->addOption(
895             "TORECORD",         1, STAFCommandParser::kValueRequired);
896         data.fPurgeParser->addOption(
897             "RMTMACHINE",       1, STAFCommandParser::kValueRequired);
898         data.fPurgeParser->addOption(
899             "RMTUSER",          1, STAFCommandParser::kValueRequired);
900         data.fPurgeParser->addOption(
901             "CONFIRM",          1, STAFCommandParser::kValueNotAllowed);
902         data.fPurgeParser->addOption(
903             "CONFIRMALL",       1, STAFCommandParser::kValueNotAllowed);
904 
905         data.fPurgeParser->addOptionGroup("PURGE", 1, 1);
906         data.fPurgeParser->addOptionGroup("GLOBAL MACHINE", 1, 1);
907         data.fPurgeParser->addOptionGroup("LOGNAME", 1, 1);
908         data.fPurgeParser->addOptionGroup("CONFIRM CONFIRMALL", 1, 1);
909         data.fPurgeParser->addOptionGroup("FROM AFTER", 0, 1);
910         data.fPurgeParser->addOptionGroup("BEFORE TO", 0, 1);
911         data.fPurgeParser->addOptionGroup("FIRST LAST", 0, 1);
912 
913         data.fPurgeParser->addOptionNeed("HANDLE", "MACHINE");
914         data.fPurgeParser->addOptionNeed("RMTMACHINE", "RMTUSER");
915         data.fPurgeParser->addOptionNeed("RMTUSER", "RMTMACHINE");
916 
917         // LIST parser
918 
919         data.fListParser = STAFCommandParserPtr(new STAFCommandParser,
920                                                 STAFCommandParserPtr::INIT);
921         data.fListParser->addOption(
922             "LIST",             1, STAFCommandParser::kValueNotAllowed);
923         data.fListParser->addOption(
924             "GLOBAL",           1, STAFCommandParser::kValueNotAllowed);
925         data.fListParser->addOption(
926             "MACHINES",         1, STAFCommandParser::kValueNotAllowed);
927         data.fListParser->addOption(
928             "MACHINE",          1, STAFCommandParser::kValueRequired);
929         data.fListParser->addOption(
930             "HANDLES",          1, STAFCommandParser::kValueNotAllowed);
931         data.fListParser->addOption(
932             "HANDLE",           1, STAFCommandParser::kValueRequired);
933         data.fListParser->addOption(
934             "RMTMACHINE",       1, STAFCommandParser::kValueRequired);
935         data.fListParser->addOption(
936             "RMTUSER",          1, STAFCommandParser::kValueRequired);
937         data.fListParser->addOption(
938             "SETTINGS",         1, STAFCommandParser::kValueNotAllowed);
939 
940         data.fListParser->addOptionGroup("LIST", 1, 1);
941         data.fListParser->addOptionGroup("GLOBAL MACHINES MACHINE SETTINGS",
942                                          1, 1);
943         data.fListParser->addOptionGroup("HANDLES HANDLE", 0, 1);
944 
945         data.fListParser->addOptionNeed("HANDLES HANDLE", "MACHINE");
946         data.fListParser->addOptionNeed("RMTMACHINE", "RMTUSER");
947         data.fListParser->addOptionNeed("RMTUSER", "RMTMACHINE");
948 
949 
950         // DELETE parser
951 
952         data.fDeleteParser = STAFCommandParserPtr(new STAFCommandParser,
953                                                   STAFCommandParserPtr::INIT);
954         data.fDeleteParser->addOption(
955             "DELETE",           1, STAFCommandParser::kValueNotAllowed);
956         data.fDeleteParser->addOption(
957             "GLOBAL",           1, STAFCommandParser::kValueNotAllowed);
958         data.fDeleteParser->addOption(
959             "MACHINE",          1, STAFCommandParser::kValueRequired);
960         data.fDeleteParser->addOption(
961             "HANDLE",           1, STAFCommandParser::kValueRequired);
962         data.fDeleteParser->addOption(
963             "LOGNAME",          1, STAFCommandParser::kValueRequired);
964         data.fDeleteParser->addOption(
965             "CONFIRM",          1, STAFCommandParser::kValueNotAllowed);
966         data.fDeleteParser->addOption(
967             "RMTMACHINE",       1, STAFCommandParser::kValueRequired);
968         data.fDeleteParser->addOption(
969             "RMTUSER",          1, STAFCommandParser::kValueRequired);
970 
971         data.fDeleteParser->addOptionGroup("DELETE", 1, 1);
972         data.fDeleteParser->addOptionGroup("GLOBAL MACHINE", 1, 1);
973         data.fDeleteParser->addOptionGroup("LOGNAME", 1, 1);
974         data.fDeleteParser->addOptionGroup("CONFIRM", 1, 1);
975 
976         data.fDeleteParser->addOptionNeed("HANDLE", "MACHINE");
977         data.fDeleteParser->addOptionNeed("RMTMACHINE", "RMTUSER");
978         data.fDeleteParser->addOptionNeed("RMTUSER", "RMTMACHINE");
979 
980         // SET parser
981 
982         data.fSetParser = STAFCommandParserPtr(new STAFCommandParser,
983                                                STAFCommandParserPtr::INIT);
984         data.fSetParser->addOption(
985             "SET",              1, STAFCommandParser::kValueNotAllowed);
986         data.fSetParser->addOption(
987             "MAXRECORDSIZE",    1, STAFCommandParser::kValueRequired);
988         data.fSetParser->addOption(
989             "DEFAULTMAXQUERYRECORDS", 1, STAFCommandParser::kValueRequired);
990         data.fSetParser->addOption(
991             "NORESOLVEMESSAGE", 1, STAFCommandParser::kValueNotAllowed);
992         data.fSetParser->addOption(
993             "RESOLVEMESSAGE",   1, STAFCommandParser::kValueNotAllowed);
994         data.fSetParser->addOption(
995             "ENABLERESOLVEMESSAGEVAR",  1, STAFCommandParser::kValueNotAllowed);
996         data.fSetParser->addOption(
997             "DISABLERESOLVEMESSAGEVAR", 1, STAFCommandParser::kValueNotAllowed);
998 
999         data.fSetParser->addOptionGroup("NORESOLVEMESSAGE RESOLVEMESSAGE",
1000                                         0, 1);
1001         data.fSetParser->addOptionGroup("ENABLERESOLVEMESSAGEVAR "
1002                                         "DISABLERESOLVEMESSAGEVAR",
1003                                         0, 1);
1004 
1005         // Construct the map class for the marshalled QUERY log-record output
1006 
1007         data.fLogRecordClass = STAFMapClassDefinition::create(
1008             "STAF/Service/Log/LogRecord");
1009 
1010         data.fLogRecordClass->addKey("timestamp",  "Date-Time");
1011         data.fLogRecordClass->addKey("level",      "Level");
1012         data.fLogRecordClass->addKey("message",    "Message");
1013 
1014         // Construct the map class for the marshalled QUERY LONG log-record
1015         // output
1016 
1017         data.fLogRecordLongClass = STAFMapClassDefinition::create(
1018             "STAF/Service/Log/LogRecordLong");
1019 
1020         data.fLogRecordLongClass->addKey("recordNumber", "Record #");
1021         data.fLogRecordLongClass->setKeyProperty(
1022             "recordNumber", "display-short-name", "R#");
1023         data.fLogRecordLongClass->addKey("timestamp",  "Date-Time");
1024         data.fLogRecordLongClass->addKey("machine",    "Machine");
1025         data.fLogRecordLongClass->addKey("handle",     "Handle");
1026         data.fLogRecordLongClass->setKeyProperty(
1027             "handle", "display-short-name", "H#");
1028         data.fLogRecordLongClass->addKey("handleName", "Handle Name");
1029         data.fLogRecordLongClass->setKeyProperty(
1030             "handleName", "display-short-name", "Name");
1031         data.fLogRecordLongClass->addKey("user",       "User");
1032         data.fLogRecordLongClass->addKey("endpoint",   "Endpoint");
1033         data.fLogRecordLongClass->addKey("level",      "Level");
1034         data.fLogRecordLongClass->addKey("message",    "Message");
1035 
1036         // Construct the map class for the marshalled QUERY STATS output
1037 
1038         data.fQueryStatsClass = STAFMapClassDefinition::create(
1039             "STAF/Service/Log/QueryStats");
1040 
1041         data.fQueryStatsClass->addKey("fatal",   sFATALPretty);
1042         data.fQueryStatsClass->addKey("error",   sERRORPretty);
1043         data.fQueryStatsClass->addKey("warning", sWARNINGPretty);
1044         data.fQueryStatsClass->addKey("info",    sINFOPretty);
1045         data.fQueryStatsClass->addKey("trace",   sTRACEPretty);
1046         data.fQueryStatsClass->addKey("trace2",  sTRACE2Pretty);
1047         data.fQueryStatsClass->addKey("trace3",  sTRACE3Pretty);
1048         data.fQueryStatsClass->addKey("debug",   sDEBUGPretty);
1049         data.fQueryStatsClass->addKey("debug2",  sDEBUG2Pretty);
1050         data.fQueryStatsClass->addKey("debug3",  sDEBUG3Pretty);
1051         data.fQueryStatsClass->addKey("start",   sSTARTPretty);
1052         data.fQueryStatsClass->addKey("stop",    sSTOPPretty);
1053         data.fQueryStatsClass->addKey("pass",    sPASSPretty);
1054         data.fQueryStatsClass->addKey("fail",    sFAILPretty);
1055         data.fQueryStatsClass->addKey("status",  sSTATUSPretty);
1056         data.fQueryStatsClass->addKey("user1",   sUSER1Pretty);
1057         data.fQueryStatsClass->addKey("user2",   sUSER2Pretty);
1058         data.fQueryStatsClass->addKey("user3",   sUSER3Pretty);
1059         data.fQueryStatsClass->addKey("user4",   sUSER4Pretty);
1060         data.fQueryStatsClass->addKey("user5",   sUSER5Pretty);
1061         data.fQueryStatsClass->addKey("user6",   sUSER6Pretty);
1062         data.fQueryStatsClass->addKey("user7",   sUSER7Pretty);
1063         data.fQueryStatsClass->addKey("user8",   sUSER8Pretty);
1064 
1065         // Construct the map class for the marshalled PURGE request output
1066 
1067         data.fPurgeStatsClass = STAFMapClassDefinition::create(
1068             "STAF/Service/Log/PurgeStats");
1069 
1070         data.fPurgeStatsClass->addKey("purgedRecords", "Purged Records");
1071         data.fPurgeStatsClass->addKey("totalRecords",  "Total Records");
1072 
1073         // Construct the map class for the marshalled LIST SETTINGS output
1074         // for local logging
1075 
1076         data.fListLocalSettingsClass = STAFMapClassDefinition::create(
1077             "STAF/Service/Log/LocalSettings");
1078 
1079         data.fListLocalSettingsClass->addKey("loggingMode", "Logging Mode");
1080         data.fListLocalSettingsClass->addKey("directory",   "Directory");
1081         data.fListLocalSettingsClass->addKey("maxRecordSize",
1082                                              "Max Record Size");
1083         data.fListLocalSettingsClass->addKey("defaultMaxQueryRecords",
1084                                              "Default Max Query Records");
1085         data.fListLocalSettingsClass->addKey("resolveMessage",
1086                                              "Resolve Message");
1087         data.fListLocalSettingsClass->addKey("resolveMessageVar",
1088                                              "Resolve Message Var");
1089 
1090         // Construct the map class for the marshalled LIST SETTINGS output
1091         // for remote logging
1092 
1093         data.fListRemoteSettingsClass = STAFMapClassDefinition::create(
1094             "STAF/Service/Log/RemoteSettings");
1095 
1096         data.fListRemoteSettingsClass->addKey("loggingMode", "Logging Mode");
1097         data.fListRemoteSettingsClass->addKey("remoteLogServer",
1098                                               "Remote Log Server");
1099         data.fListRemoteSettingsClass->addKey("remoteLogService",
1100                                               "Remote Log Service");
1101 
1102         // Construct map class for marshalled LIST logs/machines/handles output
1103 
1104         data.fListLogsClass = STAFMapClassDefinition::create(
1105             "STAF/Service/Log/ListLogs");
1106 
1107         data.fListLogsClass->addKey("logName",   "Log Name");
1108         data.fListLogsClass->addKey("timestamp", "Date-Time");
1109         data.fListLogsClass->addKey("upperSize", "U-Size");
1110         data.fListLogsClass->addKey("size",      "L-Size");
1111 
1112         // Set service handle
1113 
1114         *pServiceHandle = new LogServiceData(data);
1115 
1116         return kSTAFOk;
1117     }
1118     catch (STAFException &e)
1119     { *pErrorBuffer = getExceptionString(e,
1120                       "STAFLogService.cpp: STAFServiceConstruct").adoptImpl();
1121     }
1122     catch (...)
1123     {
1124         STAFString error("STAFLogService.cpp: STAFServiceConstruct: "
1125                          "Caught unknown exception");
1126         *pErrorBuffer = error.adoptImpl();
1127     }
1128 
1129     return kSTAFUnknownError;
1130 }
1131 
1132 
STAFServiceInit(STAFServiceHandle_t serviceHandle,void * pInitInfo,unsigned int initLevel,STAFString_t * pErrorBuffer)1133 STAFRC_t STAFServiceInit(STAFServiceHandle_t serviceHandle,
1134                          void *pInitInfo, unsigned int initLevel,
1135                          STAFString_t *pErrorBuffer)
1136 {
1137     STAFRC_t retCode = kSTAFUnknownError;
1138 
1139     try
1140     {
1141         if (initLevel != 30) return kSTAFInvalidAPILevel;
1142 
1143         LogServiceData *pData =
1144             reinterpret_cast<LogServiceData *>(serviceHandle);
1145 
1146         STAFServiceInitLevel30 *pInfo =
1147             reinterpret_cast<STAFServiceInitLevel30 *>(pInitInfo);
1148 
1149         retCode = STAFHandle::create(pData->fName, pData->fHandle);
1150 
1151         if (retCode != kSTAFOk)
1152             return retCode;
1153 
1154         STAFCommandParseResultPtr parsedResult =
1155             pData->fParmsParser->parse(pInfo->parms);
1156 
1157         if (parsedResult->rc != kSTAFOk)
1158         {
1159             *pErrorBuffer = parsedResult->errorBuffer.adoptImpl();
1160             return parsedResult->rc;
1161         }
1162 
1163         if (parsedResult->optionTimes(sENABLEREMOTELOGGING) != 0)
1164         {
1165             pData->fRLogMode = 1;
1166 
1167             STAFResultPtr serverResult = resolveOpLocal(pData, parsedResult,
1168                                                         sREMOTELOGSERVER);
1169             if (serverResult->rc != kSTAFOk)
1170             {
1171                 *pErrorBuffer = serverResult->result.adoptImpl();
1172                 return serverResult->rc;
1173             }
1174 
1175             pData->fRemoteLogServer = serverResult->result;
1176 
1177             STAFResultPtr serviceResult = resolveOpLocal(pData, parsedResult,
1178                                                          sREMOTELOGSERVICE);
1179             if (serviceResult->rc != kSTAFOk)
1180             {
1181                 *pErrorBuffer = serviceResult->result.adoptImpl();
1182                 return serviceResult->rc;
1183             }
1184 
1185             if (serviceResult->result.length() != 0)
1186                 pData->fRemoteLogService = serviceResult->result;
1187         }
1188 
1189         STAFResultPtr dirResult = resolveOpLocal(pData, parsedResult,
1190                                                  sDIRECTORY);
1191         if (dirResult->rc != kSTAFOk)
1192         {
1193             *pErrorBuffer = dirResult->result.adoptImpl();
1194             return dirResult->rc;
1195         }
1196 
1197         STAFFSPath logPath;
1198 
1199         if (dirResult->result.length() == 0)
1200         {
1201             logPath.setRoot(pInfo->writeLocation);
1202             logPath.addDir("service");
1203             logPath.addDir(pData->fShortName.toLowerCase());
1204             pData->fRoot = logPath.asString();
1205         }
1206         else
1207         {
1208             pData->fRoot = dirResult->result;
1209             logPath.setRoot(pData->fRoot);
1210         }
1211 
1212         // Create the log data directory if it doesn't already exist to
1213         // verify the log data directory name.
1214 
1215         if (!logPath.exists())
1216         {
1217             try
1218             {
1219                 STAFFSEntryPtr logdir =
1220                     logPath.createDirectory(kSTAFFSCreatePath);
1221             }
1222             catch (...)
1223             {
1224                 STAFString error("STAFLogService.cpp: STAFServiceInit: "
1225                                  "Invalid Log Directory: " + pData->fRoot);
1226                 cout << error << endl;
1227                 *pErrorBuffer = error.adoptImpl();
1228                 return kSTAFServiceConfigurationError;
1229             }
1230         }
1231 
1232         if (parsedResult->optionTimes(sMAXRECORDSIZE) != 0)
1233         {
1234             STAFResultPtr maxResult = resolveOpLocal(pData, parsedResult,
1235                                                      sMAXRECORDSIZE);
1236 
1237             if (maxResult->rc != kSTAFOk)
1238             {
1239                 *pErrorBuffer = maxResult->result.adoptImpl();
1240                 return maxResult->rc;
1241             }
1242 
1243             // Convert resolved option string to an unsigned integer in range
1244             // 0 to UINT_MAX
1245 
1246             maxResult = convertOptionStringToUInt(
1247                 maxResult->result, sMAXRECORDSIZE, pData->fMaxRecordSize);
1248 
1249             if (maxResult->rc != kSTAFOk)
1250             {
1251                 *pErrorBuffer = maxResult->result.adoptImpl();
1252                 return maxResult->rc;
1253             }
1254         }
1255 
1256         if (parsedResult->optionTimes(sDEFAULTMAXQUERYRECORDS) != 0)
1257         {
1258             STAFResultPtr maxResult = resolveOpLocal(
1259                 pData, parsedResult, sDEFAULTMAXQUERYRECORDS);
1260 
1261             if (maxResult->rc != kSTAFOk)
1262             {
1263                 *pErrorBuffer = maxResult->result.adoptImpl();
1264                 return maxResult->rc;
1265             }
1266 
1267             // Convert resolved option string to an unsigned integer in range
1268             // 0 to UINT_MAX
1269 
1270             maxResult = convertOptionStringToUInt(
1271                 maxResult->result, sDEFAULTMAXQUERYRECORDS,
1272                 pData->fDefaultMaxQueryRecords);
1273 
1274             if (maxResult->rc != kSTAFOk)
1275             {
1276                 *pErrorBuffer = maxResult->result.adoptImpl();
1277                 return maxResult->rc;
1278             }
1279         }
1280 
1281         if (parsedResult->optionTimes(sRESOLVEMESSAGE) != 0)
1282             pData->fDefaultResolveMessage = 1;
1283         else if (parsedResult->optionTimes(sNORESOLVEMESSAGE) != 0)
1284             pData->fDefaultResolveMessage = 0;
1285 
1286         if (parsedResult->optionTimes(sENABLERESOLVEMESSAGEVAR) != 0)
1287             pData->fUseResolveMessageVar = 1;
1288         else if (parsedResult->optionTimes(sDISABLERESOLVEMESSAGEVAR) != 0)
1289             pData->fUseResolveMessageVar = 0;
1290 
1291         // Get the default authenticator
1292 
1293         STAFResultPtr resResult = pData->fHandle->submit(
1294             sLocal, sVar, sDefAuthString);
1295 
1296         if (resResult->rc != kSTAFOk)
1297         {
1298             *pErrorBuffer = resResult->result.adoptImpl();
1299             return resResult->rc;
1300         }
1301 
1302         pData->fDefaultAuthenticator = resResult->result;
1303 
1304         // Get the machine name for the local machine
1305 
1306         resResult = pData->fHandle->submit(sLocal, sVar, sResMachineString);
1307 
1308         if (resResult->rc != kSTAFOk)
1309         {
1310             *pErrorBuffer = resResult->result.adoptImpl();
1311             return resResult->rc;
1312         }
1313 
1314         pData->fLocalMachineName = resResult->result;
1315 
1316         // Get the line separator
1317 
1318         resResult = pData->fHandle->submit(sLocal, sVar, sEOLString);
1319 
1320         if (resResult->rc != kSTAFOk)
1321         {
1322             *pErrorBuffer = resResult->result.adoptImpl();
1323             return resResult->rc;
1324         }
1325 
1326         sLineSep = resResult->result;
1327 
1328         // Assign the help text string for the service
1329 
1330         sHelpMsg = STAFString("*** ") + pData->fShortName + " Service Help ***" +
1331             sLineSep + sLineSep +
1332             "LOG    <GLOBAL | MACHINE | HANDLE> LOGNAME <Logname> LEVEL <Level>" +
1333             sLineSep +
1334             "       MESSAGE <Message> [RESOLVEMESSAGE | NORESOLVEMESSAGE]" +
1335             sLineSep + sLineSep +
1336             "QUERY  <GLOBAL | MACHINE <Machine> [HANDLE <Handle>]> LOGNAME <Logname>" +
1337             sLineSep +
1338             "       [LEVELMASK <Mask>] [QMACHINE <Machine>]... " +
1339             "[QHANDLE <Handle>]..." +
1340             sLineSep +
1341             "       [NAME <Name>]... [USER <User>]... [ENDPOINT <Endpoint>]..." +
1342             sLineSep +
1343             "       [CONTAINS <String>]... [CSCONTAINS <String>]..." +
1344             sLineSep +
1345             "       [STARTSWITH <String>]... [CSSTARTSWITH <String>]..." +
1346             sLineSep +
1347             "       [FROM <Timestamp> | AFTER <Timestamp>]" +
1348             sLineSep +
1349             "       [BEFORE <Timestamp> | TO <Timestamp>]" +
1350             sLineSep +
1351             "       [FROMRECORD <Num>] [TORECORD <Num>]" +
1352             sLineSep +
1353             "       [FIRST <Num> | LAST <Num> | ALL] [TOTAL | STATS | LONG]" +
1354             sLineSep +
1355             "       [LEVELBITSTRING]" +
1356             sLineSep + sLineSep +
1357             "LIST   GLOBAL | MACHINES | MACHINE <Machine> [HANDLES | HANDLE <Handle>] |" +
1358             sLineSep +
1359             "       SETTINGS" +
1360             sLineSep + sLineSep +
1361             "DELETE <GLOBAL | MACHINE <Machine> [HANDLE <Handle>]>" +
1362             sLineSep +
1363             "       LOGNAME <Logname> CONFIRM" +
1364             sLineSep + sLineSep +
1365             "PURGE  <GLOBAL | MACHINE <Machine> [HANDLE <Handle>]> LOGNAME <Logname>" +
1366             sLineSep +
1367             "       CONFIRM | CONFIRMALL" +
1368             sLineSep +
1369             "       [LEVELMASK <Mask>] [QMACHINE <Machine>]... [QHANDLE <Handle>]..." +
1370             sLineSep +
1371             "       [NAME <Name>]... [USER <User>]... [ENDPOINT <Endpoint>]..." +
1372             sLineSep +
1373             "       [CONTAINS <String>]... [CSCONTAINS <String>]..." +
1374             sLineSep +
1375             "       [STARTSWITH <String>]... [CSSTARTSWITH <String>]..." +
1376             sLineSep +
1377             "       [FROM <Timestamp> | AFTER <Timestamp>]" +
1378             sLineSep +
1379             "       [BEFORE <Timestamp> | TO <Timestamp>]" +
1380             sLineSep +
1381             "       [FROMRECORD <Num>] [TORECORD <Num>]" +
1382             sLineSep +
1383             "       [FIRST <Num> | LAST <Num>]" +
1384             sLineSep + sLineSep +
1385             "SET    [MAXRECORDSIZE <Size>] [DEFAULTMAXQUERYRECORDS <Number>]" +
1386             sLineSep +
1387             "       [ENABLERESOLVEMESSAGEVAR | DISABLERESOLVEMESSAGEVAR]" +
1388             sLineSep +
1389             "       [RESOLVEMESSAGE | NORESOLVEMESSAGE]" +
1390             sLineSep + sLineSep +
1391             "VERSION" +
1392             sLineSep + sLineSep +
1393             "HELP";
1394 
1395         // Register help for the error codes for this service
1396 
1397         registerHelpData(pData, kSTAFLogInvalidLevel,
1398             STAFString("Invalid level"),
1399             STAFString("An invalid logging level was specified.  "
1400                        "See the STAF User's Guide for a complete list of "
1401                        "logging levels."));
1402 
1403         registerHelpData(pData, kSTAFLogInvalidFileFormat,
1404             STAFString("Invalid file format"),
1405             STAFString("An invalid/unknown record format was encountered "
1406                        "while reading the log file"));
1407 
1408         registerHelpData(pData, kSTAFLogPurgeFailure,
1409             STAFString("Unable to purge all log records"),
1410             STAFString("Your purge criteria selected every record in the log "
1411                        "file.  Use CONFIRMALL instead of CONFIRM if you "
1412                        "really want to delete every record (or submit a "
1413                        "DELETE request).  Or, modify your purge criteria."));
1414 
1415         registerHelpData(pData, kSTAFLogExceededDefaultMaxRecords,
1416             STAFString("Exceeded default maximum query records"),
1417             STAFString("Your query criteria selected more records than "
1418                        "allowed by the DefaultMaxQueryRecords setting.  "
1419                        "Use the FIRST <Num> or LAST <Num> option to specify "
1420                        "the number of records or the ALL option if you "
1421                        "really want all of the records."));
1422     }
1423     catch (STAFException &e)
1424     {
1425         *pErrorBuffer = getExceptionString(e,
1426                         "STAFLogService.cpp: STAFServiceInit").adoptImpl();
1427     }
1428     catch (...)
1429     {
1430         STAFString error("STAFLogService.cpp: STAFServiceInit: "
1431                          "Caught unknown exception");
1432         *pErrorBuffer = error.adoptImpl();
1433     }
1434 
1435     return retCode;
1436 }
1437 
1438 
STAFServiceAcceptRequest(STAFServiceHandle_t serviceHandle,void * pRequestInfo,unsigned int reqLevel,STAFString_t * pResultBuffer)1439 STAFRC_t STAFServiceAcceptRequest(STAFServiceHandle_t serviceHandle,
1440                                   void *pRequestInfo, unsigned int reqLevel,
1441                                   STAFString_t *pResultBuffer)
1442 {
1443     if (reqLevel != 30) return kSTAFInvalidAPILevel;
1444 
1445     STAFRC_t retCode = kSTAFUnknownError;
1446 
1447     try
1448     {
1449         STAFResultPtr result(new STAFResult(), STAFResultPtr::INIT);
1450 
1451         STAFServiceRequestLevel30 *pInfo =
1452             reinterpret_cast<STAFServiceRequestLevel30 *>(pRequestInfo);
1453 
1454         LogServiceData *pData =
1455             reinterpret_cast<LogServiceData *>(serviceHandle);
1456 
1457         STAFString request(pInfo->request);
1458         STAFString action = request.subWord(0, 1).toUpperCase();
1459 
1460         if (pData->fRLogMode != 0)
1461         {
1462             if (action == sLOG) result = handleRemoteLog(pInfo, pData);
1463             else if (action == sVERSION)
1464             {
1465                 result = STAFResultPtr(new STAFResult(kSTAFOk, sVersionInfo),
1466                                        STAFResultPtr::INIT);
1467             }
1468             else if ((action == sLIST) &&
1469                      (request.subWord(1, 2).toUpperCase() == sSETTINGS))
1470             {
1471                 result = handleList(pInfo, pData);
1472             }
1473             else result = handleRemoteLogGeneral(pInfo, pData);
1474         }
1475         else if (action == sLOG)    result = handleLog(pInfo, pData);
1476         else if (action == sQUERY)  result = handleQuery(pInfo, pData);
1477         else if (action == sLIST)   result = handleList(pInfo, pData);
1478         else if (action == sDELETE) result = handleDelete(pInfo, pData);
1479         else if (action == sPURGE)  result = handlePurge(pInfo, pData);
1480         else if (action == sSET)    result = handleSet(pInfo, pData);
1481         else if (action == sHELP)   result = handleHelp(pInfo, pData);
1482         else if (action == sVERSION)
1483         {
1484             result = STAFResultPtr(new STAFResult(kSTAFOk, sVersionInfo),
1485                                    STAFResultPtr::INIT);
1486         }
1487         else
1488         {
1489             STAFString errMsg = STAFString("'") + request.subWord(0, 1) +
1490                 "' is not a valid command request for the " +
1491                 pData->fShortName + " service" + sLineSep + sLineSep +
1492                 sHelpMsg;
1493 
1494             result = STAFResultPtr(new STAFResult(
1495                 kSTAFInvalidRequestString, errMsg), STAFResultPtr::INIT);
1496         }
1497 
1498         *pResultBuffer = result->result.adoptImpl();
1499         retCode = result->rc;
1500     }
1501     catch (STAFException &e)
1502     {
1503         retCode = e.getErrorCode();
1504 
1505         *pResultBuffer = getExceptionString(
1506             e, "STAFLogService.cpp: STAFServiceAcceptRequest").adoptImpl();
1507     }
1508     catch (...)
1509     {
1510         STAFString error("STAFLogService.cpp: STAFServiceAcceptRequest: "
1511                          "Caught unknown exception");
1512         *pResultBuffer = error.adoptImpl();
1513     }
1514 
1515     return retCode;
1516 }
1517 
1518 
STAFServiceTerm(STAFServiceHandle_t serviceHandle,void * pTermInfo,unsigned int termLevel,STAFString_t * pErrorBuffer)1519 STAFRC_t STAFServiceTerm(STAFServiceHandle_t serviceHandle, void *pTermInfo,
1520                          unsigned int termLevel, STAFString_t *pErrorBuffer)
1521 {
1522     if (termLevel != 0) return kSTAFInvalidAPILevel;
1523 
1524     STAFRC_t retCode = kSTAFUnknownError;
1525 
1526     try
1527     {
1528         retCode = kSTAFOk;
1529 
1530         LogServiceData *pData =
1531             reinterpret_cast<LogServiceData *>(serviceHandle);
1532 
1533         // Un-register Help Data
1534 
1535         unregisterHelpData(pData, kSTAFLogInvalidLevel);
1536         unregisterHelpData(pData, kSTAFLogInvalidFileFormat);
1537         unregisterHelpData(pData, kSTAFLogPurgeFailure);
1538     }
1539     catch (STAFException &e)
1540     {
1541         *pErrorBuffer = getExceptionString(e,
1542                         "STAFLogService.cpp: STAFServiceTerm").adoptImpl();
1543     }
1544     catch (...)
1545     {
1546         STAFString error("STAFLogService.cpp: STAFServiceTerm: "
1547                          "Caught unknown exception");
1548         *pErrorBuffer = error.adoptImpl();
1549     }
1550 
1551     return retCode;
1552 }
1553 
1554 
STAFServiceDestruct(STAFServiceHandle_t * serviceHandle,void * pDestructInfo,unsigned int destructLevel,STAFString_t * pErrorBuffer)1555 STAFRC_t STAFServiceDestruct(STAFServiceHandle_t *serviceHandle,
1556                              void *pDestructInfo, unsigned int destructLevel,
1557                              STAFString_t *pErrorBuffer)
1558 {
1559     if (destructLevel != 0) return kSTAFInvalidAPILevel;
1560 
1561     STAFRC_t retCode = kSTAFUnknownError;
1562 
1563     try
1564     {
1565         LogServiceData *pData =
1566             reinterpret_cast<LogServiceData *>(*serviceHandle);
1567         delete pData;
1568         *serviceHandle = 0;
1569 
1570         retCode = kSTAFOk;
1571     }
1572     catch (STAFException &e)
1573     {
1574         *pErrorBuffer = getExceptionString(e,
1575                         "STAFLogService.cpp: STAFServiceDestruct").adoptImpl();
1576     }
1577     catch (...)
1578     {
1579         STAFString error("STAFLogService.cpp: STAFServiceDestruct: "
1580                          "Caught unknown exception");
1581         *pErrorBuffer = error.adoptImpl();
1582     }
1583 
1584     return retCode;
1585 }
1586 
1587 
handleLog(STAFServiceRequestLevel30 * pInfo,LogServiceData * pData)1588 STAFResultPtr handleLog(STAFServiceRequestLevel30 *pInfo, LogServiceData *pData)
1589 {
1590     // XXX: This routine in particular has serious issues when we add the
1591     //      ability to resolve remote handle variables.  It relies on functions
1592     //      which assume that the requestor is in the pInfo structure, which it
1593     //      may not be if we are a remote log server.
1594 
1595     INIT_TIMES();
1596     RECORD_TIME("Parsing");
1597 
1598     STAFCommandParseResultPtr parsedResult =
1599         pData->fLogParser->parse(pInfo->request);
1600 
1601     if (parsedResult->rc != kSTAFOk)
1602     {
1603         return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString,
1604                              parsedResult->errorBuffer), STAFResultPtr::INIT);
1605     }
1606 
1607     RECORD_TIME("Check trust");
1608 
1609     // Verify that the requesting machine/user has at least trust level 3
1610 
1611     if (parsedResult->optionTimes(sRMTMACHINE) == 0)
1612     {
1613         VALIDATE_TRUST(3, pData->fShortName, "LOG", pData->fLocalMachineName);
1614     }
1615     else
1616     {
1617         // Verify that the remote log machine/user has at least trust level 3
1618 
1619         STAFString trustRequest(
1620             sGetMachine + parsedResult->optionValue(sRMTMACHINE) +
1621             sGetUser + parsedResult->optionValue(sRMTUSER));
1622 
1623         STAFResultPtr trustResult = pData->fHandle->submit(
1624             sLocal, sTrust, trustRequest);
1625 
1626         if (trustResult->rc != kSTAFOk)
1627         {
1628             STAFString errorMsg = STAFString(
1629                 "Verifying that the remote log machine/user has at least "
1630                 "trust level 3 failed.  STAF local TRUST ") + trustRequest +
1631                 " failed with RC: " + trustResult->rc +
1632                 ", Result: " + trustResult->result;
1633 
1634             return STAFResultPtr(
1635                 new STAFResult(trustResult->rc, errorMsg),
1636                 STAFResultPtr::INIT);
1637         }
1638 
1639         try
1640         {
1641             unsigned int trustLevel = trustResult->result.asUInt();
1642 
1643             VALIDATE_TRUST3(3, pData->fShortName, "LOG",
1644                             pData->fLocalMachineName, trustLevel,
1645                             parsedResult->optionValue(sRMTMACHINE), "",
1646                             parsedResult->optionValue(sRMTUSER));
1647         }
1648         catch (STAFException)
1649         {
1650             STAFString errorMsg = STAFString(
1651                 "Verifying that the remote log machine/user has at least "
1652                 "trust level 3 failed.  STAF local TRUST ") + trustRequest +
1653                 " did not return a numeric trust level, Result: " +
1654                 trustResult->result;
1655 
1656             return STAFResultPtr(
1657                 new STAFResult(kSTAFAccessDenied, errorMsg),
1658                 STAFResultPtr::INIT);
1659         }
1660     }
1661 
1662     // Get log level and log mask and see if we should log
1663 
1664     RECORD_TIME("Check log level");
1665 
1666     STAFResultPtr levelResult = resolveOp(pInfo, pData, parsedResult, sLEVEL);
1667 
1668     if (levelResult->rc != kSTAFOk) return levelResult;
1669 
1670     unsigned int logLevel = 0;
1671 
1672     if (!isValidLogLevel(levelResult->result, logLevel))
1673     {
1674         return STAFResultPtr(new STAFResult(kSTAFLogInvalidLevel,
1675                                             levelResult->result),
1676                              STAFResultPtr::INIT);
1677     }
1678 
1679     STAFResultPtr logmaskResult = resolveStr(pInfo, pData,
1680                                              pData->fResolveLogMaskString);
1681     if ((logmaskResult->rc != kSTAFOk) &&
1682         (logmaskResult->rc != kSTAFVariableDoesNotExist))
1683     {
1684         return logmaskResult;
1685     }
1686 
1687     if (logmaskResult->rc == kSTAFVariableDoesNotExist)
1688         logmaskResult->result = sEverythingLogMask;
1689 
1690     unsigned int logMask = 0;
1691 
1692     if (!convertLogMaskToUInt(logmaskResult->result, logMask))
1693     {
1694         return STAFResultPtr(new STAFResult(kSTAFLogInvalidLevel,
1695                                             logmaskResult->result),
1696                              STAFResultPtr::INIT);
1697     }
1698 
1699     if (!(logLevel & logMask))
1700         return STAFResultPtr(new STAFResult, STAFResultPtr::INIT);
1701 
1702     // Get logname and message
1703 
1704     RECORD_TIME("Get logname and message");
1705 
1706     STAFResultPtr lognameResult = resolveOp(pInfo, pData, parsedResult,
1707                                             sLOGNAME);
1708 
1709     if (lognameResult->rc != kSTAFOk) return lognameResult;
1710 
1711     // if the user specifies to resolve messages or
1712     // STAF/Service/Log/ResolveMessage is enabled and set or
1713     // the default is to resolve messages and the user didn't say not to
1714     // then resolve the message
1715 
1716     STAFString message = parsedResult->optionValue(sMESSAGE);
1717     unsigned int resolveMessage = pData->fDefaultResolveMessage;
1718 
1719     if (parsedResult->optionTimes(sRESOLVEMESSAGE) != 0)
1720     {
1721         resolveMessage = 1;
1722     }
1723     else if (parsedResult->optionTimes(sNORESOLVEMESSAGE) != 0)
1724     {
1725         resolveMessage = 0;
1726     }
1727     else if (pData->fUseResolveMessageVar != 0)
1728     {
1729         STAFResultPtr resolveResult = resolveStr(pInfo, pData,
1730                                                  pData->fResolveMessageString);
1731         if (resolveResult->rc == kSTAFOk)
1732         {
1733             try
1734             {
1735                 if (resolveResult->result.asUInt() != 0)
1736                     resolveMessage = 1;
1737                 else
1738                     resolveMessage = 0;
1739             }
1740             catch (STAFException)
1741             {
1742                 STAFString errorMsg = STAFString("The resolved value for ") +
1743                     pData->fResolveMessageString + " must be 0 or 1.  "
1744                     "Invalid value: " + resolveResult->result;
1745 
1746                 return STAFResultPtr(
1747                     new STAFResult(kSTAFInvalidValue, errorMsg),
1748                     STAFResultPtr::INIT);
1749             }
1750         }
1751         else if (resolveResult->rc != kSTAFVariableDoesNotExist)
1752         {
1753             return resolveResult;
1754         }
1755     }
1756 
1757     if (resolveMessage != 0)
1758     {
1759         STAFResultPtr messageResult = resolveOp(
1760             pInfo, pData, parsedResult, sMESSAGE);
1761 
1762         if (messageResult->rc != kSTAFOk) return messageResult;
1763 
1764         message = messageResult->result;
1765     }
1766 
1767     if (message.length(STAFString::kChar) > pData->fMaxRecordSize)
1768         message = message.subString(0, pData->fMaxRecordSize, STAFString::kChar);
1769 
1770     // Check for remote logging info
1771 
1772     RECORD_TIME("Check for remote");
1773 
1774     bool isRemote = false;
1775     STAFString remoteMachine;
1776     STAFString remoteHandleName;
1777     STAFString remoteHandle;
1778     STAFString remoteUser;
1779     STAFString remoteLogicalMachine;
1780     STAFString remoteNickname;
1781 
1782     if (parsedResult->optionTimes(sRMTMACHINE) != 0)
1783     {
1784         isRemote = true;
1785         remoteMachine = parsedResult->optionValue(sRMTMACHINE);
1786         remoteHandleName = parsedResult->optionValue(sRMTNAME);
1787         remoteHandle = parsedResult->optionValue(sRMTHANDLE);
1788         remoteUser = parsedResult->optionValue(sRMTUSER);
1789         remoteLogicalMachine = parsedResult->optionValue(sRMTMACH);
1790         remoteNickname = parsedResult->optionValue(sRMTNICKNAME);
1791     }
1792 
1793     // Setup/Create the path
1794 
1795     RECORD_TIME("Create path");
1796 
1797     STAFFSPath logfilePath;
1798 
1799     logfilePath.setRoot(pData->fRoot);
1800 
1801     if (parsedResult->optionTimes(sGLOBAL) != 0)
1802     {
1803         logfilePath.addDir(sGLOBAL);
1804     }
1805     else
1806     {
1807         logfilePath.addDir(sMACHINE);
1808 
1809         if (isRemote)
1810             logfilePath.addDir(remoteNickname);
1811         else
1812             logfilePath.addDir(pInfo->machineNickname);
1813 
1814         if (parsedResult->optionTimes(sMACHINE) != 0)
1815         {
1816             logfilePath.addDir(sGLOBAL);
1817         }
1818         else
1819         {
1820             logfilePath.addDir(sHANDLE);
1821 
1822             if (isRemote)
1823                 logfilePath.addDir(remoteHandle);
1824             else
1825                 logfilePath.addDir(pInfo->handle);
1826         }
1827     }
1828 
1829     if (!logfilePath.exists())
1830     {
1831         try
1832         {
1833             // XXX: Don't want exceptions here
1834             STAFFSEntryPtr logdir =
1835                            logfilePath.createDirectory(kSTAFFSCreatePath);
1836         }
1837         catch (...)
1838         { /* Do Nothing */ }
1839     }
1840 
1841     logfilePath.setName(lognameResult->result);
1842     logfilePath.setExtension(sLogExt);
1843 
1844     // Must get lock before opening file to avoid log corruption problem
1845     // with multiple simultaneous read/writes to same log.
1846 
1847     // Get a write lock on the global Read/Write Semaphore
1848 
1849     RECORD_TIME("Get and lock entry");
1850 
1851     STAFLogFileLocksPtr logLocks =
1852         STAFLogFileLocks::acquireLocks(logfilePath.asString());
1853     STAFRWSemRLock accessLock(*logLocks->logAccess);
1854     STAFMutexSemLock recordLock(*logLocks->recordAccess);
1855 
1856     // Open the log file
1857 
1858     RECORD_TIME("Open log file");
1859 
1860     fstream logfile(logfilePath.asString().toCurrentCodePage()->buffer(),
1861                     ios::out | ios::app | STAF_ios_binary);
1862 
1863     if (!logfile)
1864     {
1865         return STAFResultPtr(new STAFResult(kSTAFFileOpenError,
1866                                             logfilePath.asString()),
1867                              STAFResultPtr::INIT);
1868     }
1869 
1870     // Write the log file data
1871 
1872     RECORD_TIME("Write log record");
1873 
1874     STAFTimestamp currTimestamp;
1875 
1876     LogRecord logRecord(currTimestamp.asDateString().asUInt(),
1877                         currTimestamp.asSecondsPastMidnight(), logLevel,
1878                         pInfo->machine, pInfo->handleName, pInfo->handle,
1879                         pInfo->user, pInfo->endpoint, message);
1880 
1881     if (isRemote)
1882     {
1883         logRecord.machine = remoteLogicalMachine;
1884         logRecord.handle = remoteHandle.asUIntWithDefault(0);
1885         logRecord.handleName = remoteHandleName;
1886         logRecord.user = remoteUser;
1887         logRecord.endpoint = remoteMachine;
1888     }
1889 
1890     writeLogRecordToFile(logfile, logRecord);
1891 
1892     RECORD_TIME("Log complete (except for file close)");
1893     OUTPUT_TIMES();
1894 
1895     return STAFResultPtr(new STAFResult, STAFResultPtr::INIT);
1896 }
1897 
1898 
handleQuery(STAFServiceRequestLevel30 * pInfo,LogServiceData * pData)1899 STAFResultPtr handleQuery(STAFServiceRequestLevel30 *pInfo, LogServiceData *pData)
1900 {
1901     STAFCommandParseResultPtr parsedResult =
1902         pData->fQueryParser->parse(pInfo->request);
1903 
1904     if (parsedResult->rc != kSTAFOk)
1905     {
1906         return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString,
1907                              parsedResult->errorBuffer), STAFResultPtr::INIT);
1908     }
1909 
1910     if (parsedResult->optionTimes(sRMTMACHINE) == 0)
1911     {
1912         // Verify that the requesting machine/user has at least trust level 2
1913 
1914         VALIDATE_TRUST(2, pData->fShortName, "QUERY", pData->fLocalMachineName);
1915     }
1916     else
1917     {
1918         // Verify that the remote log machine/user has at least trust level 2
1919 
1920         STAFString trustRequest(
1921             sGetMachine + parsedResult->optionValue(sRMTMACHINE) +
1922             sGetUser + parsedResult->optionValue(sRMTUSER));
1923 
1924         STAFResultPtr trustResult = pData->fHandle->submit(
1925             sLocal, sTrust, trustRequest);
1926 
1927         if (trustResult->rc != kSTAFOk)
1928         {
1929             STAFString errorMsg = STAFString(
1930                 "Verifying that the remote log machine/user has at least "
1931                 "trust level 2 failed.  STAF local TRUST ") + trustRequest +
1932                 " failed with RC: " + trustResult->rc +
1933                 ", Result: " + trustResult->result;
1934 
1935             return STAFResultPtr(
1936                 new STAFResult(trustResult->rc, errorMsg),
1937                 STAFResultPtr::INIT);
1938         }
1939 
1940         try
1941         {
1942             unsigned int trustLevel = trustResult->result.asUInt();
1943 
1944             VALIDATE_TRUST3(2, pData->fShortName, "QUERY",
1945                             pData->fLocalMachineName, trustLevel,
1946                             parsedResult->optionValue(sRMTMACHINE), "",
1947                             parsedResult->optionValue(sRMTUSER));
1948         }
1949         catch (STAFException)
1950         {
1951             STAFString errorMsg = STAFString(
1952                 "Verifying that the remote log machine/user has at least "
1953                 "trust level 2 failed.  STAF local TRUST ") + trustRequest +
1954                 " did not return a numeric trust level, Result: " +
1955                 trustResult->result;
1956 
1957             return STAFResultPtr(
1958                 new STAFResult(kSTAFAccessDenied, errorMsg),
1959                 STAFResultPtr::INIT);
1960         }
1961     }
1962 
1963     // Build up the log filter criteria
1964 
1965     STAFResultPtr errorResult;
1966     LogRecordFilter logFilter;
1967     LogStats logStats = { 0 };
1968 
1969     if (!updateQueryPurgeLogFilter(logFilter, errorResult, pInfo, pData,
1970                                    parsedResult))
1971     {
1972         return errorResult;
1973     }
1974 
1975     // See if they specified LEVELBITSTRING or STATS or TOTAL
1976 
1977     bool levelAsBits = (parsedResult->optionTimes(sLEVELBITSTRING) > 0) ?
1978                        true : false;
1979     bool onlyStats = (parsedResult->optionTimes(sSTATS) > 0) ? true : false;
1980     bool onlyTotal = (parsedResult->optionTimes(sTOTAL) > 0) ? true : false;
1981     bool longFormat = (parsedResult->optionTimes(sLONG) > 0) ? true : false;
1982 
1983     unsigned int first = 0;
1984     unsigned int last = 0;
1985     bool all = false;
1986 
1987     // Check if they specified FIRST or LAST or ALL
1988 
1989     if (parsedResult->optionTimes(sFIRST))
1990     {
1991         STAFResultPtr result = resolveOp(
1992             pInfo, pData, parsedResult, sFIRST);
1993 
1994         if (result->rc != kSTAFOk) return result;
1995 
1996         // Convert resolved option string to an unsigned integer in range 0
1997         // to UINT_MAX
1998 
1999         result = convertOptionStringToUInt(result->result, sFIRST, first);
2000 
2001         if (result->rc != kSTAFOk) return result;
2002     }
2003     else if (parsedResult->optionTimes(sLAST))
2004     {
2005         STAFResultPtr result = resolveOp(
2006             pInfo, pData, parsedResult, sLAST);
2007 
2008         if (result->rc != kSTAFOk) return result;
2009 
2010         // Convert resolved option string to an unsigned integer in range 0
2011         // to UINT_MAX
2012 
2013         result = convertOptionStringToUInt(result->result, sLAST, last);
2014 
2015         if (result->rc != kSTAFOk) return result;
2016     }
2017     else if (parsedResult->optionTimes(sALL))
2018     {
2019         all = true;
2020     }
2021 
2022     bool useFromRecord = false;
2023     unsigned int fromRecord = 0;
2024     bool useToRecord = false;
2025     unsigned int toRecord = 0;
2026 
2027     if (parsedResult->optionTimes(sFROMRECORD) != 0)
2028     {
2029         STAFResultPtr result = resolveOp(
2030             pInfo, pData, parsedResult, sFROMRECORD);
2031 
2032         if (result->rc != kSTAFOk) return result;
2033 
2034         // Convert resolved option string to an unsigned integer in range 1
2035         // to UINT_MAX
2036 
2037         result = convertOptionStringToUInt(
2038             result->result, sFROMRECORD, fromRecord, 1);
2039 
2040         if (result->rc != kSTAFOk) return result;
2041 
2042         useFromRecord = true;
2043     }
2044 
2045     if (parsedResult->optionTimes(sTORECORD) != 0)
2046     {
2047         STAFResultPtr result = resolveOp(
2048             pInfo, pData, parsedResult, sTORECORD);
2049 
2050         if (result->rc != kSTAFOk) return result;
2051 
2052         // Convert resolved option string to an unsigned integer in range 1
2053         // to UINT_MAX
2054 
2055         result = convertOptionStringToUInt(
2056             result->result, sTORECORD, toRecord, 1);
2057 
2058         if (result->rc != kSTAFOk) return result;
2059 
2060         useToRecord = true;
2061     }
2062 
2063     if (useToRecord && useFromRecord && (fromRecord > toRecord))
2064     {
2065         STAFString errorMsg = STAFString("FROMRECORD value must be <= ") +
2066             "TORECORD value.  FROMRECORD: " + STAFString(fromRecord) +
2067             ", TORECORD: " + STAFString(toRecord);
2068         return STAFResultPtr(new STAFResult(kSTAFInvalidValue, errorMsg),
2069                              STAFResultPtr::INIT);
2070 
2071     }
2072 
2073     // Get the log file path
2074 
2075     STAFFSPath logfilePath;
2076 
2077     if (!generateQueryPurgeDeleteLogFilePath(logfilePath, errorResult,
2078                                              pInfo, pData, parsedResult))
2079     {
2080         return errorResult;
2081     }
2082 
2083     // Open the log file
2084 
2085     if (!logfilePath.exists())
2086     {
2087         return STAFResultPtr(new STAFResult(kSTAFDoesNotExist,
2088                                             logfilePath.name()),
2089                              STAFResultPtr::INIT);
2090     }
2091 
2092     fstream logfile(logfilePath.asString().toCurrentCodePage()->buffer(),
2093                     ios::in | STAF_ios_binary);
2094 
2095     if (!logfile)
2096     {
2097         return STAFResultPtr(new STAFResult(kSTAFFileOpenError,
2098                                             logfilePath.asString()),
2099                              STAFResultPtr::INIT);
2100     }
2101 
2102     // Determine if should return an error and limit number of records if the
2103     // number of records matching the query criteria exceeds the default
2104     // maximum query records.
2105 
2106     bool limitRecords = false;
2107 
2108     if ((pData->fDefaultMaxQueryRecords != 0) && (!all) &&
2109          (first == 0) && (last == 0) && (!onlyTotal) && (!onlyStats))
2110     {
2111         limitRecords = true;
2112         last = pData->fDefaultMaxQueryRecords;
2113     }
2114 
2115     STAFRC_t rc = kSTAFOk;
2116 
2117     // Create the marshalling context
2118     STAFObjectPtr mc = STAFObject::createMarshallingContext();
2119 
2120     // Create an empty list object for the marshalled list of log records
2121     STAFObjectPtr logList = STAFObject::createList();
2122 
2123     // Set the log record map class definition pointer
2124 
2125     STAFMapClassDefinitionPtr mapClassPtr = pData->fLogRecordClass->
2126         reference();
2127 
2128     if (longFormat)
2129         mapClassPtr = pData->fLogRecordLongClass->reference();
2130 
2131     // Get a read lock on the global Read/Write Semaphore
2132 
2133     STAFLogFileLocksPtr logLocks =
2134         STAFLogFileLocks::acquireLocks(logfilePath.asString());
2135     STAFRWSemRLock accessLock(*logLocks->logAccess);
2136 
2137     // Read each record
2138 
2139     const int RECORDS_PER_LOCK = 100;
2140     unsigned int currFirstRecords = 0;
2141     STAFString result = STAFString();
2142     unsigned int totalRecords = 0;
2143     LogRecord logRecord;
2144 
2145     // If LAST option is specified, use a FIFO queue to store the last <nnn>
2146     // log records.  A std::queue uses a deque as the default container and
2147     // provides better performance than a list for large LAST values
2148     std::queue<LogRecord> lastLogRecordsQueue;
2149 
2150     // Record number counter (used to compare with fromRecord and toRecord)
2151     // and to know which record number is currently being processed.
2152     unsigned int recordNum = 0;
2153 
2154     // Flag to use to indicate if don't need to process any more records
2155     bool done = false;
2156 
2157     while (!logfile.eof() && !done)
2158     {
2159         STAFMutexSemLock recordLock(*logLocks->recordAccess);
2160 
2161         for (int recordCount = 0;
2162              (recordCount < RECORDS_PER_LOCK) && !logfile.eof();
2163              ++recordCount)
2164         {
2165             recordNum++;
2166 
2167             // First, get the information from the log record
2168 
2169             unsigned int status = readLogRecordFromFile(
2170                 logfile, logRecord, recordNum);
2171 
2172             if (status == kReadLogEndOfFile)
2173             {
2174                 // Finish up with whatever needs to be done
2175                 continue;
2176             }
2177             else if (status == kReadLogInvalidFormat)
2178             {
2179                 // Invalid log record format.  Cannot continue.
2180 
2181                 STAFString errorMsg = STAFString(
2182                     "Invalid record format in record number ") + recordNum +
2183                     " with format ID " + logRecord.recordFormatID;
2184 
2185                 return STAFResultPtr(
2186                     new STAFResult(kSTAFLogInvalidFileFormat, errorMsg),
2187                     STAFResultPtr::INIT);
2188             }
2189 
2190             // Now, make sure this record meets the selection criteria
2191 
2192             if (useFromRecord)
2193             {
2194                 if (recordNum < fromRecord)
2195                 {
2196                     // Ignore this log record
2197                     continue;
2198                 }
2199             }
2200 
2201             if (useToRecord)
2202             {
2203                 if (recordNum > toRecord)
2204                 {
2205                     // Don't need to process any more log records
2206                     done = true;
2207                     break;
2208                 }
2209             }
2210 
2211             // XXX: Might want to make a change to stop once we reach the
2212             //      BEFORE / TO date
2213 
2214             if (!logRecordMatchesFilter(logRecord, logFilter,
2215                                         pData->fDefaultAuthenticator))
2216             {
2217                 continue;
2218             }
2219 
2220             // Now, do whatever we are supposed to with the record
2221 
2222             /* DEBUG: printLogRecord(logRecord); */
2223 
2224             if (last > 0)
2225             {
2226                 // Make sure we only keep 'last' number of records
2227                 if (lastLogRecordsQueue.size() == last)
2228                 {
2229                     lastLogRecordsQueue.pop();
2230 
2231                     // ???-CVR: This check seems odd.  The user seems to have
2232                     //          explicitly told us how many records they want,
2233                     //          but if they've also told us some maximum
2234                     //          number of records, then we return an error.
2235                     //          Seems like we need to see if they've actually
2236                     //          exceeded the limit before returning this error.
2237 
2238                     if (limitRecords) rc = kSTAFLogExceededDefaultMaxRecords;
2239                 }
2240 
2241                 lastLogRecordsQueue.push(logRecord);
2242             }
2243             else
2244             {
2245                 if (onlyTotal)
2246                 {
2247                     ++totalRecords;
2248                 }
2249                 else if (onlyStats)
2250                 {
2251                     updateLogStats(logStats, logRecord.logLevel);
2252                 }
2253                 else
2254                 {
2255                     addLogRecordToList(logList, mapClassPtr, logRecord,
2256                                        levelAsBits, longFormat);
2257                 }
2258 
2259                 if ((first > 0) && (++currFirstRecords >= first))
2260                 {
2261                     // Don't need to process any more log records
2262                     done = true;
2263                     break;
2264                 }
2265             }
2266         }
2267     }
2268 
2269     // If we were doing the "last" set of things, we now need to generate
2270     // the output or update the stats
2271 
2272     if (last > 0)
2273     {
2274     	while (!lastLogRecordsQueue.empty())
2275         {
2276             if (onlyTotal) ++totalRecords;
2277             else if (onlyStats)
2278             {
2279             	logRecord = lastLogRecordsQueue.front();
2280                 updateLogStats(logStats, logRecord.logLevel);
2281             }
2282             else
2283             {
2284             	logRecord = lastLogRecordsQueue.front();
2285                 addLogRecordToList(logList, mapClassPtr, logRecord,
2286                                    levelAsBits, longFormat);
2287             }
2288 
2289             lastLogRecordsQueue.pop();
2290         }
2291     }
2292 
2293     if (onlyTotal)
2294     {
2295         result = STAFString(totalRecords);
2296     }
2297     else if (onlyStats)
2298     {
2299         // Create a map object for the marshalled map of log stats
2300 
2301         STAFObjectPtr queryStatsMap =
2302             pData->fQueryStatsClass->createInstance();
2303 
2304         addLogStatsToMap(queryStatsMap, logStats);
2305 
2306         // Set the marshalling context map class definitions and root object
2307 
2308         mc->setMapClassDefinition(pData->fQueryStatsClass->reference());
2309         mc->setRootObject(queryStatsMap);
2310 
2311         result = mc->marshall();
2312     }
2313     else
2314     {
2315         // Set the marshalling context map class definitions and root object
2316 
2317         mc->setMapClassDefinition(mapClassPtr->reference());
2318         mc->setRootObject(logList);
2319 
2320         result = mc->marshall();
2321     }
2322 
2323     return STAFResultPtr(new STAFResult(rc, result), STAFResultPtr::INIT);
2324 }
2325 
2326 
handleList(STAFServiceRequestLevel30 * pInfo,LogServiceData * pData)2327 STAFResultPtr handleList(STAFServiceRequestLevel30 *pInfo, LogServiceData *pData)
2328 {
2329     STAFCommandParseResultPtr parsedResult =
2330         pData->fListParser->parse(pInfo->request);
2331 
2332     if (parsedResult->rc != kSTAFOk)
2333     {
2334         return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString,
2335                              parsedResult->errorBuffer), STAFResultPtr::INIT);
2336     }
2337 
2338     // Verify that the requesting machine/user has at least trust level 2
2339 
2340     if (parsedResult->optionTimes(sRMTMACHINE) == 0)
2341     {
2342         VALIDATE_TRUST(2, pData->fShortName, "LIST", pData->fLocalMachineName);
2343     }
2344     else
2345     {
2346         // Verify that the remote log machine/user has at least trust level 2
2347 
2348         STAFString trustRequest(
2349             sGetMachine + parsedResult->optionValue(sRMTMACHINE) +
2350             sGetUser + parsedResult->optionValue(sRMTUSER));
2351 
2352         STAFResultPtr trustResult = pData->fHandle->submit(
2353             sLocal, sTrust, trustRequest);
2354 
2355         if (trustResult->rc != kSTAFOk)
2356         {
2357             STAFString errorMsg = STAFString(
2358                 "Verifying that the remote log machine/user has at least "
2359                 "trust level 2 failed.  STAF local TRUST ") + trustRequest +
2360                 " failed with RC: " + trustResult->rc +
2361                 ", Result: " + trustResult->result;
2362 
2363             return STAFResultPtr(
2364                 new STAFResult(trustResult->rc, errorMsg),
2365                 STAFResultPtr::INIT);
2366         }
2367 
2368         try
2369         {
2370             unsigned int trustLevel = trustResult->result.asUInt();
2371 
2372             VALIDATE_TRUST3(2, pData->fShortName, "LIST",
2373                             pData->fLocalMachineName, trustLevel,
2374                             parsedResult->optionValue(sRMTMACHINE), "",
2375                             parsedResult->optionValue(sRMTUSER));
2376         }
2377         catch (STAFException)
2378         {
2379             STAFString errorMsg = STAFString(
2380                 "Verifying that the remote log machine/user has at least "
2381                 "trust level 2 failed.  STAF local TRUST ") + trustRequest +
2382                 " did not return a numeric trust level, Result: " +
2383                 trustResult->result;
2384 
2385             return STAFResultPtr(
2386                 new STAFResult(kSTAFAccessDenied, errorMsg),
2387                 STAFResultPtr::INIT);
2388         }
2389     }
2390 
2391     // Create the marshalling context
2392 
2393     STAFObjectPtr mc = STAFObject::createMarshallingContext();
2394 
2395     // Generate output based on the LIST options specified
2396 
2397     if (parsedResult->optionTimes(sSETTINGS) != 0)
2398     {
2399         STAFString result;
2400 
2401         if (pData->fRLogMode != 0)
2402         {
2403             // Create a map object for the remote log settings
2404 
2405             STAFObjectPtr listRemoteSettingsMap =
2406                 pData->fListRemoteSettingsClass->createInstance();
2407 
2408             listRemoteSettingsMap->put("loggingMode", "Remote");
2409             listRemoteSettingsMap->put("remoteLogServer",
2410                                        pData->fRemoteLogServer);
2411             listRemoteSettingsMap->put("remoteLogService",
2412                                        pData->fRemoteLogService);
2413 
2414             // Set marshalling context map class definitions and root object
2415 
2416             mc->setMapClassDefinition(
2417                 pData->fListRemoteSettingsClass->reference());
2418             mc->setRootObject(listRemoteSettingsMap);
2419 
2420             result = mc->marshall();
2421         }
2422         else
2423         {
2424             // Create a map object for the local log settings
2425 
2426             STAFObjectPtr listLocalSettingsMap =
2427                 pData->fListLocalSettingsClass->createInstance();
2428 
2429             listLocalSettingsMap->put("loggingMode", "Local");
2430             listLocalSettingsMap->put("directory", pData->fRoot);
2431             listLocalSettingsMap->put(
2432                 "maxRecordSize", STAFString(pData->fMaxRecordSize));
2433             listLocalSettingsMap->put(
2434                 "defaultMaxQueryRecords",
2435                 STAFString(pData->fDefaultMaxQueryRecords));
2436 
2437             if (pData->fDefaultResolveMessage != 0)
2438                 listLocalSettingsMap->put("resolveMessage", "Enabled");
2439             else
2440                 listLocalSettingsMap->put("resolveMessage", "Disabled");
2441 
2442             if (pData->fUseResolveMessageVar != 0)
2443                 listLocalSettingsMap->put("resolveMessageVar", "Enabled");
2444             else
2445                 listLocalSettingsMap->put("resolveMessageVar", "Disabled");
2446 
2447             // Set marshalling context map class definitions and root object
2448 
2449             mc->setMapClassDefinition(
2450                 pData->fListLocalSettingsClass->reference());
2451             mc->setRootObject(listLocalSettingsMap);
2452 
2453             result = mc->marshall();
2454         }
2455 
2456         return STAFResultPtr(new STAFResult(kSTAFOk, result),
2457                              STAFResultPtr::INIT);
2458     }
2459 
2460     STAFFSPath path;
2461     STAFFSEntryType_t entryType = kSTAFFSFile;
2462     STAFString extPattern = kUTF8_STAR;
2463     unsigned int globalTimes = parsedResult->optionTimes(sGLOBAL);
2464     unsigned int machinesTimes = parsedResult->optionTimes(sMACHINES);
2465     unsigned int machineTimes = parsedResult->optionTimes(sMACHINE);
2466     unsigned int handlesTimes = parsedResult->optionTimes(sHANDLES);
2467     unsigned int handleTimes = parsedResult->optionTimes(sHANDLE);
2468 
2469     path.setRoot(pData->fRoot);
2470 
2471     if (globalTimes != 0)
2472     {
2473         path.addDir(sGLOBAL);
2474         extPattern = sLogExt;
2475     }
2476     else if (machinesTimes != 0)
2477     {
2478         entryType = kSTAFFSDirectory;
2479         path.addDir(sMACHINE);
2480     }
2481     else  // MACHINE was specified
2482     {
2483         STAFResultPtr machineValueResult = resolveOp(pInfo, pData, parsedResult,
2484                                                      sMACHINE);
2485 
2486         if (machineValueResult->rc != kSTAFOk) return machineValueResult;
2487 
2488         path.addDir(sMACHINE);
2489         path.addDir(machineValueResult->result);
2490 
2491         if (handlesTimes != 0)
2492         {
2493             entryType = kSTAFFSDirectory;
2494             path.addDir(sHANDLE);
2495         }
2496         else if (handleTimes != 0)
2497         {
2498             STAFResultPtr handleValueResult = resolveOp(pInfo, pData,
2499                                                         parsedResult, sHANDLE);
2500 
2501             if (handleValueResult->rc != kSTAFOk) return handleValueResult;
2502 
2503             path.addDir(sHANDLE);
2504             path.addDir(handleValueResult->result);
2505             extPattern = sLogExt;
2506         }
2507         else  // Only MACHINE was specified
2508         {
2509             path.addDir(sGLOBAL);
2510             extPattern = sLogExt;
2511         }
2512     }
2513 
2514     // Set marshalling context map class definitions
2515 
2516     mc->setMapClassDefinition(pData->fListLogsClass->reference());
2517 
2518     // Create a empty list object for the marshalled list of logs, machines,
2519     // or handles
2520 
2521     STAFObjectPtr outputList = STAFObject::createList();
2522 
2523     if (path.exists())
2524     {
2525         STAFFSEntryPtr dirEntry;
2526 
2527         try
2528         {
2529             dirEntry = path.getEntry();
2530         }
2531         catch (STAFException &e)
2532         {
2533             STAFString msg = "STAFLogService::handleList: Error getting "
2534                 "entry for directory " + path.asString();
2535             STAFString result = getExceptionString(
2536                 e, msg.toCurrentCodePage()->buffer()).adoptImpl();
2537 
2538             return STAFResultPtr(new STAFResult(kSTAFFileOpenError, result),
2539                                  STAFResultPtr::INIT);
2540         }
2541 
2542         STAFFSEnumPtr dirEnum = dirEntry->enumerate(
2543             kUTF8_STAR, extPattern, entryType);
2544 
2545         for (; dirEnum->isValid(); dirEnum->next())
2546         {
2547             STAFFSEntryPtr entry = dirEnum->entry();
2548             STAFString data;
2549 
2550             if (machinesTimes || handlesTimes)
2551             {
2552                 // Don't strip of the extension, because it could be
2553                 // part of the machine name if using long names
2554 
2555                 outputList->append(
2556                     entry->path().setRoot().clearDirList().asString());
2557             }
2558             else
2559             {
2560                 STAFObjectPtr logMap = pData->fListLogsClass->createInstance();
2561 
2562                 logMap->put("logName",
2563                 entry->path().setRoot().setExtension()
2564                        .clearDirList().asString());
2565                 logMap->put("timestamp", entry->modTime().asString());
2566                 logMap->put("upperSize", entry->size().first);
2567                 logMap->put("size", entry->size().second);
2568 
2569                 outputList->append(logMap);
2570             }
2571         }
2572     }
2573 
2574     // Set the root object for the marshalling context
2575 
2576     mc->setRootObject(outputList);
2577 
2578     // Set the result to the marshalled output for a list of log records
2579 
2580     return STAFResultPtr(new STAFResult(kSTAFOk, mc->marshall()),
2581                          STAFResultPtr::INIT);
2582 }
2583 
2584 
handleDelete(STAFServiceRequestLevel30 * pInfo,LogServiceData * pData)2585 STAFResultPtr handleDelete(STAFServiceRequestLevel30 *pInfo,
2586                            LogServiceData *pData)
2587 {
2588     STAFCommandParseResultPtr parsedResult =
2589         pData->fDeleteParser->parse(pInfo->request);
2590 
2591     if (parsedResult->rc != kSTAFOk)
2592     {
2593         return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString,
2594                              parsedResult->errorBuffer), STAFResultPtr::INIT);
2595     }
2596 
2597     // Verify the requesting machine/user has at least trust level 4
2598 
2599     if (parsedResult->optionTimes(sRMTMACHINE) == 0)
2600     {
2601         VALIDATE_TRUST(4, pData->fShortName, "DELETE",
2602                        pData->fLocalMachineName);
2603     }
2604     else
2605     {
2606         // Verify the remote log machine/user has at least trust level 4
2607 
2608         STAFString trustRequest(
2609             sGetMachine + parsedResult->optionValue(sRMTMACHINE) +
2610             sGetUser + parsedResult->optionValue(sRMTUSER));
2611 
2612         STAFResultPtr trustResult = pData->fHandle->submit(
2613             sLocal, sTrust, trustRequest);
2614 
2615         if (trustResult->rc != kSTAFOk)
2616         {
2617             STAFString errorMsg = STAFString(
2618                 "Verifying that the remote log machine/user has at least "
2619                 "trust level 4 failed.  STAF local TRUST ") + trustRequest +
2620                 " failed with RC: " + trustResult->rc +
2621                 ", Result: " + trustResult->result;
2622 
2623             return STAFResultPtr(
2624                 new STAFResult(trustResult->rc, errorMsg),
2625                 STAFResultPtr::INIT);
2626         }
2627 
2628         try
2629         {
2630             unsigned int trustLevel = trustResult->result.asUInt();
2631 
2632             VALIDATE_TRUST3(4, pData->fShortName, "DELETE",
2633                             pData->fLocalMachineName, trustLevel,
2634                             parsedResult->optionValue(sRMTMACHINE), "",
2635                             parsedResult->optionValue(sRMTUSER));
2636         }
2637         catch (STAFException)
2638         {
2639             STAFString errorMsg = STAFString(
2640                 "Verifying that the remote log machine/user has at least "
2641                 "trust level 4 failed.  STAF local TRUST ") + trustRequest +
2642                 " did not return a numeric trust level, Result: " +
2643                 trustResult->result;
2644 
2645             return STAFResultPtr(
2646                 new STAFResult(kSTAFAccessDenied, errorMsg),
2647                 STAFResultPtr::INIT);
2648         }
2649     }
2650 
2651     STAFFSPath logfilePath;
2652     STAFResultPtr errorResult;
2653 
2654     if (!generateQueryPurgeDeleteLogFilePath(logfilePath, errorResult,
2655                                              pInfo, pData, parsedResult))
2656     {
2657         return errorResult;
2658     }
2659 
2660     if (!logfilePath.exists())
2661     {
2662         return STAFResultPtr(new STAFResult(kSTAFDoesNotExist,
2663                                             logfilePath.name()),
2664                              STAFResultPtr::INIT);
2665     }
2666 
2667     STAFFSEntryPtr logfileEntry;
2668 
2669     try
2670     {
2671         logfileEntry = logfilePath.getEntry();
2672     }
2673     catch (STAFException &e)
2674     {
2675         STAFString msg = "STAFLogService::handleDelete: Error getting "
2676             "entry for logfile " + logfilePath.asString();
2677         STAFString result = getExceptionString(
2678             e, msg.toCurrentCodePage()->buffer()).adoptImpl();
2679 
2680         return STAFResultPtr(new STAFResult(kSTAFFileDeleteError, result),
2681                              STAFResultPtr::INIT);
2682     }
2683 
2684     // Get a write lock on the global Read/Write Semaphore
2685 
2686     STAFLogFileLocksPtr logLocks =
2687         STAFLogFileLocks::acquireLocks(logfilePath.asString());
2688     STAFRWSemWLock accessLock(*logLocks->logAccess);
2689 
2690     logfileEntry->remove();
2691 
2692     return STAFResultPtr(new STAFResult, STAFResultPtr::INIT);
2693 }
2694 
2695 
handlePurge(STAFServiceRequestLevel30 * pInfo,LogServiceData * pData)2696 STAFResultPtr handlePurge(STAFServiceRequestLevel30 *pInfo, LogServiceData *pData)
2697 {
2698     STAFCommandParseResultPtr parsedResult =
2699         pData->fPurgeParser->parse(pInfo->request);
2700 
2701     if (parsedResult->rc != kSTAFOk)
2702     {
2703         return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString,
2704                              parsedResult->errorBuffer), STAFResultPtr::INIT);
2705     }
2706 
2707     // Verify that the requesting machine/user has at least trust level 4
2708 
2709     if (parsedResult->optionTimes(sRMTMACHINE) == 0)
2710     {
2711         VALIDATE_TRUST(4, pData->fShortName, "PURGE", pData->fLocalMachineName);
2712     }
2713     else
2714     {
2715         // Verify that the remote log machine/user has at least trust level 4
2716 
2717         STAFString trustRequest(
2718             sGetMachine + parsedResult->optionValue(sRMTMACHINE) +
2719             sGetUser + parsedResult->optionValue(sRMTUSER));
2720 
2721         STAFResultPtr trustResult = pData->fHandle->submit(
2722             sLocal, sTrust, trustRequest);
2723 
2724         if (trustResult->rc != kSTAFOk)
2725         {
2726             STAFString errorMsg = STAFString(
2727                 "Verifying that the remote log machine/user has at least "
2728                 "trust level 4 failed.  STAF local TRUST ") + trustRequest +
2729                 " failed with RC: " + trustResult->rc +
2730                 ", Result: " + trustResult->result;
2731 
2732             return STAFResultPtr(
2733                 new STAFResult(trustResult->rc, errorMsg),
2734                 STAFResultPtr::INIT);
2735         }
2736 
2737         try
2738         {
2739             unsigned int trustLevel = trustResult->result.asUInt();
2740 
2741             VALIDATE_TRUST3(4, pData->fShortName, "PURGE",
2742                             pData->fLocalMachineName, trustLevel,
2743                             parsedResult->optionValue(sRMTMACHINE), "",
2744                             parsedResult->optionValue(sRMTUSER));
2745         }
2746         catch (STAFException)
2747         {
2748             STAFString errorMsg = STAFString(
2749                 "Verifying that the remote log machine/user has at least "
2750                 "trust level 4 failed.  STAF local TRUST ") + trustRequest +
2751                 " did not return a numeric trust level, Result: " +
2752                 trustResult->result;
2753 
2754             return STAFResultPtr(
2755                 new STAFResult(kSTAFAccessDenied, errorMsg),
2756                 STAFResultPtr::INIT);
2757         }
2758     }
2759 
2760     // See if they specified the CONFIRMALL option
2761 
2762     bool confirmAll = false;
2763 
2764     if (parsedResult->optionTimes(sCONFIRMALL) != 0)
2765     {
2766         confirmAll = true;
2767     }
2768 
2769     // Build up the log filter criteria
2770 
2771     STAFResultPtr errorResult;
2772     LogRecordFilter logFilter;
2773     LogStats logStats = { 0 };
2774 
2775     if (!updateQueryPurgeLogFilter(logFilter, errorResult, pInfo, pData,
2776                                    parsedResult))
2777     {
2778         return errorResult;
2779     }
2780 
2781     unsigned int first = 0;
2782     unsigned int last = 0;
2783     STAFResultPtr result;
2784 
2785     if (parsedResult->optionTimes(sFIRST) != 0)
2786     {
2787         // Resolve any STAF variables in the FIRST option value
2788 
2789         result = resolveOp(pInfo, pData, parsedResult, sFIRST);
2790 
2791         if (result->rc != kSTAFOk) return result;
2792 
2793         // Convert resolved option string to an unsigned integer in range
2794         // 0 to UINT_MAX
2795 
2796         result = convertOptionStringToUInt(result->result, sFIRST, first);
2797 
2798         if (result->rc != kSTAFOk) return result;
2799     }
2800     else if (parsedResult->optionTimes(sLAST) != 0)
2801     {
2802         // Resolve any STAF varaibles in the LAST option value
2803 
2804         result = resolveOp(pInfo, pData, parsedResult, sLAST);
2805 
2806         if (result->rc != kSTAFOk) return result;
2807 
2808         // Convert resolved option string to an unsigned integer in range
2809         // 0 to UINT_MAX
2810 
2811         result = convertOptionStringToUInt(result->result, sLAST, last);
2812 
2813         if (result->rc != kSTAFOk) return result;
2814     }
2815 
2816     bool useFromRecord = false;
2817     unsigned int fromRecord = 0;
2818     bool useToRecord = false;
2819     unsigned int toRecord = 0;
2820 
2821     if (parsedResult->optionTimes(sFROMRECORD) != 0)
2822     {
2823         result = resolveOp(pInfo, pData, parsedResult, sFROMRECORD);
2824 
2825         if (result->rc != kSTAFOk) return result;
2826 
2827         // Convert resolved option string to an unsigned integer in range
2828         // 1 to UINT_MAX
2829 
2830         result = convertOptionStringToUInt(
2831             result->result, sFROMRECORD, fromRecord, 1);
2832 
2833         if (result->rc != kSTAFOk) return result;
2834 
2835         useFromRecord = true;
2836     }
2837 
2838     if (parsedResult->optionTimes(sTORECORD) != 0)
2839     {
2840         result = resolveOp(pInfo, pData, parsedResult, sTORECORD);
2841 
2842         if (result->rc != kSTAFOk) return result;
2843 
2844         // Convert resolved option string to an unsigned integer in range
2845         // 1 to UINT_MAX
2846 
2847         result = convertOptionStringToUInt(
2848             result->result, sTORECORD, toRecord, 1);
2849 
2850         if (result->rc != kSTAFOk) return result;
2851 
2852         useToRecord = true;
2853     }
2854 
2855     if (useToRecord && useFromRecord && (fromRecord > toRecord))
2856     {
2857         STAFString errorMsg = STAFString("FROMRECORD value must be <= ") +
2858             "TORECORD value.  FROMRECORD: " + STAFString(fromRecord) +
2859             ", TORECORD: " + STAFString(toRecord);
2860         return STAFResultPtr(new STAFResult(kSTAFInvalidValue, errorMsg),
2861                              STAFResultPtr::INIT);
2862     }
2863 
2864     // Get the log file path
2865 
2866     STAFFSPath logfilePath;
2867 
2868     if (!generateQueryPurgeDeleteLogFilePath(logfilePath, errorResult,
2869                                              pInfo, pData, parsedResult))
2870     {
2871         return errorResult;
2872     }
2873 
2874     // See if the log file exists
2875 
2876     if (!logfilePath.exists())
2877     {
2878         return STAFResultPtr(new STAFResult(kSTAFDoesNotExist,
2879                                             logfilePath.name()),
2880                              STAFResultPtr::INIT);
2881     }
2882 
2883     STAFFSEntryPtr logfileEntry;
2884 
2885     try
2886     {
2887         logfileEntry = logfilePath.getEntry();
2888     }
2889     catch (STAFException &e)
2890     {
2891         STAFString msg = "STAFLogService::handlePurge: Error getting "
2892             "entry for logfile " + logfilePath.asString();
2893         STAFString result = getExceptionString(
2894             e, msg.toCurrentCodePage()->buffer()).adoptImpl();
2895 
2896         return STAFResultPtr(new STAFResult(kSTAFFileOpenError, result),
2897                              STAFResultPtr::INIT);
2898     }
2899 
2900     // Get a write lock on the global Read/Write Semaphore
2901 
2902     STAFLogFileLocksPtr logLocks =
2903         STAFLogFileLocks::acquireLocks(logfilePath.asString());
2904     STAFRWSemWLock accessLock(*logLocks->logAccess);
2905 
2906     // Now copy the log file to a temporary file
2907 
2908     STAFFSPath tempfilePath = logfilePath;
2909 
2910     tempfilePath.setExtension(sTmpExt);
2911 
2912     try
2913     {
2914         logfileEntry->copy(tempfilePath.asString());
2915     }
2916     catch (STAFException &e)
2917     {
2918         STAFString msg = "STAFLogService::handlePurge: Error copying "
2919             "logfile " + logfilePath.asString() + " to temporary file " +
2920             tempfilePath.asString();
2921         STAFString result = getExceptionString(
2922             e, msg.toCurrentCodePage()->buffer()).adoptImpl();
2923 
2924         return STAFResultPtr(new STAFResult(kSTAFFileWriteError, result),
2925                              STAFResultPtr::INIT);
2926     }
2927 
2928     // Open the log file and temporary log file
2929     // Note: Notice the log file is the output file and temporary file is
2930     //       the input file
2931     // Note: We don't need to lock the temporary file since only one PURGE
2932     //       can occur at any given time
2933 
2934     fstream logfile(logfilePath.asString().toCurrentCodePage()->buffer(),
2935                     ios::out | STAF_ios_binary | ios::trunc);
2936 
2937     if (!logfile)
2938     {
2939         return STAFResultPtr(new STAFResult(kSTAFFileOpenError,
2940                                             logfilePath.asString()),
2941                              STAFResultPtr::INIT);
2942     }
2943 
2944 
2945     fstream tempfile(tempfilePath.asString().toCurrentCodePage()->buffer(),
2946                      ios::in | STAF_ios_binary);
2947 
2948     if (!tempfile)
2949     {
2950         return STAFResultPtr(new STAFResult(kSTAFFileOpenError,
2951                                             tempfilePath.asString()),
2952                              STAFResultPtr::INIT);
2953     }
2954 
2955     // Read each record
2956 
2957     unsigned int currFirstRecords = 0;
2958     unsigned int writtenRecords = 0;
2959     LogRecord logRecord;
2960 
2961     // If LAST option is specified, use a FIFO queue to store the last <nnn>
2962     // log records.  A std::queue uses a deque as the default container and
2963     // provides better performance than a list for large LAST values
2964     std::queue<LogRecord> lastLogRecordsQueue;
2965 
2966     // Record number counter (used to compare with fromRecord and toRecord)
2967     unsigned int recordNum = 0;
2968 
2969     while (!tempfile.eof())
2970     {
2971         // First, get the information from the log record
2972 
2973         unsigned int status = readLogRecordFromFile(
2974             tempfile, logRecord, recordNum + 1);
2975 
2976         if (status == kReadLogEndOfFile)
2977         {
2978             // Finish up with whatever needs to be done
2979             continue;
2980         }
2981         else if (status == kReadLogInvalidFormat)
2982         {
2983             // Invalid log record format.  Cannot continue.
2984 
2985             STAFString errorMsg = STAFString(
2986                 "Invalid record format in record number ") + recordNum +
2987                 " with format ID " + logRecord.recordFormatID;
2988 
2989             return STAFResultPtr(
2990                 new STAFResult(kSTAFLogInvalidFileFormat, errorMsg),
2991                 STAFResultPtr::INIT);
2992         }
2993 
2994         recordNum++;
2995 
2996         // Now, make sure this record meets the selection criteria
2997 
2998         bool match = true;
2999 
3000         if (useFromRecord)
3001         {
3002             if (recordNum < fromRecord)
3003             {
3004                 // Ignore this log record
3005                 match = false;
3006             }
3007         }
3008 
3009         if (useToRecord)
3010         {
3011             if (recordNum > toRecord)
3012             {
3013                 match = false;
3014             }
3015         }
3016 
3017         // See if this record meets the selection criteria
3018 
3019         if (!match || (match && !logRecordMatchesFilter(
3020             logRecord, logFilter, pData->fDefaultAuthenticator)))
3021         {
3022             // If it doesn't match then, it isn't purged so we write it to
3023             // the file
3024             writeLogRecordToFile(logfile, logRecord);
3025             ++writtenRecords;
3026         }
3027         else
3028         {
3029             // If it does match, then handle first and last issues
3030             // Note: If first/last is not specified then the record is purged
3031             //       and won't be written
3032 
3033             if (last > 0)
3034             {
3035                 // Make sure we only purge 'last' number of records
3036                 if (lastLogRecordsQueue.size() == last)
3037                 {
3038                     writeLogRecordToFile(logfile, lastLogRecordsQueue.front());
3039                     lastLogRecordsQueue.pop();
3040                     ++writtenRecords;
3041                 }
3042 
3043                 lastLogRecordsQueue.push(logRecord);
3044             }
3045             else if ((first > 0) && (++currFirstRecords > first))
3046             {
3047                 writeLogRecordToFile(logfile, logRecord);
3048                 ++writtenRecords;
3049             }
3050         }
3051     }
3052 
3053     unsigned int totalRecords = recordNum;
3054 
3055     // Make sure we didn't purge the whole file if didn't specify the
3056     // CONFIRMALL option and if there were any records in the log file to
3057     // begin with
3058 
3059     if ((writtenRecords == 0) && (totalRecords > 0) && !confirmAll)
3060     {
3061         // If so, copy the temp file back and return an error
3062 
3063         try
3064         {
3065             tempfilePath.getEntry()->copy(logfilePath.asString());
3066         }
3067         catch (STAFException &e)
3068         {
3069             STAFString msg = "STAFLogService::handlePurge: Error copying "
3070                 "temporary file " + tempfilePath.asString() + " back to "
3071                 "logfile " + logfilePath.asString();
3072             STAFString result = getExceptionString(
3073                 e, msg.toCurrentCodePage()->buffer()).adoptImpl();
3074             return STAFResultPtr(new STAFResult(kSTAFLogPurgeFailure, result),
3075                                  STAFResultPtr::INIT);
3076         }
3077 
3078         STAFString msg = "Your purge criteria selected every record in the "
3079             "log file.  Use CONFIRMALL instead of CONFIRM if you really want "
3080             "to delete every record (or submit a DELETE request).  Or, "
3081             "modify your purge criteria if you don't want to delete every "
3082             "record.";
3083 
3084         return STAFResultPtr(new STAFResult(kSTAFLogPurgeFailure, msg),
3085                      STAFResultPtr::INIT);
3086     }
3087 
3088     // Remove the temporary file
3089     tempfile.close();
3090 
3091     try
3092     {
3093         tempfilePath.getEntry()->remove();
3094     }
3095     catch (STAFException)
3096     {
3097         // Ignore
3098     }
3099 
3100     // Create a map object for the marshalled map of log purge stats
3101 
3102     STAFObjectPtr purgeStatsMap = pData->fPurgeStatsClass->createInstance();
3103 
3104     purgeStatsMap->put("purgedRecords",
3105                      STAFString(totalRecords - writtenRecords));
3106     purgeStatsMap->put("totalRecords", STAFString(totalRecords));
3107 
3108     // Create the marshalling context and set map class definitions and
3109     // its root object
3110 
3111     STAFObjectPtr mc = STAFObject::createMarshallingContext();
3112 
3113     mc->setMapClassDefinition(pData->fPurgeStatsClass->reference());
3114     mc->setRootObject(purgeStatsMap);
3115 
3116     // Set the result to the marshalled output for a map of purge statistics
3117 
3118     return STAFResultPtr(new STAFResult(kSTAFOk, mc->marshall()),
3119                          STAFResultPtr::INIT);
3120 }
3121 
3122 
handleSet(STAFServiceRequestLevel30 * pInfo,LogServiceData * pData)3123 STAFResultPtr handleSet(STAFServiceRequestLevel30 *pInfo, LogServiceData *pData)
3124 {
3125     // Verify that the requesting machine/user has at least trust level 5
3126 
3127     VALIDATE_TRUST(5, pData->fShortName, "SET", pData->fLocalMachineName);
3128 
3129     STAFString result;
3130 
3131     STAFCommandParseResultPtr parsedResult =
3132         pData->fSetParser->parse(pInfo->request);
3133 
3134     if (parsedResult->rc != kSTAFOk)
3135     {
3136         return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString,
3137                              parsedResult->errorBuffer), STAFResultPtr::INIT);
3138     }
3139 
3140     if (parsedResult->optionTimes(sMAXRECORDSIZE) != 0)
3141     {
3142         STAFResultPtr maxResult = resolveOp(pInfo, pData, parsedResult,
3143                                             sMAXRECORDSIZE);
3144 
3145         if (maxResult->rc != kSTAFOk) return maxResult;
3146 
3147         // Convert resolved option string to an unsigned integer in range
3148         // 0 to UINT_MAX
3149 
3150         maxResult = convertOptionStringToUInt(
3151             maxResult->result, sMAXRECORDSIZE, pData->fMaxRecordSize);
3152 
3153         if (maxResult->rc != kSTAFOk) return maxResult;
3154     }
3155 
3156     if (parsedResult->optionTimes(sDEFAULTMAXQUERYRECORDS) != 0)
3157     {
3158         STAFResultPtr maxResult = resolveOp(
3159             pInfo, pData, parsedResult, sDEFAULTMAXQUERYRECORDS);
3160 
3161         if (maxResult->rc != kSTAFOk) return maxResult;
3162 
3163         // Convert resolved option string to an unsigned integer in range
3164         // 0 to UINT_MAX
3165 
3166         maxResult = convertOptionStringToUInt(
3167             maxResult->result, sDEFAULTMAXQUERYRECORDS,
3168             pData->fDefaultMaxQueryRecords);
3169 
3170         if (maxResult->rc != kSTAFOk) return maxResult;
3171     }
3172 
3173     if (parsedResult->optionTimes(sRESOLVEMESSAGE) != 0)
3174     {
3175         pData->fDefaultResolveMessage = 1;
3176     }
3177     else if (parsedResult->optionTimes(sNORESOLVEMESSAGE) != 0)
3178     {
3179         pData->fDefaultResolveMessage = 0;
3180     }
3181 
3182     if (parsedResult->optionTimes(sENABLERESOLVEMESSAGEVAR) != 0)
3183     {
3184         pData->fUseResolveMessageVar = 1;
3185     }
3186     else if (parsedResult->optionTimes(sDISABLERESOLVEMESSAGEVAR) != 0)
3187     {
3188         pData->fUseResolveMessageVar = 0;
3189     }
3190 
3191     return STAFResultPtr(new STAFResult(kSTAFOk), STAFResultPtr::INIT);
3192 }
3193 
3194 
handleHelp(STAFServiceRequestLevel30 * pInfo,LogServiceData * pData)3195 STAFResultPtr handleHelp(STAFServiceRequestLevel30 *pInfo, LogServiceData *pData)
3196 {
3197     // Verify that the requesting machine/user has at least trust level 1
3198 
3199     VALIDATE_TRUST(1, pData->fShortName, "HELP", pData->fLocalMachineName);
3200 
3201     // Return the help information for the service
3202 
3203     return STAFResultPtr(new STAFResult(kSTAFOk, sHelpMsg),
3204                          STAFResultPtr::INIT);
3205 }
3206 
3207 
handleRemoteLog(STAFServiceRequestLevel30 * pInfo,LogServiceData * pData)3208 STAFResultPtr handleRemoteLog(STAFServiceRequestLevel30 *pInfo,
3209                               LogServiceData *pData)
3210 {
3211     // Verify that the requesting machine/user has at least trust level 1 in
3212     // order to perform a remote LOG request
3213 
3214     VALIDATE_TRUST(1, pData->fShortName, "LOG", pData->fLocalMachineName);
3215 
3216     STAFCommandParseResultPtr parsedResult =
3217         pData->fLogParser->parse(pInfo->request);
3218 
3219     if (parsedResult->rc != kSTAFOk)
3220     {
3221         return STAFResultPtr(new STAFResult(kSTAFInvalidRequestString,
3222                              parsedResult->errorBuffer), STAFResultPtr::INIT);
3223     }
3224 
3225     // Get log level and log mask and see if we should log
3226 
3227     STAFResultPtr levelResult = resolveOp(pInfo, pData, parsedResult, sLEVEL);
3228 
3229     if (levelResult->rc != kSTAFOk) return levelResult;
3230 
3231     unsigned int logLevel = 0;
3232 
3233     if (!isValidLogLevel(levelResult->result, logLevel))
3234     {
3235         return STAFResultPtr(new STAFResult(kSTAFLogInvalidLevel,
3236                                             levelResult->result),
3237                              STAFResultPtr::INIT);
3238     }
3239 
3240     STAFResultPtr logmaskResult = resolveStr(pInfo, pData,
3241                                              pData->fResolveLogMaskString);
3242     if ((logmaskResult->rc != kSTAFOk) &&
3243         (logmaskResult->rc != kSTAFVariableDoesNotExist))
3244     {
3245         return logmaskResult;
3246     }
3247 
3248     if (logmaskResult->rc == kSTAFVariableDoesNotExist)
3249         logmaskResult->result = sEverythingLogMask;
3250 
3251     unsigned int logMask = 0;
3252 
3253     if (!convertLogMaskToUInt(logmaskResult->result, logMask))
3254     {
3255         return STAFResultPtr(new STAFResult(kSTAFLogInvalidLevel,
3256                                             logmaskResult->result),
3257                              STAFResultPtr::INIT);
3258     }
3259 
3260     if (!(logLevel & logMask))
3261         return STAFResultPtr(new STAFResult, STAFResultPtr::INIT);
3262 
3263     // Now pass the request on to the remote log server
3264 
3265     STAFString newRequest(pInfo->request);
3266 
3267     newRequest += sSpace;
3268     newRequest += sRMTMACHINE;
3269     newRequest += sSpace;
3270     newRequest += pData->fHandle->wrapData(pInfo->endpoint);
3271     newRequest += sSpace;
3272     newRequest += sRMTNAME;
3273     newRequest += sSpace;
3274     newRequest += pData->fHandle->wrapData(pInfo->handleName);
3275     newRequest += sSpace;
3276     newRequest += sRMTHANDLE;
3277     newRequest += sSpace;
3278     newRequest += STAFString(pInfo->handle);
3279     newRequest += sSpace + sRMTUSER + sSpace;
3280     newRequest += pData->fHandle->wrapData(pInfo->user);
3281     newRequest += sSpace + sRMTMACH + sSpace;
3282     newRequest += pData->fHandle->wrapData(pInfo->machine);
3283     newRequest += sSpace + sRMTNICKNAME + sSpace;
3284     newRequest += pData->fHandle->wrapData(pInfo->machineNickname);
3285 
3286     return pData->fHandle->submit(pData->fRemoteLogServer,
3287                                   pData->fRemoteLogService, newRequest);
3288 }
3289 
3290 
handleRemoteLogGeneral(STAFServiceRequestLevel30 * pInfo,LogServiceData * pData)3291 STAFResultPtr handleRemoteLogGeneral(STAFServiceRequestLevel30 *pInfo,
3292                                      LogServiceData *pData)
3293 {
3294     // Verify that the requesting machine/user has at least trust level 1
3295     // in order to submit a request to the remote log service
3296 
3297     STAFString request = STAFString(pInfo->request).subWord(0, 1).toUpperCase();
3298 
3299     VALIDATE_TRUST(1, pData->fShortName, request, pData->fLocalMachineName);
3300 
3301     // Pass the request on to the remote log server
3302 
3303     STAFString newRequest(pInfo->request);
3304 
3305     newRequest += sSpace;
3306     newRequest += sRMTMACHINE;
3307     newRequest += sSpace;
3308     newRequest += pData->fHandle->wrapData(pInfo->machine);
3309     newRequest += sSpace + sRMTUSER + sSpace;
3310     newRequest += pData->fHandle->wrapData(pInfo->user);
3311 
3312     return pData->fHandle->submit(pData->fRemoteLogServer,
3313                                   pData->fRemoteLogService, newRequest);
3314 }
3315 
3316 
resolveStr(STAFServiceRequestLevel30 * pInfo,LogServiceData * pData,const STAFString & theString)3317 STAFResultPtr resolveStr(STAFServiceRequestLevel30 *pInfo,
3318                          LogServiceData *pData, const STAFString &theString)
3319 {
3320     return pData->fHandle->submit(
3321         sLocal, sVar, sResStrResolve + STAFString(pInfo->requestNumber) +
3322         sString + pData->fHandle->wrapData(theString));
3323 }
3324 
3325 
resolveOp(STAFServiceRequestLevel30 * pInfo,LogServiceData * pData,STAFCommandParseResultPtr & parsedResult,const STAFString & fOption,unsigned int optionIndex)3326 STAFResultPtr resolveOp(STAFServiceRequestLevel30 *pInfo, LogServiceData *pData,
3327                         STAFCommandParseResultPtr &parsedResult,
3328                         const STAFString &fOption, unsigned int optionIndex)
3329 {
3330     // ???: Would const STAFString & work here?
3331     STAFString optionValue = parsedResult->optionValue(fOption, optionIndex);
3332 
3333     if (optionValue.find(sLeftCurly) == STAFString::kNPos)
3334     {
3335         return STAFResultPtr(new STAFResult(kSTAFOk, optionValue),
3336                              STAFResultPtr::INIT);
3337     }
3338 
3339     return resolveStr(pInfo, pData, optionValue);
3340 }
3341 
3342 
resolveOpLocal(LogServiceData * pData,STAFCommandParseResultPtr & parsedResult,const STAFString & fOption,unsigned int optionIndex)3343 STAFResultPtr resolveOpLocal(LogServiceData *pData,
3344                              STAFCommandParseResultPtr &parsedResult,
3345                              const STAFString &fOption,
3346                              unsigned int optionIndex)
3347 {
3348     // ???: Would const STAFString & work here?
3349     STAFString optionValue = parsedResult->optionValue(fOption, optionIndex);
3350 
3351     if (optionValue.find(sLeftCurly) == STAFString::kNPos)
3352     {
3353         return STAFResultPtr(new STAFResult(kSTAFOk, optionValue),
3354                              STAFResultPtr::INIT);
3355     }
3356 
3357     return pData->fHandle->submit(sLocal, sVar, sResStrResolve +
3358                                      sString +
3359                                      pData->fHandle->wrapData(optionValue));
3360 }
3361 
3362 
convertStringToUInt(const STAFString & theString,unsigned int & number,const unsigned int minValue,const unsigned int maxValue)3363 STAFResultPtr convertStringToUInt(const STAFString &theString,
3364                                   unsigned int &number,
3365                                   const unsigned int minValue,
3366                                   const unsigned int maxValue)
3367 {
3368     return convertOptionStringToUInt(theString, "", number,
3369                                      minValue, maxValue);
3370 }
3371 
3372 
convertOptionStringToUInt(const STAFString & theString,const STAFString & optionName,unsigned int & number,const unsigned int minValue,const unsigned int maxValue)3373 STAFResultPtr convertOptionStringToUInt(const STAFString &theString,
3374                                         const STAFString &optionName,
3375                                         unsigned int &number,
3376                                         const unsigned int minValue,
3377                                         const unsigned int maxValue)
3378 {
3379     // Convert an option value to an unsigned integer
3380 
3381     STAFString_t errorBufferT = 0;
3382 
3383     STAFRC_t rc = STAFUtilConvertStringToUInt(
3384         theString.getImpl(), optionName.getImpl(), &number,
3385         &errorBufferT, minValue, maxValue);
3386 
3387     if (rc == kSTAFOk)
3388     {
3389         return STAFResultPtr(new STAFResult(), STAFResultPtr::INIT);
3390     }
3391     else
3392     {
3393         return STAFResultPtr(
3394             new STAFResult(rc, STAFString(errorBufferT, STAFString::kShallow)),
3395             STAFResultPtr::INIT);
3396     }
3397 }
3398 
3399 
isValidLogLevel(const STAFString & levelString,unsigned int & outputLevel)3400 bool isValidLogLevel(const STAFString &levelString, unsigned int &outputLevel)
3401 {
3402     if (levelString.findFirstNotOf(sZeroOne) == STAFString::kNPos)
3403     {
3404         // If we are here, the level string is all zeros and ones
3405         // If the level string has more than 32 characters or has more than
3406         // one "1" then it is invalid
3407 
3408         if (levelString.length(STAFString::kChar) > 32) return false;
3409         if (levelString.count(sOne) != 1) return false;
3410 
3411         unsigned int index = levelString.find(sOne, 0, STAFString::kChar);
3412 
3413         outputLevel = 1;
3414         outputLevel <<= (levelString.length(STAFString::kChar) - index - 1);
3415     }
3416     else
3417     {
3418         if (!convertLogLevelToUInt(levelString, outputLevel)) return false;
3419     }
3420 
3421     if ((outputLevel > 0x00004000) && (outputLevel < 0x01000000)) return false;
3422 
3423     return true;
3424 }
3425 
3426 
3427 // returns true if the level string is understood
3428 // returns false if the level string is bad
3429 
convertLogLevelToUInt(const STAFString & levelString,unsigned int & outputLevel)3430 bool convertLogLevelToUInt(const STAFString &levelString,
3431                            unsigned int &outputLevel)
3432 {
3433     STAFString upperLevel = levelString.toUpperCase();
3434 
3435     if (upperLevel == sFATAL)        outputLevel = 0x00000001;
3436     else if (upperLevel == sERROR)   outputLevel = 0x00000002;
3437     else if (upperLevel == sWARNING) outputLevel = 0x00000004;
3438     else if (upperLevel == sINFO)    outputLevel = 0x00000008;
3439     else if (upperLevel == sTRACE)   outputLevel = 0x00000010;
3440     else if (upperLevel == sTRACE2)  outputLevel = 0x00000020;
3441     else if (upperLevel == sTRACE3)  outputLevel = 0x00000040;
3442     else if (upperLevel == sDEBUG)   outputLevel = 0x00000080;
3443     else if (upperLevel == sDEBUG2)  outputLevel = 0x00000100;
3444     else if (upperLevel == sDEBUG3)  outputLevel = 0x00000200;
3445     else if (upperLevel == sSTART)   outputLevel = 0x00000400;
3446     else if (upperLevel == sSTOP)    outputLevel = 0x00000800;
3447     else if (upperLevel == sPASS)    outputLevel = 0x00001000;
3448     else if (upperLevel == sFAIL)    outputLevel = 0x00002000;
3449     else if (upperLevel == sSTATUS)  outputLevel = 0x00004000;
3450     else if (upperLevel == sUSER1)   outputLevel = 0x01000000;
3451     else if (upperLevel == sUSER2)   outputLevel = 0x02000000;
3452     else if (upperLevel == sUSER3)   outputLevel = 0x04000000;
3453     else if (upperLevel == sUSER4)   outputLevel = 0x08000000;
3454     else if (upperLevel == sUSER5)   outputLevel = 0x10000000;
3455     else if (upperLevel == sUSER6)   outputLevel = 0x20000000;
3456     else if (upperLevel == sUSER7)   outputLevel = 0x40000000;
3457     else if (upperLevel == sUSER8)   outputLevel = 0x80000000;
3458     else return false;
3459 
3460     return true;
3461 }
3462 
3463 
convertLogLevelToString(unsigned int logLevel,bool levelAsBits)3464 STAFString &convertLogLevelToString(unsigned int logLevel, bool levelAsBits)
3465 {
3466     if (logLevel == 0x00000001)
3467         return levelAsBits ? sFATALBits : sFATALPretty;
3468     else if (logLevel == 0x00000002)
3469         return levelAsBits ? sERRORBits : sERRORPretty;
3470     else if (logLevel == 0x00000004)
3471         return levelAsBits ? sWARNINGBits :  sWARNINGPretty;
3472     else if (logLevel == 0x00000008)
3473         return levelAsBits ? sINFOBits : sINFOPretty;
3474     else if (logLevel == 0x00000010)
3475         return levelAsBits ? sTRACEBits : sTRACEPretty;
3476     else if (logLevel == 0x00000020)
3477         return levelAsBits ? sTRACE2Bits : sTRACE2Pretty;
3478     else if (logLevel == 0x00000040)
3479         return levelAsBits ? sTRACE3Bits : sTRACE3Pretty;
3480     else if (logLevel == 0x00000080)
3481         return levelAsBits ? sDEBUGBits : sDEBUGPretty;
3482     else if (logLevel == 0x00000100)
3483         return levelAsBits ? sDEBUG2Bits : sDEBUG2Pretty;
3484     else if (logLevel == 0x00000200)
3485         return levelAsBits ? sDEBUG3Bits : sDEBUG3Pretty;
3486     else if (logLevel == 0x00000400)
3487         return levelAsBits ? sSTARTBits : sSTARTPretty;
3488     else if (logLevel == 0x00000800)
3489         return levelAsBits ? sSTOPBits : sSTOPPretty;
3490     else if (logLevel == 0x00001000)
3491         return levelAsBits ? sPASSBits : sPASSPretty;
3492     else if (logLevel == 0x00002000)
3493         return levelAsBits ? sFAILBits : sFAILPretty;
3494     else if (logLevel == 0x00004000)
3495         return levelAsBits ? sSTATUSBits : sSTATUSPretty;
3496     else if (logLevel == 0x01000000)
3497         return levelAsBits ? sUSER1Bits : sUSER1Pretty;
3498     else if (logLevel == 0x02000000)
3499         return levelAsBits ? sUSER2Bits : sUSER2Pretty;
3500     else if (logLevel == 0x04000000)
3501         return levelAsBits ? sUSER3Bits : sUSER3Pretty;
3502     else if (logLevel == 0x08000000)
3503         return levelAsBits ? sUSER4Bits : sUSER4Pretty;
3504     else if (logLevel == 0x10000000)
3505         return levelAsBits ? sUSER5Bits : sUSER5Pretty;
3506     else if (logLevel == 0x20000000)
3507         return levelAsBits ? sUSER6Bits : sUSER6Pretty;
3508     else if (logLevel == 0x40000000)
3509         return levelAsBits ? sUSER7Bits : sUSER7Pretty;
3510     else if (logLevel == 0x80000000)
3511         return levelAsBits ? sUSER8Bits : sUSER8Pretty;
3512     else
3513         return levelAsBits ? sUNKNOWNBits : sUNKNOWNPretty;
3514 }
3515 
3516 
convertLogMaskToUInt(const STAFString & logmaskString,unsigned int & logmaskOutput)3517 bool convertLogMaskToUInt(const STAFString &logmaskString,
3518                           unsigned int &logmaskOutput)
3519 {
3520     logmaskOutput = 0;
3521 
3522     if (logmaskString.findFirstNotOf(sZeroOne) == STAFString::kNPos)
3523     {
3524         // If we are here, the level string is all zeros and ones
3525         // If the level string has more than 32 characters then it is invalid
3526 
3527         if (logmaskString.length(STAFString::kChar) > 32) return false;
3528 
3529         for (int i = 0; i < logmaskString.length(STAFString::kChar); ++i)
3530         {
3531             if (logmaskString.subString(i, 1, STAFString::kChar) == sOne)
3532             {
3533                 logmaskOutput |=
3534                     1 << (logmaskString.length(STAFString::kChar) - i - 1);
3535             }
3536         }
3537     }
3538     else
3539     {
3540         for (int i = 0; i < logmaskString.numWords(); ++i)
3541         {
3542             unsigned int thisLevel = 0;
3543 
3544             if (convertLogLevelToUInt(logmaskString.subWord(i, 1), thisLevel))
3545                 logmaskOutput |= thisLevel;
3546             else
3547                 return false;
3548         }
3549     }
3550 
3551     return true;
3552 }
3553 
3554 
writeUIntToFile(ostream & output,unsigned int data,unsigned int length)3555 void writeUIntToFile(ostream &output, unsigned int data, unsigned int length)
3556 {
3557     union
3558     {
3559         char bytes[4];
3560         unsigned int uint;
3561     };
3562 
3563     uint = STAFUtilSwapUInt(STAFUtilConvertNativeUIntToLE(data));
3564 
3565     output.write(&bytes[4 - length], length);
3566 }
3567 
3568 
readUIntFromFile(istream & input,unsigned int & data,unsigned int length)3569 void readUIntFromFile(istream &input, unsigned int &data, unsigned int length)
3570 {
3571     union
3572     {
3573         char bytes[4];
3574         unsigned int uint;
3575     };
3576 
3577     uint = 0;
3578 
3579     input.read(&bytes[4 - length], length);
3580 
3581     data = STAFUtilConvertLEUIntToNative(STAFUtilSwapUInt(uint));
3582 }
3583 
3584 
readStringFromFile(istream & input,STAFString & inString)3585 void readStringFromFile(istream &input, STAFString &inString)
3586 {
3587     // First read in the UTF-8 data
3588 
3589     unsigned int stringLength = 0;
3590 
3591     readUIntFromFile(input, stringLength);
3592 
3593     char *inputData = new char[stringLength];
3594 
3595     input.read(inputData, stringLength);
3596 
3597     try
3598     {
3599         inString = STAFString(inputData, stringLength, STAFString::kUTF8);
3600     }
3601     catch(...)
3602     {
3603         delete [] inputData;
3604         throw;
3605     }
3606 
3607     delete [] inputData;
3608 }
3609 
3610 
writeStringToFile(ostream & output,const STAFString & outString)3611 void writeStringToFile(ostream &output, const STAFString &outString)
3612 {
3613     unsigned int stringLength = outString.length();
3614 
3615     writeUIntToFile(output, stringLength);
3616     output.write(outString.buffer(), stringLength);
3617 }
3618 
3619 
3620 // returns true if the logfile path was generated successfully
3621 // returns false (and errorResult is set) if there was an error generating
3622 //     the logfile path
3623 
generateQueryPurgeDeleteLogFilePath(STAFFSPath & logfilePath,STAFResultPtr & errorResult,STAFServiceRequestLevel30 * pInfo,LogServiceData * pData,STAFCommandParseResultPtr & parsedResult)3624 bool generateQueryPurgeDeleteLogFilePath(STAFFSPath &logfilePath,
3625      STAFResultPtr &errorResult, STAFServiceRequestLevel30 *pInfo,
3626      LogServiceData *pData, STAFCommandParseResultPtr &parsedResult)
3627 {
3628     // Get logname
3629 
3630     STAFResultPtr lognameResult = resolveOp(pInfo, pData, parsedResult,
3631                                             sLOGNAME);
3632 
3633     if (lognameResult->rc != kSTAFOk)
3634     {
3635         errorResult = lognameResult;
3636         return false;
3637     }
3638 
3639     // Setup the path
3640 
3641     logfilePath.setRoot(pData->fRoot);
3642 
3643     if (parsedResult->optionTimes(sGLOBAL) != 0)
3644     {
3645         // They specified a GLOBAL log file
3646 
3647         logfilePath.addDir(sGLOBAL);
3648     }
3649     else
3650     {
3651         // They specified at least a MACHINE log file
3652 
3653         STAFResultPtr machineResult = resolveOp(pInfo, pData, parsedResult,
3654                                                 sMACHINE);
3655 
3656         if (machineResult->rc != kSTAFOk)
3657         {
3658             errorResult = machineResult;
3659             return false;
3660         }
3661 
3662         logfilePath.addDir(sMACHINE);
3663         logfilePath.addDir(machineResult->result);
3664 
3665         if (parsedResult->optionTimes(sHANDLE) != 0)
3666         {
3667             // They specified a HANDLE log file
3668 
3669             STAFResultPtr handleResult = resolveOp(pInfo, pData, parsedResult,
3670                                                    sHANDLE);
3671 
3672             if (handleResult->rc != kSTAFOk)
3673             {
3674                 errorResult = handleResult;
3675                 return false;
3676             }
3677 
3678             logfilePath.addDir(sHANDLE);
3679             logfilePath.addDir(handleResult->result);
3680         }
3681         else
3682         {
3683             logfilePath.addDir(sGLOBAL);
3684         }
3685     }
3686 
3687     logfilePath.setName(lognameResult->result);
3688     logfilePath.setExtension(sLogExt);
3689 
3690     return true;
3691 }
3692 
3693 
readLogRecordFromFile(istream & logfile,LogRecord & logRecord,unsigned int recordNum)3694 unsigned int readLogRecordFromFile(istream &logfile, LogRecord &logRecord,
3695                                    unsigned int recordNum)
3696 {
3697     unsigned int totalLength = 0;
3698 
3699     readUIntFromFile(logfile, logRecord.recordFormatID, 1);
3700 
3701     if (logfile.eof()) return kReadLogEndOfFile;
3702 
3703     logRecord.recordNumber = recordNum;
3704 
3705     if (logRecord.recordFormatID == sCurrRecordFormatID)
3706     {
3707         // This format added endpoint to the log record
3708 
3709         readUIntFromFile(logfile, logRecord.date);
3710         readUIntFromFile(logfile, logRecord.secondsPastMidnight, 3);
3711         readUIntFromFile(logfile, logRecord.logLevel);
3712         readUIntFromFile(logfile, logRecord.handle);
3713         readStringFromFile(logfile, logRecord.machine);
3714         readStringFromFile(logfile, logRecord.handleName);
3715         readStringFromFile(logfile, logRecord.user);
3716         readStringFromFile(logfile, logRecord.endpoint);
3717         readStringFromFile(logfile, logRecord.message);
3718     }
3719     else if (logRecord.recordFormatID == 3)
3720     {
3721         // This format added user to the log record for Feature #627135
3722 
3723         readUIntFromFile(logfile, logRecord.date);
3724         readUIntFromFile(logfile, logRecord.secondsPastMidnight, 3);
3725         readUIntFromFile(logfile, logRecord.logLevel);
3726         readUIntFromFile(logfile, logRecord.handle);
3727         readStringFromFile(logfile, logRecord.machine);
3728         readStringFromFile(logfile, logRecord.handleName);
3729         readStringFromFile(logfile, logRecord.user);
3730         readStringFromFile(logfile, logRecord.message);
3731         logRecord.endpoint = "tcp" + sSpecSeparator + logRecord.machine;
3732     }
3733     else if (logRecord.recordFormatID == 2)
3734     {
3735         readUIntFromFile(logfile, logRecord.date);
3736         readUIntFromFile(logfile, logRecord.secondsPastMidnight, 3);
3737         readUIntFromFile(logfile, logRecord.logLevel);
3738         readUIntFromFile(logfile, logRecord.handle);
3739         readStringFromFile(logfile, logRecord.machine);
3740         readStringFromFile(logfile, logRecord.handleName);
3741         readStringFromFile(logfile, logRecord.message);
3742         logRecord.user = sUnauthenticatedUser;
3743         logRecord.endpoint = "tcp" + sSpecSeparator + logRecord.machine;
3744     }
3745     else if (logRecord.recordFormatID == 1)
3746     {
3747         // This is the format used by the last couple of implementations
3748         // of the Log service written in Rexx
3749 
3750         readUIntFromFile(logfile, logRecord.date);
3751         readUIntFromFile(logfile, logRecord.secondsPastMidnight, 3);
3752         readUIntFromFile(logfile, logRecord.logLevel);
3753         readUIntFromFile(logfile, totalLength);
3754 
3755         if (totalLength < 3)
3756         {
3757             // Log record is incomplete
3758             return kReadLogInvalidFormat;
3759         }
3760 
3761         // Get a buffer and read the rest of the data
3762 
3763         STAFRefPtr<char> data = STAFRefPtr<char>(new char[totalLength],
3764                                                  STAFRefPtr<char>::INIT);
3765         logfile.read(data, totalLength);
3766 
3767         STAFString dataString(data, totalLength, STAFString::kCurrent);
3768 
3769         // Find the separation points for the other fields
3770 
3771         unsigned int sepLoc1 = dataString.find(sOldSep);
3772 
3773         if (sepLoc1 == STAFString::kNPos)
3774         {
3775             // Log record is incomplete
3776             return kReadLogInvalidFormat;
3777         }
3778 
3779         unsigned int sepLoc2 = dataString.find(sOldSep, sepLoc1 + 1);
3780 
3781         if (sepLoc2 == STAFString::kNPos)
3782         {
3783             // Log record is incomplete
3784             return kReadLogInvalidFormat;
3785         }
3786 
3787         unsigned int sepLoc3 = dataString.find(sOldSep, sepLoc2 + 1);
3788 
3789         if (sepLoc3 == STAFString::kNPos)
3790         {
3791             // Log record is incomplete
3792             return kReadLogInvalidFormat;
3793         }
3794 
3795         logRecord.machine = dataString.subString(0, sepLoc1);
3796         logRecord.handle = dataString.subString(
3797             sepLoc1 + 1, sepLoc2 - sepLoc1 - 1).asUIntWithDefault(0);
3798         logRecord.handleName = dataString.subString(
3799             sepLoc2 + 1, sepLoc3 - sepLoc2 - 1);
3800 
3801         if ((sepLoc3 + 1) >= dataString.length())
3802         {
3803             // Log record is incomplete
3804             return kReadLogInvalidFormat;
3805         }
3806 
3807         logRecord.message = dataString.subString(sepLoc3 + 1);
3808 
3809         logRecord.user = sUnauthenticatedUser;
3810         logRecord.endpoint = "tcp" + sSpecSeparator + logRecord.machine;
3811     }
3812     else if (logRecord.recordFormatID == 0)
3813     {
3814     	// This means one of two things:
3815     	// 1) The recordFormatID is really 0 which was the format used by the
3816     	//    first few implementations of the LOG service written in Rexx a
3817     	//    long time ago (circa 1999).  This is unlikely.
3818     	// 2) The log record is empty (e.g. incomplete and invalid) and the
3819     	//    format ID defaulted to 0 as it could not be read.
3820     	//    This is the more likely reason.
3821 
3822         readUIntFromFile(logfile, totalLength);
3823 
3824         if (totalLength < 7)
3825         {
3826             // Log record is incomplete
3827             return kReadLogInvalidFormat;
3828         }
3829 
3830         readUIntFromFile(logfile, logRecord.date);
3831         readUIntFromFile(logfile, logRecord.secondsPastMidnight, 3);
3832 
3833         // Remove date and time length from totalLength
3834 
3835         totalLength -= 7;
3836 
3837         // Get a buffer and read the rest of the data
3838 
3839         STAFRefPtr<char> data = STAFRefPtr<char>(new char[totalLength],
3840                                                  STAFRefPtr<char>::INIT);
3841         logfile.read(data, totalLength);
3842 
3843         STAFString dataString(data, totalLength, STAFString::kCurrent);
3844 
3845         // Find the separation points for the other fields
3846 
3847         unsigned int sepLoc1 = dataString.find(sOldSep);
3848 
3849         if (sepLoc1 == STAFString::kNPos)
3850         {
3851             // Log record is incomplete
3852             return kReadLogInvalidFormat;
3853         }
3854 
3855         unsigned int sepLoc2 = dataString.find(sOldSep, sepLoc1 + 1);
3856 
3857         if (sepLoc2 == STAFString::kNPos)
3858         {
3859             // Log record is incomplete
3860             return kReadLogInvalidFormat;
3861         }
3862 
3863         unsigned int sepLoc3 = dataString.find(sOldSep, sepLoc2 + 1);
3864 
3865         if (sepLoc3 == STAFString::kNPos)
3866         {
3867             // Log record is incomplete
3868             return kReadLogInvalidFormat;
3869         }
3870 
3871         logRecord.machine = dataString.subString(0, sepLoc1);
3872         logRecord.handle = dataString.subString(
3873             sepLoc1 + 1, sepLoc2 - sepLoc1 - 1).asUIntWithDefault(0);
3874         logRecord.handleName = dataString.subString(
3875             sepLoc2 + 1, sepLoc3 - sepLoc2 - 1);
3876 
3877         if ((sepLoc3 + 5) >= dataString.length())
3878         {
3879             // Log record is incomplete
3880             return kReadLogInvalidFormat;
3881         }
3882 
3883         logRecord.message = dataString.subString(sepLoc3 + 5);
3884 
3885         logRecord.logLevel = *(reinterpret_cast<unsigned int *>(
3886                                const_cast<char *>(dataString.buffer()
3887                                                   + sepLoc3 + 1)));
3888 
3889         // Fixup log level from Rexx's big-endian to native format
3890 
3891         logRecord.logLevel = STAFUtilConvertLEUIntToNative(
3892             STAFUtilSwapUInt(logRecord.logLevel));
3893 
3894         logRecord.user = sUnauthenticatedUser;
3895         logRecord.endpoint = "tcp" + sSpecSeparator + logRecord.machine;
3896     }
3897     else
3898     {
3899     	// This indicates that the log record has an invalid record format ID
3900         return kReadLogInvalidFormat;
3901     }
3902 
3903     return kReadLogOk;
3904 }
3905 
3906 
writeLogRecordToFile(ostream & logfile,LogRecord & logRecord)3907 void writeLogRecordToFile(ostream &logfile, LogRecord &logRecord)
3908 {
3909     writeUIntToFile(logfile, sCurrRecordFormatID, 1);
3910     writeUIntToFile(logfile, logRecord.date);
3911     writeUIntToFile(logfile, logRecord.secondsPastMidnight, 3);
3912     writeUIntToFile(logfile, logRecord.logLevel);
3913     writeUIntToFile(logfile, logRecord.handle);
3914     writeStringToFile(logfile, logRecord.machine);
3915     writeStringToFile(logfile, logRecord.handleName);
3916     writeStringToFile(logfile, logRecord.user);
3917     writeStringToFile(logfile, logRecord.endpoint);
3918     writeStringToFile(logfile, STAFHandle::maskPrivateData(logRecord.message));
3919 }
3920 
3921 
3922 // Add a log record in a marshalling context as a map to the logList
3923 
addLogRecordToList(STAFObjectPtr & logList,STAFMapClassDefinitionPtr & logRecordClass,const LogRecord & logRecord,bool levelAsBits,bool longFormat)3924 void addLogRecordToList(STAFObjectPtr &logList,
3925                         STAFMapClassDefinitionPtr &logRecordClass,
3926                         const LogRecord &logRecord, bool levelAsBits,
3927                         bool longFormat)
3928 {
3929     unsigned int year = logRecord.date / 10000;
3930     unsigned int month = (logRecord.date % 10000) / 100;
3931     unsigned int day = logRecord.date % 100;
3932     unsigned int hour = logRecord.secondsPastMidnight / 3600;
3933     unsigned int minute = (logRecord.secondsPastMidnight % 3600) / 60;
3934     unsigned int second = logRecord.secondsPastMidnight % 60;
3935 
3936     STAFString timestampString;
3937 
3938     try
3939     {
3940         STAFTimestamp theTimestamp(year, month, day, hour, minute, second);
3941         timestampString = theTimestamp.asString();
3942     }
3943     catch (STAFException)
3944     {
3945         // Instead of returning a STAFTimestamp exception in the output of a
3946         // LOG QUERY request when encountering a log record with an invalid
3947         // timestamp (which isn't very helpful), output "00000000-00:00:00" for
3948         // the timestamp so that valid log records can be displayed.
3949         // Note:  If the system crashed while writing to a log file, the last
3950         // record in the log may be corrupt (e.g. have an invalid timestamp).
3951         timestampString = "00000000-00:00:00";
3952     }
3953 
3954     STAFObjectPtr logRecordMap = logRecordClass->createInstance();
3955 
3956     logRecordMap->put("timestamp", timestampString);
3957     logRecordMap->put("level", convertLogLevelToString(
3958         logRecord.logLevel, levelAsBits));
3959     logRecordMap->put("message", logRecord.message);
3960 
3961     if (longFormat)
3962     {
3963         logRecordMap->put("recordNumber", STAFString(logRecord.recordNumber));
3964         logRecordMap->put("machine", logRecord.machine);
3965         logRecordMap->put("handle", STAFString(logRecord.handle));
3966         logRecordMap->put("handleName", logRecord.handleName);
3967         logRecordMap->put("user", logRecord.user);
3968         logRecordMap->put("endpoint", logRecord.endpoint);
3969     }
3970 
3971     logList->append(logRecordMap);
3972 }
3973 
3974 
printLogRecord(const LogRecord & logRecord)3975 void printLogRecord(const LogRecord &logRecord)
3976 {
3977     cout << "Record #: " << logRecord.recordNumber
3978          << ", Record ID: " << logRecord.recordFormatID
3979          << ", Date: " << logRecord.date
3980          << ", Seconds: " << logRecord.secondsPastMidnight
3981          << ", Level: 0x" << hex << logRecord.logLevel << dec << endl
3982          << "Machine: " << logRecord.machine
3983          << ", HandleName: " << logRecord.handleName
3984          << " ,Handle: " << logRecord.handle
3985          << ", User: " << logRecord.user
3986          << ", Endpoint: " << logRecord.endpoint
3987          << endl << "Message: " << logRecord.message << endl << endl;
3988 }
3989 
3990 
logRecordMatchesFilter(const LogRecord & logRecord,const LogRecordFilter & logFilter,const STAFString & defaultAuthenticator)3991 bool logRecordMatchesFilter(const LogRecord &logRecord,
3992                             const LogRecordFilter &logFilter,
3993                             const STAFString &defaultAuthenticator)
3994 {
3995     // Check if the record matches the specified date(s)
3996 
3997     if (logFilter.useFrom &&
3998         ((logRecord.date < logFilter.fromTimestamp.date) ||
3999          ((logRecord.date == logFilter.fromTimestamp.date) &&
4000           (logRecord.secondsPastMidnight < logFilter.fromTimestamp.seconds))))
4001     {
4002         return false;
4003     }
4004 
4005     if (logFilter.useAfter &&
4006         ((logRecord.date < logFilter.afterTimestamp.date) ||
4007          ((logRecord.date == logFilter.afterTimestamp.date) &&
4008           (logRecord.secondsPastMidnight <= logFilter.afterTimestamp.seconds))))
4009     {
4010         return false;
4011     }
4012 
4013     if (logFilter.useBefore &&
4014         ((logRecord.date > logFilter.beforeTimestamp.date) ||
4015          ((logRecord.date == logFilter.beforeTimestamp.date) &&
4016           (logRecord.secondsPastMidnight >= logFilter.beforeTimestamp.seconds))))
4017     {
4018         return false;
4019     }
4020 
4021     if (logFilter.useTo &&
4022         ((logRecord.date > logFilter.toTimestamp.date) ||
4023          ((logRecord.date == logFilter.toTimestamp.date) &&
4024           (logRecord.secondsPastMidnight > logFilter.toTimestamp.seconds))))
4025     {
4026         return false;
4027     }
4028 
4029     if (logFilter.useLevelMask && !(logFilter.levelMask & logRecord.logLevel))
4030         return false;
4031 
4032     // Check if the record matches at least one of the specified QMACHINE(s)
4033 
4034     StringList::const_iterator stringIter;
4035     bool foundMatch = false;
4036 
4037     for (stringIter = logFilter.qMachines.begin();
4038          !foundMatch && (stringIter != logFilter.qMachines.end()); ++stringIter)
4039     {
4040         if (logRecord.machine.isEqualTo(*stringIter,
4041                                         kSTAFStringCaseInsensitive))
4042         {
4043             foundMatch = true;
4044         }
4045     }
4046 
4047     if ((logFilter.qMachines.size() != 0) && !foundMatch)
4048         return false;
4049 
4050     // Check if the record matches at least one of ths specified handle NAME(s)
4051 
4052     foundMatch = false;
4053 
4054     for (stringIter = logFilter.names.begin();
4055          !foundMatch && (stringIter != logFilter.names.end()); ++stringIter)
4056     {
4057         if (logRecord.handleName.isEqualTo(*stringIter,
4058                                            kSTAFStringCaseInsensitive))
4059         {
4060             foundMatch = true;
4061         }
4062     }
4063 
4064     if ((logFilter.names.size() != 0) && !foundMatch)
4065         return false;
4066 
4067     // Check if the record matches at least one of the specified ENDPOINT(s)
4068 
4069     foundMatch = false;
4070 
4071     for (stringIter = logFilter.endpoints.begin();
4072          !foundMatch && (stringIter != logFilter.endpoints.end());
4073          ++stringIter)
4074     {
4075         if (logRecord.endpoint.isEqualTo(*stringIter,
4076                                          kSTAFStringCaseInsensitive))
4077         {
4078             foundMatch = true;
4079         }
4080     }
4081 
4082     if ((logFilter.endpoints.size() != 0) && !foundMatch)
4083         return false;
4084 
4085     /*  XXX: This used to do a case-insensitive match on authenticator
4086              and a case-sensitive match on user identifer and match
4087              using wildcards.  We decided to remove this until we came
4088              up with a more generic matching scheme to use for all
4089              STAF requests that also allows some sort of escaping in
4090              case someone really wanted to match on a * or ? characater
4091 
4092     // Change authenticator in logRecord's user to lower-case
4093 
4094     STAFString lowerLogRecordUser = logRecord.user;
4095 
4096     unsigned int sepIndex = lowerLogRecordUser.find(sSpecSeparator);
4097 
4098     if (sepIndex != STAFString::kNPos)
4099     {
4100         lowerLogRecordUser =
4101            logRecord.user.subString(0, sepIndex).toLowerCase() +
4102            logRecord.user.subString(sepIndex);
4103     }
4104 
4105     // Check if the record matches at least one USER option
4106 
4107     foundMatch = false;
4108 
4109     for (stringIter = logFilter.users.begin();
4110          !foundMatch && (stringIter != logFilter.users.end()); ++stringIter)
4111     {
4112         STAFString lowerUser = *stringIter;
4113 
4114         // Check if authenticator was specified in the user value
4115 
4116         sepIndex = lowerUser.find(sSpecSeparator);
4117 
4118         if (sepIndex == STAFString::kNPos)
4119         {
4120             // No authenticator specified - get default authenticator
4121             // and change authenticator to lower-case
4122             lowerUser = defaultAuthenticator.toLowerCase() + sSpecSeparator +
4123                         lowerUser;
4124         }
4125         else
4126         {
4127             // User specified in form of Authenticator://UserIdentifier
4128             // Change authenticator to lower-case.
4129             lowerUser = lowerUser.subString(0, sepIndex).toLowerCase() +
4130                         lowerUser.subString(sepIndex);
4131         }
4132 
4133         if (lowerLogRecordUser.matchesWildcards(lowerUser))
4134             foundMatch = true;
4135     }
4136     */
4137 
4138     // Check if the record matches at least one of the specified USER(s)
4139 
4140     foundMatch = false;
4141 
4142     for (stringIter = logFilter.users.begin();
4143          !foundMatch && (stringIter != logFilter.users.end());
4144          ++stringIter)
4145     {
4146         if (logRecord.user.isEqualTo(*stringIter,
4147                                      kSTAFStringCaseInsensitive))
4148         {
4149             foundMatch = true;
4150         }
4151     }
4152 
4153     if ((logFilter.users.size() != 0) && !foundMatch)
4154         return false;
4155 
4156     // Check if matches at least one CONTAINS option
4157 
4158     STAFString lowerMessage = logRecord.message.toLowerCase();
4159     foundMatch = false;
4160 
4161     for (stringIter = logFilter.contains.begin();
4162          !foundMatch && (stringIter != logFilter.contains.end()); ++stringIter)
4163     {
4164         if (lowerMessage.find(*stringIter) != STAFString::kNPos)
4165             foundMatch = true;
4166     }
4167 
4168     if ((logFilter.contains.size() != 0) && !foundMatch)
4169         return false;
4170 
4171     // Check if matches at least one CSCONTAINS option
4172 
4173     STAFString message = logRecord.message;
4174     foundMatch = false;
4175 
4176     for (stringIter = logFilter.cscontains.begin();
4177          !foundMatch && (stringIter != logFilter.cscontains.end()); ++stringIter)
4178     {
4179         if (message.find(*stringIter) != STAFString::kNPos)
4180             foundMatch = true;
4181     }
4182 
4183     if ((logFilter.cscontains.size() != 0) && !foundMatch)
4184         return false;
4185 
4186     // Check if matches at least one STARTSWITH or CSSTARTSWITH option
4187 
4188     foundMatch = false;
4189 
4190     for (stringIter = logFilter.startswith.begin();
4191          !foundMatch && (stringIter != logFilter.startswith.end());
4192          ++stringIter)
4193     {
4194         if (lowerMessage.find(*stringIter) == 0)
4195             foundMatch = true;
4196     }
4197 
4198     for (stringIter = logFilter.csstartswith.begin();
4199          !foundMatch && (stringIter != logFilter.csstartswith.end());
4200          ++stringIter)
4201     {
4202         if (message.find(*stringIter) == 0)
4203             foundMatch = true;
4204     }
4205 
4206     if ((logFilter.startswith.size() != 0 || logFilter.csstartswith.size() != 0)
4207         && !foundMatch)
4208         return false;
4209 
4210     // Check if matches at least one QHANDLE option
4211 
4212     foundMatch = false;
4213 
4214     for (HandleList::const_iterator hIter = logFilter.qHandles.begin();
4215          !foundMatch && (hIter != logFilter.qHandles.end()); ++hIter)
4216     {
4217       if (*hIter == logRecord.handle)
4218           foundMatch = true;
4219     }
4220 
4221     if ((logFilter.qHandles.size() != 0) && !foundMatch)
4222         return false;
4223 
4224     return true;
4225 }
4226 
4227 
4228 // returns true if the log filter was updated successfully
4229 // returns false (and result is set) if there was an error updating
4230 //         the log filter
4231 
updateQueryPurgeLogFilter(LogRecordFilter & logFilter,STAFResultPtr & result,STAFServiceRequestLevel30 * pInfo,LogServiceData * pData,STAFCommandParseResultPtr & parsedResult)4232 bool updateQueryPurgeLogFilter(LogRecordFilter &logFilter,
4233      STAFResultPtr &result, STAFServiceRequestLevel30 *pInfo,
4234      LogServiceData *pData, STAFCommandParseResultPtr &parsedResult)
4235 {
4236     int i = 0;
4237 
4238     for (i = 1; i <= parsedResult->optionTimes(sCONTAINS); ++i)
4239     {
4240         result = resolveOp(pInfo, pData, parsedResult, sCONTAINS, i);
4241 
4242         if (result->rc != kSTAFOk) return false;
4243 
4244         logFilter.contains.push_back(result->result.toLowerCase());
4245     }
4246 
4247     for (i = 1; i <= parsedResult->optionTimes(sCSCONTAINS); ++i)
4248     {
4249         result = resolveOp(pInfo, pData, parsedResult, sCSCONTAINS, i);
4250 
4251         if (result->rc != kSTAFOk) return false;
4252 
4253         logFilter.cscontains.push_back(result->result);
4254     }
4255 
4256     for (i = 1; i <= parsedResult->optionTimes(sSTARTSWITH); ++i)
4257     {
4258         result = resolveOp(pInfo, pData, parsedResult, sSTARTSWITH, i);
4259 
4260         if (result->rc != kSTAFOk) return false;
4261 
4262         logFilter.startswith.push_back(result->result.toLowerCase());
4263     }
4264 
4265     for (i = 1; i <= parsedResult->optionTimes(sCSSTARTSWITH); ++i)
4266     {
4267         result = resolveOp(pInfo, pData, parsedResult, sCSSTARTSWITH, i);
4268 
4269         if (result->rc != kSTAFOk) return false;
4270 
4271         logFilter.csstartswith.push_back(result->result);
4272     }
4273 
4274     for (i = 1; i <= parsedResult->optionTimes(sQMACHINE); ++i)
4275     {
4276         result = resolveOp(pInfo, pData, parsedResult, sQMACHINE, i);
4277 
4278         if (result->rc != kSTAFOk) return false;
4279 
4280         logFilter.qMachines.push_back(result->result);
4281     }
4282 
4283     for (i = 1; i <= parsedResult->optionTimes(sNAME); ++i)
4284     {
4285         result = resolveOp(pInfo, pData, parsedResult, sNAME, i);
4286 
4287         if (result->rc != kSTAFOk) return false;
4288 
4289         logFilter.names.push_back(result->result);
4290     }
4291 
4292     for (i = 1; i <= parsedResult->optionTimes(sUSER); ++i)
4293     {
4294         result = resolveOp(pInfo, pData, parsedResult, sUSER, i);
4295 
4296         if (result->rc != kSTAFOk) return false;
4297 
4298         logFilter.users.push_back(result->result);
4299     }
4300 
4301     for (i = 1; i <= parsedResult->optionTimes(sENDPOINT); ++i)
4302     {
4303         result = resolveOp(pInfo, pData, parsedResult, sENDPOINT, i);
4304 
4305         if (result->rc != kSTAFOk) return false;
4306 
4307         logFilter.endpoints.push_back(result->result);
4308     }
4309 
4310     for (i = 1; i <= parsedResult->optionTimes(sQHANDLE); ++i)
4311     {
4312         result = resolveOp(pInfo, pData, parsedResult, sQHANDLE, i);
4313 
4314         if (result->rc != kSTAFOk) return false;
4315 
4316         // Convert resolved option string to an unsigned integer in range
4317         // 1 to UINT_MAX
4318 
4319         unsigned int qHandle;
4320 
4321         result = convertOptionStringToUInt(
4322             result->result, sQHANDLE, qHandle, 1);
4323 
4324         if (result->rc != kSTAFOk) return false;
4325 
4326         logFilter.qHandles.push_back(qHandle);
4327     }
4328 
4329     if (parsedResult->optionTimes(sLEVELMASK) != 0)
4330     {
4331         result = resolveOp(pInfo, pData, parsedResult, sLEVELMASK);
4332 
4333         if (result->rc != kSTAFOk) return false;
4334 
4335         if (!convertLogMaskToUInt(result->result, logFilter.levelMask))
4336         {
4337             result->rc = kSTAFLogInvalidLevel;
4338             return false;
4339         }
4340 
4341         logFilter.useLevelMask = true;
4342     }
4343 
4344     if (parsedResult->optionTimes(sFROM) != 0)
4345     {
4346         result = resolveOp(pInfo, pData, parsedResult, sFROM);
4347 
4348         if (result->rc != kSTAFOk) return false;
4349 
4350         // Replace case-insensitive occurrence of TODAY with current date
4351         STAFString timestampString = result->result.toUpperCase().replace(
4352             sTODAY, (STAFTimestamp::now().asString()).subString(0, 8));
4353 
4354         if (!STAFTimestamp::isValidTimestampString(timestampString,
4355                                                    sTimestampSeps))
4356         {
4357             result->rc = kSTAFInvalidValue;
4358             return false;
4359         }
4360 
4361         STAFTimestamp from(timestampString, sTimestampSeps);
4362 
4363         logFilter.useFrom = true;
4364         logFilter.fromTimestamp.date = from.asDateString().asUInt();
4365         logFilter.fromTimestamp.seconds = from.asSecondsPastMidnight();
4366     }
4367 
4368     if (parsedResult->optionTimes(sAFTER) != 0)
4369     {
4370         result = resolveOp(pInfo, pData, parsedResult, sAFTER);
4371 
4372         if (result->rc != kSTAFOk) return false;
4373 
4374         // Replace case-insensitive occurrence of TODAY with current date
4375         STAFString timestampString = result->result.toUpperCase().replace(
4376             sTODAY, (STAFTimestamp::now().asString()).subString(0, 8));
4377 
4378         if (!STAFTimestamp::isValidTimestampString(timestampString,
4379                                                    sTimestampSeps))
4380         {
4381             result->rc = kSTAFInvalidValue;
4382             return false;
4383         }
4384 
4385         STAFTimestamp after(timestampString, sTimestampSeps);
4386 
4387         logFilter.useAfter = true;
4388         logFilter.afterTimestamp.date = after.asDateString().asUInt();
4389         logFilter.afterTimestamp.seconds = after.asSecondsPastMidnight();
4390     }
4391 
4392     if (parsedResult->optionTimes(sBEFORE) != 0)
4393     {
4394         result = resolveOp(pInfo, pData, parsedResult, sBEFORE);
4395 
4396         if (result->rc != kSTAFOk) return false;
4397 
4398         // Replace case-insensitive occurrence of TODAY with current date
4399         STAFString timestampString = result->result.toUpperCase().replace(
4400             sTODAY, (STAFTimestamp::now().asString()).subString(0, 8));
4401 
4402         if (!STAFTimestamp::isValidTimestampString(timestampString,
4403                                                    sTimestampSeps))
4404         {
4405             result->rc = kSTAFInvalidValue;
4406             return false;
4407         }
4408 
4409         STAFTimestamp before(timestampString, sTimestampSeps);
4410 
4411         logFilter.useBefore = true;
4412         logFilter.beforeTimestamp.date = before.asDateString().asUInt();
4413         logFilter.beforeTimestamp.seconds = before.asSecondsPastMidnight();
4414     }
4415 
4416     if (parsedResult->optionTimes(sTO) != 0)
4417     {
4418         result = resolveOp(pInfo, pData, parsedResult, sTO);
4419 
4420         if (result->rc != kSTAFOk) return false;
4421 
4422         // Replace case-insensitive occurrence of TODAY with current date
4423         STAFString timestampString = result->result.toUpperCase().replace(
4424             sTODAY, (STAFTimestamp::now().asString()).subString(0, 8));
4425 
4426         if (!STAFTimestamp::isValidTimestampString(timestampString,
4427                                                    sTimestampSeps))
4428         {
4429             result->rc = kSTAFInvalidValue;
4430             return false;
4431         }
4432 
4433         STAFTimestamp to(timestampString, sTimestampSeps);
4434 
4435         logFilter.useTo = true;
4436         logFilter.toTimestamp.date = to.asDateString().asUInt();
4437         logFilter.toTimestamp.seconds = to.asSecondsPastMidnight();
4438     }
4439 
4440     return true;
4441 }
4442 
4443 
updateLogStats(LogStats & logStats,unsigned int logLevel)4444 void updateLogStats(LogStats &logStats, unsigned int logLevel)
4445 {
4446     if (logLevel == 0x00000001)      ++logStats.fatal;
4447     else if (logLevel == 0x00000002) ++logStats.error;
4448     else if (logLevel == 0x00000004) ++logStats.warning;
4449     else if (logLevel == 0x00000008) ++logStats.info;
4450     else if (logLevel == 0x00000010) ++logStats.trace;
4451     else if (logLevel == 0x00000020) ++logStats.trace2;
4452     else if (logLevel == 0x00000040) ++logStats.trace3;
4453     else if (logLevel == 0x00000080) ++logStats.debug;
4454     else if (logLevel == 0x00000100) ++logStats.debug2;
4455     else if (logLevel == 0x00000200) ++logStats.debug3;
4456     else if (logLevel == 0x00000400) ++logStats.start;
4457     else if (logLevel == 0x00000800) ++logStats.stop;
4458     else if (logLevel == 0x00001000) ++logStats.pass;
4459     else if (logLevel == 0x00002000) ++logStats.fail;
4460     else if (logLevel == 0x00004000) ++logStats.status;
4461     else if (logLevel == 0x01000000) ++logStats.user1;
4462     else if (logLevel == 0x02000000) ++logStats.user2;
4463     else if (logLevel == 0x04000000) ++logStats.user3;
4464     else if (logLevel == 0x08000000) ++logStats.user4;
4465     else if (logLevel == 0x10000000) ++logStats.user5;
4466     else if (logLevel == 0x20000000) ++logStats.user6;
4467     else if (logLevel == 0x40000000) ++logStats.user7;
4468     else if (logLevel == 0x80000000) ++logStats.user8;
4469 }
4470 
4471 
4472 // Add log stats in a marshalling context as a map to the logList
4473 
addLogStatsToMap(STAFObjectPtr & queryStatsMap,const LogStats & logStats)4474 void addLogStatsToMap(STAFObjectPtr &queryStatsMap, const LogStats &logStats)
4475 {
4476     queryStatsMap->put("fatal",   STAFString(logStats.fatal));
4477     queryStatsMap->put("error",   STAFString(logStats.error));
4478     queryStatsMap->put("warning", STAFString(logStats.warning));
4479     queryStatsMap->put("info",    STAFString(logStats.info));
4480     queryStatsMap->put("trace",   STAFString(logStats.trace));
4481     queryStatsMap->put("trace2",  STAFString(logStats.trace2));
4482     queryStatsMap->put("trace3",  STAFString(logStats.trace3));
4483     queryStatsMap->put("debug",   STAFString(logStats.debug));
4484     queryStatsMap->put("debug2",  STAFString(logStats.debug2));
4485     queryStatsMap->put("debug3",  STAFString(logStats.debug3));
4486     queryStatsMap->put("start",   STAFString(logStats.start));
4487     queryStatsMap->put("stop",    STAFString(logStats.stop));
4488     queryStatsMap->put("pass",    STAFString(logStats.pass));
4489     queryStatsMap->put("fail",    STAFString(logStats.fail));
4490     queryStatsMap->put("status",  STAFString(logStats.status));
4491     queryStatsMap->put("user1",   STAFString(logStats.user1));
4492     queryStatsMap->put("user2",   STAFString(logStats.user2));
4493     queryStatsMap->put("user3",   STAFString(logStats.user3));
4494     queryStatsMap->put("user4",   STAFString(logStats.user4));
4495     queryStatsMap->put("user5",   STAFString(logStats.user5));
4496     queryStatsMap->put("user6",   STAFString(logStats.user6));
4497     queryStatsMap->put("user7",   STAFString(logStats.user7));
4498     queryStatsMap->put("user8",   STAFString(logStats.user8));
4499 }
4500 
4501 
registerHelpData(LogServiceData * pData,unsigned int errorNumber,const STAFString & shortInfo,const STAFString & longInfo)4502 void registerHelpData(LogServiceData *pData, unsigned int errorNumber,
4503                       const STAFString &shortInfo, const STAFString &longInfo)
4504 {
4505     static STAFString regString("REGISTER SERVICE %C ERROR %d INFO %C "
4506                                 "DESCRIPTION %C");
4507 
4508     pData->fHandle->submit(sLocal, sHELP, STAFHandle::formatString(
4509         regString.getImpl(), pData->fShortName.getImpl(), errorNumber,
4510         shortInfo.getImpl(), longInfo.getImpl()));
4511 }
4512 
4513 
unregisterHelpData(LogServiceData * pData,unsigned int errorNumber)4514 void unregisterHelpData(LogServiceData *pData, unsigned int errorNumber)
4515 {
4516     static STAFString regString("UNREGISTER SERVICE %C ERROR %d");
4517 
4518     pData->fHandle->submit(sLocal, sHELP, STAFHandle::formatString(
4519         regString.getImpl(), pData->fShortName.getImpl(), errorNumber));
4520 }
4521 
4522