diff options
Diffstat (limited to 'tools/omfile.c')
-rw-r--r-- | tools/omfile.c | 191 |
1 files changed, 125 insertions, 66 deletions
diff --git a/tools/omfile.c b/tools/omfile.c index fb83632a..3e845a73 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -44,6 +44,10 @@ #include <unistd.h> #include <sys/file.h> +#ifdef OS_SOLARIS +# include <fcntl.h> +#endif + #include "syslogd.h" #include "syslogd-types.h" #include "srUtils.h" @@ -174,7 +178,7 @@ rsRetVal setDynaFileCacheSize(void __attribute__((unused)) *pVal, int iNewVal) } iDynaFileCacheSize = iNewVal; - dbgprintf("DynaFileCacheSize changed to %d.\n", iNewVal); + DBGPRINTF("DynaFileCacheSize changed to %d.\n", iNewVal); RETiRet; } @@ -244,7 +248,6 @@ static rsRetVal cflineParseOutchannel(instanceData *pData, uchar* p, omodStringR */ pData->f_sizeLimitCmd = (char*) pOch->cmdOnSizeLimit; -RUNLOG_VAR("%p", pszTplName); iRet = cflineParseTemplateName(&p, pOMSR, iEntry, iTplOpts, (pszTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszTplName); @@ -298,7 +301,7 @@ int resolveFileSizeLimit(instanceData *pData) free(pCmd); - pData->fd = open((char*) pData->f_fname, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, + pData->fd = open((char*) pData->f_fname, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY|O_CLOEXEC, pData->fCreateMode); actualFileSize = lseek(pData->fd, 0, SEEK_END); @@ -327,7 +330,7 @@ static void dynaFileDelCacheEntry(dynaFileCacheEntry **pCache, int iEntry, int b if(pCache[iEntry] == NULL) FINALIZE; - dbgprintf("Removed entry %d for file '%s' from dynaCache.\n", iEntry, + DBGPRINTF("Removed entry %d for file '%s' from dynaCache.\n", iEntry, pCache[iEntry]->pName == NULL ? "[OPEN FAILED]" : (char*)pCache[iEntry]->pName); /* if the name is NULL, this is an improperly initilized entry which * needs to be discarded. In this case, neither the file is to be closed @@ -349,9 +352,11 @@ finalize_it: } -/* This function frees the dynamic file name cache. +/* This function frees all dynamic file name cache entries and closes the + * relevant files. Part of Shutdown and HUP processing. + * rgerhards, 2008-10-23 */ -static void dynaFileFreeCache(instanceData *pData) +static inline void dynaFileFreeCacheEntries(instanceData *pData) { register int i; ASSERT(pData != NULL); @@ -360,46 +365,67 @@ static void dynaFileFreeCache(instanceData *pData) for(i = 0 ; i < pData->iCurrCacheSize ; ++i) { dynaFileDelCacheEntry(pData->dynCache, i, 1); } + ENDfunc; +} + + +/* This function frees the dynamic file name cache. + */ +static void dynaFileFreeCache(instanceData *pData) +{ + ASSERT(pData != NULL); + BEGINfunc; + dynaFileFreeCacheEntries(pData); if(pData->dynCache != NULL) d_free(pData->dynCache); ENDfunc; } -/* This is a shared code for both static and dynamic files. +/* This is now shared code for all types of files. It simply prepares + * file access, which, among others, means the the file wil be opened + * and any directories in between will be created (based on config, of + * course). -- rgerhards, 2008-10-22 + * changed to iRet interface - 2009-03-19 */ -static void prepareFile(instanceData *pData, uchar *newFileName) +static rsRetVal +prepareFile(instanceData *pData, uchar *newFileName) { + DEFiRet; + if(pData->fileType == eTypePIPE) { + pData->fd = open((char*) pData->f_fname, O_RDWR|O_NONBLOCK|O_CLOEXEC); + FINALIZE; /* we are done in this case */ + } + if(access((char*)newFileName, F_OK) == 0) { /* file already exists */ - pData->fd = open((char*) newFileName, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, + pData->fd = open((char*) newFileName, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY|O_CLOEXEC, pData->fCreateMode); } else { pData->fd = -1; /* file does not exist, create it (and eventually parent directories */ if(pData->bCreateDirs) { - /* we fist need to create parent dirs if they are missing + /* We first need to create parent dirs if they are missing. * We do not report any errors here ourselfs but let the code * fall through to error handler below. */ if(makeFileParentDirs(newFileName, strlen((char*)newFileName), pData->fDirCreateMode, pData->dirUID, pData->dirGID, pData->bFailOnChown) != 0) { - return; /* we give up */ + ABORT_FINALIZE(RS_RET_ERR); /* we give up */ } } /* no matter if we needed to create directories or not, we now try to create * the file. -- rgerhards, 2008-12-18 (based on patch from William Tisater) */ - pData->fd = open((char*) newFileName, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, + pData->fd = open((char*) newFileName, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY|O_CLOEXEC, pData->fCreateMode); if(pData->fd != -1) { /* check and set uid/gid */ if(pData->fileUID != (uid_t)-1 || pData->fileGID != (gid_t) -1) { /* we need to set owner/group */ - if(fchown(pData->fd, pData->fileUID, - pData->fileGID) != 0) { + if(fchown(pData->fd, pData->fileUID, pData->fileGID) != 0) { if(pData->bFailOnChown) { int eSave = errno; close(pData->fd); @@ -413,6 +439,18 @@ static void prepareFile(instanceData *pData, uchar *newFileName) } } } +finalize_it: + /* this was "pData->fd != 0", which I think was a bug. I guess 0 was intended to mean + * non-open file descriptor. Anyhow, I leave this comment for the time being to that if + * problems surface, one at least knows what happened. -- rgerhards, 2009-03-19 + */ + if(pData->fd != -1 && isatty(pData->fd)) { + DBGPRINTF("file %d is a tty file\n", pData->fd); + pData->fileType = eTypeTTY; + untty(); + } + + RETiRet; } @@ -431,6 +469,8 @@ static int prepareDynFile(instanceData *pData, uchar *newFileName, unsigned iMsg int i; int iFirstFree; dynaFileCacheEntry **pCache; + + BEGINfunc ASSERT(pData != NULL); ASSERT(newFileName != NULL); @@ -486,13 +526,13 @@ static int prepareDynFile(instanceData *pData, uchar *newFileName, unsigned iMsg /* we need to allocate memory for the cache structure */ pCache[iFirstFree] = (dynaFileCacheEntry*) calloc(1, sizeof(dynaFileCacheEntry)); if(pCache[iFirstFree] == NULL) { - dbgprintf("prepareDynfile(): could not alloc mem, discarding this request\n"); + DBGPRINTF("prepareDynfile(): could not alloc mem, discarding this request\n"); return -1; } } /* Ok, we finally can open the file */ - prepareFile(pData, newFileName); + prepareFile(pData, newFileName); /* ignore exact error, we check fd below */ /* file is either open now or an error state set */ if(pData->fd == -1) { @@ -500,10 +540,11 @@ static int prepareDynFile(instanceData *pData, uchar *newFileName, unsigned iMsg * message. Otherwise, we could run into a never-ending loop. The bad * news is that we also lose errors on startup messages, but so it is. */ - if(iMsgOpts & INTERNAL_MSG) - dbgprintf("Could not open dynaFile, discarding message\n"); - else + if(iMsgOpts & INTERNAL_MSG) { + DBGPRINTF("Could not open dynaFile, discarding message\n"); + } else { errmsg.LogError(0, NO_ERRCODE, "Could not open dynamic file '%s' - discarding message", (char*)newFileName); + } dynaFileDelCacheEntry(pCache, iFirstFree, 1); pData->iCurrElt = -1; return -1; @@ -513,8 +554,9 @@ static int prepareDynFile(instanceData *pData, uchar *newFileName, unsigned iMsg pCache[iFirstFree]->pName = (uchar*)strdup((char*)newFileName); /* TODO: check for NULL (very unlikely) */ pCache[iFirstFree]->lastUsed = time(NULL); pData->iCurrElt = iFirstFree; - dbgprintf("Added new entry %d for file cache, file '%s'.\n", - iFirstFree, newFileName); + DBGPRINTF("Added new entry %d for file cache, file '%s'.\n", iFirstFree, newFileName); + + ENDfunc return 0; } @@ -527,6 +569,7 @@ static int prepareDynFile(instanceData *pData, uchar *newFileName, unsigned iMsg static rsRetVal writeFile(uchar **ppString, unsigned iMsgOpts, instanceData *pData) { off_t actualFileSize; + int iLenWritten; DEFiRet; ASSERT(pData != NULL); @@ -536,7 +579,14 @@ static rsRetVal writeFile(uchar **ppString, unsigned iMsgOpts, instanceData *pDa */ if(pData->bDynamicName) { if(prepareDynFile(pData, ppString[1], iMsgOpts) != 0) - ABORT_FINALIZE(RS_RET_ERR); + ABORT_FINALIZE(RS_RET_SUSPENDED); /* whatever the failure was, we need to retry */ + } + + if(pData->fd == -1) { + rsRetVal iRetLocal; + iRetLocal = prepareFile(pData, pData->f_fname); + if((iRetLocal != RS_RET_OK) || (pData->fd == -1)) + ABORT_FINALIZE(RS_RET_SUSPENDED); /* whatever the failure was, we need to retry */ } /* create the message based on format specified */ @@ -572,42 +622,47 @@ again: } } - if (write(pData->fd, ppString[0], strlen((char*)ppString[0])) < 0) { + iLenWritten = write(pData->fd, ppString[0], strlen((char*)ppString[0])); +//dbgprintf("lenwritten: %d\n", iLenWritten); + if(iLenWritten < 0) { int e = errno; + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + DBGPRINTF("log file (%d) write error %d: %s\n", pData->fd, e, errStr); - /* If a named pipe is full, just ignore it for now - - mrn 24 May 96 */ - if (pData->fileType == eTypePIPE && e == EAGAIN) - ABORT_FINALIZE(RS_RET_OK); - - /* If the filesystem is filled up, just ignore - * it for now and continue writing when possible - * based on patch for sysklogd by Martin Schulze on 2007-05-24 - */ - if (pData->fileType == eTypeFILE && e == ENOSPC) - ABORT_FINALIZE(RS_RET_OK); + /* If a named pipe is full, we suspend this action for a while */ + if(pData->fileType == eTypePIPE && e == EAGAIN) + ABORT_FINALIZE(RS_RET_SUSPENDED); - (void) close(pData->fd); - /* - * Check for EBADF on TTY's due to vhangup() + close(pData->fd); + pData->fd = -1; /* tell that fd is no longer open! */ + if(pData->bDynamicName && pData->iCurrElt != -1) { + /* in this case, we need to invalidate the name in the cache, too + * otherwise, an invalid fd may show up if we had a file name change. + * rgerhards, 2009-03-19 + */ + pData->dynCache[pData->iCurrElt]->fd = -1; + } + /* Check for EBADF on TTY's due to vhangup() * Linux uses EIO instead (mrn 12 May 96) */ - if ((pData->fileType == eTypeTTY || pData->fileType == eTypeCONSOLE) + if((pData->fileType == eTypeTTY || pData->fileType == eTypeCONSOLE) #ifdef linux - && e == EIO) { + && e == EIO #else - && e == EBADF) { + && e == EBADF #endif - pData->fd = open((char*) pData->f_fname, O_WRONLY|O_APPEND|O_NOCTTY); + ) { + pData->fd = open((char*) pData->f_fname, O_WRONLY|O_APPEND|O_NOCTTY|O_CLOEXEC); if (pData->fd < 0) { - iRet = RS_RET_DISABLE_ACTION; + iRet = RS_RET_SUSPENDED; errmsg.LogError(0, NO_ERRCODE, "%s", pData->f_fname); } else { untty(); goto again; } } else { - iRet = RS_RET_DISABLE_ACTION; + iRet = RS_RET_SUSPENDED; errno = e; errmsg.LogError(0, NO_ERRCODE, "%s", pData->f_fname); } @@ -641,13 +696,8 @@ ENDtryResume BEGINdoAction CODESTARTdoAction - dbgprintf(" (%s)\n", pData->f_fname); - /* pData->fd == -1 is an indicator that the we couldn't - * open the file at startup. For dynaFiles, this is ok, - * all others are doomed. - */ - if(pData->bDynamicName || (pData->fd != -1)) - iRet = writeFile(ppString, iMsgOpts, pData); + DBGPRINTF(" (%s)\n", pData->f_fname); + iRet = writeFile(ppString, iMsgOpts, pData); ENDdoAction @@ -675,7 +725,6 @@ CODESTARTparseSelectorAct } else { pData->bSyncFile = bEnableSync ? 1 : 0; } - pData->f_sizeLimit = 0; /* default value, use outchannels to configure! */ switch (*p) @@ -693,7 +742,7 @@ CODESTARTparseSelectorAct pData->bDynamicName = 0; pData->fCreateMode = fCreateMode; /* preserve current setting */ pData->fDirCreateMode = fDirCreateMode; /* preserve current setting */ - pData->fd = open((char*) pData->f_fname, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, + pData->fd = open((char*) pData->f_fname, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY|O_CLOEXEC, pData->fCreateMode); } break; @@ -730,7 +779,7 @@ CODESTARTparseSelectorAct if((pData->dynCache = (dynaFileCacheEntry**) calloc(iDynaFileCacheSize, sizeof(dynaFileCacheEntry*))) == NULL) { iRet = RS_RET_OUT_OF_MEMORY; - dbgprintf("Could not allocate memory for dynaFileCache - selector disabled.\n"); + DBGPRINTF("Could not allocate memory for dynaFileCache - selector disabled.\n"); } break; @@ -764,23 +813,18 @@ CODESTARTparseSelectorAct pData->dirUID = dirUID; pData->dirGID = dirGID; - if(pData->fileType == eTypePIPE) { - pData->fd = open((char*) pData->f_fname, O_RDWR|O_NONBLOCK); - } else { - prepareFile(pData, pData->f_fname); - } + /* at this stage, we ignore the return value of prepareFile, this is taken + * care of in later steps. -- rgerhards, 2009-03-19 + */ + prepareFile(pData, pData->f_fname); - if ( pData->fd < 0 ){ + if(pData->fd < 0 ) { pData->fd = -1; - dbgprintf("Error opening log file: %s\n", pData->f_fname); - errmsg.LogError(0, NO_ERRCODE, "%s", pData->f_fname); + DBGPRINTF("Error opening log file: %s\n", pData->f_fname); + errmsg.LogError(0, RS_RET_NO_FILE_ACCESS, "Could no open output file '%s'", pData->f_fname); break; } - if (isatty(pData->fd)) { - pData->fileType = eTypeTTY; - untty(); - } - if (strcmp((char*) p, _PATH_CONSOLE) == 0) + if(strcmp((char*) p, _PATH_CONSOLE) == 0) pData->fileType = eTypeCONSOLE; break; default: @@ -815,6 +859,20 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a } +BEGINdoHUP +CODESTARTdoHUP + if(pData->bDynamicName) { + dynaFileFreeCacheEntries(pData); + pData->iCurrElt = -1; /* invalidate current element */ + } else { + if(pData->fd != -1) { + close(pData->fd); + pData->fd = -1; + } + } +ENDdoHUP + + BEGINmodExit CODESTARTmodExit if(pszTplName != NULL) @@ -825,6 +883,7 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_doHUP ENDqueryEtryPt |