74
78
DEFobjCurrIf(errmsg)
81
/* for our current LRU mechanism, we need a monotonically increasing counters. We use
82
* it much like a "Lamport logical clock": we do not need the actual time, we just need
83
* to know the sequence in which files were accessed. So we use a simple counter to
84
* create that sequence. We use an unsigned 64 bit value which is extremely unlike to
85
* wrap within the lifetime of a process. If we process 1,000,000 file writes per
86
* second, the process could still exist over 500,000 years before a wrap to 0 happens.
87
* That should be sufficient (and even than, there would no really bad effect ;)).
88
* The variable below is the global counter/clock.
90
#if HAVE_ATOMIC_BUILTINS_64BIT
91
static uint64 clockFileAccess = 0;
93
static unsigned clockFileAccess = 0;
95
/* and the "tick" function */
96
#ifndef HAVE_ATOMIC_BUILTINS
97
static pthread_mutex_t mutClock;
100
getClockFileAccess(void)
102
#if HAVE_ATOMIC_BUILTINS_64BIT
103
return ATOMIC_INC_AND_FETCH_uint64(&clockFileAccess, &mutClock);
105
return ATOMIC_INC_AND_FETCH_unsigned(&clockFileAccess, &mutClock);
77
110
/* The following structure is a dynafile name cache entry.
79
112
struct s_dynaFileCacheEntry {
80
113
uchar *pName; /* name currently open, if dynamic name */
81
114
strm_t *pStrm; /* our output stream */
82
time_t lastUsed; /* for LRU - last access */
115
uint64 clkTickAccessed;/* for LRU - based on clockFileAccess */
84
117
typedef struct s_dynaFileCacheEntry dynaFileCacheEntry;
89
122
#define USE_ASYNCWRITER_DFLT 0 /* default buffer use async writer */
90
123
#define FLUSHONTX_DFLT 1 /* default for flush on TX end */
125
#define DFLT_bForceChown 0
92
126
/* globals for default values */
93
127
static int iDynaFileCacheSize = 10; /* max cache for dynamic files */
94
128
static int fCreateMode = 0644; /* mode to use when creating files */
95
129
static int fDirCreateMode = 0700; /* mode to use when creating files */
96
130
static int bFailOnChown; /* fail if chown fails? */
131
static int bForceChown = DFLT_bForceChown; /* Force chown() on existing files? */
97
132
static uid_t fileUID; /* UID to be used for newly created files */
98
133
static uid_t fileGID; /* GID to be used for newly created files */
99
134
static uid_t dirUID; /* UID to be used for newly created directories */
101
136
static int bCreateDirs = 1;/* auto-create directories for dynaFiles: 0 - no, 1 - yes */
102
137
static int bEnableSync = 0;/* enable syncing of files (no dash in front of pathname in conf): 0 - no, 1 - yes */
103
138
static int iZipLevel = 0; /* zip compression mode (0..9 as usual) */
104
static bool bFlushOnTXEnd = FLUSHONTX_DFLT;/* flush write buffers when transaction has ended? */
139
static sbool bFlushOnTXEnd = FLUSHONTX_DFLT;/* flush write buffers when transaction has ended? */
105
140
static int64 iIOBufSize = IOBUF_DFLT_SIZE; /* size of an io buffer */
106
141
static int iFlushInterval = FLUSH_INTRVL_DFLT; /* how often flush the output buffer on inactivity? */
107
142
static int bUseAsyncWriter = USE_ASYNCWRITER_DFLT; /* should we enable asynchronous writing? */
118
153
int fDirCreateMode; /* creation mode for mkdir() */
119
154
int bCreateDirs; /* auto-create directories? */
120
155
int bSyncFile; /* should the file by sync()'ed? 1- yes, 0- no */
156
sbool bForceChown; /* force chown() on existing files? */
121
157
uid_t fileUID; /* IDs for creation */
136
172
int iZipLevel; /* zip mode to use for this selector */
137
173
int iIOBufSize; /* size of associated io buffer */
138
174
int iFlushInterval; /* how fast flush buffer on inactivity? */
139
bool bFlushOnTXEnd; /* flush write buffers when transaction has ended? */
140
bool bUseAsyncWriter; /* use async stream writer? */
175
sbool bFlushOnTXEnd; /* flush write buffers when transaction has ended? */
176
sbool bUseAsyncWriter; /* use async stream writer? */
163
199
dbgprintf("\tflush interval=%d\n", pData->iFlushInterval);
164
200
dbgprintf("\tfile cache size=%d\n", pData->iDynaFileCacheSize);
165
201
dbgprintf("\tcreate directories: %s\n", pData->bCreateDirs ? "yes" : "no");
166
dbgprintf("\tfile owner %d, group %d\n", pData->fileUID, pData->fileGID);
167
dbgprintf("\tdirectory owner %d, group %d\n", pData->dirUID, pData->dirGID);
202
dbgprintf("\tfile owner %d, group %d\n", (int) pData->fileUID, (int) pData->fileGID);
203
dbgprintf("\tforce chown() for all files: %s\n", pData->bForceChown ? "yes" : "no");
204
dbgprintf("\tdirectory owner %d, group %d\n", (int) pData->dirUID, (int) pData->dirGID);
168
205
dbgprintf("\tdir create mode 0%3.3o, file create mode 0%3.3o\n",
169
206
pData->fDirCreateMode, pData->fCreateMode);
170
207
dbgprintf("\tfail if owner/group can not be set: %s\n", pData->bFailOnChown ? "yes" : "no");
354
if(access((char*)newFileName, F_OK) != 0) {
391
if(access((char*)newFileName, F_OK) == 0) {
392
if(pData->bForceChown) {
393
/* Try to fix wrong ownership set by someone else. Note that this code
394
* will no longer work once we have made the $PrivDrop code fully secure.
395
* This change is based on an idea of Michael Terry, provided as part of
396
* the effort to make rsyslogd the Ubuntu default syslogd.
397
* rgerhards, 2009-09-11
399
if(chown((char*)newFileName, pData->fileUID, pData->fileGID) != 0) {
400
if(pData->bFailOnChown) {
355
407
/* file does not exist, create it (and eventually parent directories */
357
408
if(pData->bCreateDirs) {
358
409
/* We first need to create parent dirs if they are missing.
359
410
* We do not report any errors here ourselfs but let the code
372
423
pData->fCreateMode);
374
425
/* check and set uid/gid */
375
if(pData->fileUID != (uid_t)-1 || pData->fileGID != (gid_t) -1) {
426
if(pData->bForceChown || pData->fileUID != (uid_t)-1 || pData->fileGID != (gid_t) -1) {
376
427
/* we need to set owner/group */
377
428
if(fchown(fd, pData->fileUID, pData->fileGID) != 0) {
378
429
if(pData->bFailOnChown) {
456
507
if( (pData->iCurrElt != -1)
457
508
&& !ustrcmp(newFileName, pCache[pData->iCurrElt]->pName)) {
458
509
/* great, we are all set */
459
pCache[pData->iCurrElt]->lastUsed = time(NULL); /* update timestamp for LRU */ // TODO: optimize time call!
510
pCache[pData->iCurrElt]->clkTickAccessed = getClockFileAccess();
460
511
// LRU needs only a strictly monotonically increasing counter, so such a one could do
467
518
pData->iCurrElt = -1; /* invalid current element pointer */
468
519
iFirstFree = -1; /* not yet found */
469
520
iOldest = 0; /* we assume the first element to be the oldest - that will change as we loop */
470
ttOldest = time(NULL) + 1; /* there must always be an older one */
521
ctOldest = getClockFileAccess(); /* there must always be an older one */
471
522
for(i = 0 ; i < pData->iCurrCacheSize ; ++i) {
472
523
if(pCache[i] == NULL || pCache[i]->pName == NULL) {
473
524
if(iFirstFree == -1)
477
528
/* we found our element! */
478
529
pData->pStrm = pCache[i]->pStrm;
479
530
pData->iCurrElt = i;
480
pCache[i]->lastUsed = time(NULL); /* update timestamp for LRU */
531
pCache[i]->clkTickAccessed = getClockFileAccess(); /* update "timestamp" for LRU */
483
534
/* did not find it - so lets keep track of the counters for LRU */
484
if(pCache[i]->lastUsed < ttOldest) {
485
ttOldest = pCache[i]->lastUsed;
535
if(pCache[i]->clkTickAccessed < ctOldest) {
536
ctOldest = pCache[i]->clkTickAccessed;
508
559
iFirstFree = pData->iCurrCacheSize++;
511
// RG: this is the begin of a potential problem area
512
562
/* Note that the following code sequence does not work with the cache entry itself,
513
563
* but rather with pData->pStrm, the (sole) stream pointer in the non-dynafile case.
514
564
* The cache array is only updated after the open was successful. -- rgerhards, 2010-03-21
546
596
ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
548
598
pCache[iFirstFree]->pStrm = pData->pStrm;
549
pCache[iFirstFree]->lastUsed = time(NULL);
599
pCache[iFirstFree]->clkTickAccessed = getClockFileAccess();
550
600
pData->iCurrElt = iFirstFree;
551
601
DBGPRINTF("Added new entry %d for file cache, file '%s'.\n", iFirstFree, newFileName);
567
617
ASSERT(pData != NULL);
568
618
ASSERT(pszBuf != NULL);
570
dbgprintf("doWrite, pData->pStrm %p, lenBuf %d\n", pData->pStrm, lenBuf);
620
dbgprintf("write to stream, pData->pStrm %p, lenBuf %d\n", pData->pStrm, lenBuf);
571
621
if(pData->pStrm != NULL){
572
622
CHKiRet(strm.Write(pData->pStrm, pszBuf, lenBuf));
633
683
CODESTARTtryResume
686
BEGINbeginTransaction
687
CODESTARTbeginTransaction
688
/* we have nothing to do to begin a transaction */
693
CODESTARTendTransaction
694
if(pData->bFlushOnTXEnd) {
695
CHKiRet(strm.Flush(pData->pStrm));
637
702
CODESTARTdoAction
638
703
DBGPRINTF("file to log to: %s\n", pData->f_fname);
639
704
CHKiRet(writeFile(ppString, iMsgOpts, pData));
640
if(pData->bFlushOnTXEnd) {
641
/* TODO v5: do this in endTransaction only! */
705
if(!bCoreSupportsBatching && pData->bFlushOnTXEnd) {
642
706
CHKiRet(strm.Flush(pData->pStrm));
709
if(iRet == RS_RET_OK)
710
iRet = RS_RET_DEFER_COMMIT;
724
790
pData->fDirCreateMode = fDirCreateMode;
725
791
pData->bCreateDirs = bCreateDirs;
726
792
pData->bFailOnChown = bFailOnChown;
793
pData->bForceChown = bForceChown;
727
794
pData->fileUID = fileUID;
728
795
pData->fileGID = fileGID;
729
796
pData->dirUID = dirUID;
796
864
objRelease(errmsg, CORE_COMPONENT);
797
865
objRelease(strm, CORE_COMPONENT);
798
866
free(pszFileDfltTplName);
867
DESTROY_ATOMIC_HELPER_MUT(mutClock);
803
872
CODESTARTqueryEtryPt
804
873
CODEqueryEtryPt_STD_OMOD_QUERIES
874
CODEqueryEtryPt_TXIF_OMOD_QUERIES /* we support the transactional interface! */
805
875
CODEqueryEtryPt_doHUP
812
882
CODEmodInit_QueryRegCFSLineHdlr
813
883
CHKiRet(objUse(errmsg, CORE_COMPONENT));
814
884
CHKiRet(objUse(strm, CORE_COMPONENT));
886
INIT_ATOMIC_HELPER_MUT(mutClock);
888
INITChkCoreFeature(bCoreSupportsBatching, CORE_FEATURE_BATCHING);
889
DBGPRINTF("omfile: %susing transactional output interface.\n", bCoreSupportsBatching ? "" : "not ");
815
890
CHKiRet(omsdRegCFSLineHdlr((uchar *)"dynafilecachesize", 0, eCmdHdlrInt, (void*) setDynaFileCacheSize, NULL, STD_LOADABLE_MODULE_ID));
816
891
CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileziplevel", 0, eCmdHdlrInt, NULL, &iZipLevel, STD_LOADABLE_MODULE_ID));
817
892
CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileflushinterval", 0, eCmdHdlrInt, NULL, &iFlushInterval, STD_LOADABLE_MODULE_ID));
826
901
CHKiRet(omsdRegCFSLineHdlr((uchar *)"filecreatemode", 0, eCmdHdlrFileCreateMode, NULL, &fCreateMode, STD_LOADABLE_MODULE_ID));
827
902
CHKiRet(omsdRegCFSLineHdlr((uchar *)"createdirs", 0, eCmdHdlrBinary, NULL, &bCreateDirs, STD_LOADABLE_MODULE_ID));
828
903
CHKiRet(omsdRegCFSLineHdlr((uchar *)"failonchownfailure", 0, eCmdHdlrBinary, NULL, &bFailOnChown, STD_LOADABLE_MODULE_ID));
904
CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileForceChown", 0, eCmdHdlrBinary, NULL, &bForceChown, STD_LOADABLE_MODULE_ID));
829
905
CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionfileenablesync", 0, eCmdHdlrBinary, NULL, &bEnableSync, STD_LOADABLE_MODULE_ID));
830
906
CHKiRet(regCfSysLineHdlr((uchar *)"actionfiledefaulttemplate", 0, eCmdHdlrGetWord, NULL, &pszFileDfltTplName, NULL));
831
907
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));