summaryrefslogtreecommitdiffstats
path: root/runtime/stream.c
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2009-06-12 11:47:00 +0200
committerRainer Gerhards <rgerhards@adiscon.com>2009-06-12 11:47:00 +0200
commite3d9843c85b1dfddabc937ac6ccb4057d626bf03 (patch)
tree734265f50321802e047a29b984391b619e7bd85f /runtime/stream.c
parent1af948107e6e520788e374adccf4986bf07e92f5 (diff)
downloadrsyslog-e3d9843c85b1dfddabc937ac6ccb4057d626bf03.tar.gz
rsyslog-e3d9843c85b1dfddabc937ac6ccb4057d626bf03.tar.xz
rsyslog-e3d9843c85b1dfddabc937ac6ccb4057d626bf03.zip
re-enabled pipe, tty and console in omfile
... by moving code to stream.c. Thanks to the new design, new cases are not really needed, resulting in cleaner code. I also did a cleanup of header file usage as a side-activity.
Diffstat (limited to 'runtime/stream.c')
-rw-r--r--runtime/stream.c162
1 files changed, 107 insertions, 55 deletions
diff --git a/runtime/stream.c b/runtime/stream.c
index 5355a1a5..c8672aa2 100644
--- a/runtime/stream.c
+++ b/runtime/stream.c
@@ -166,35 +166,14 @@ finalize_it:
* strm instance object.
*/
-/* open a strm file
- * It is OK to call this function when the stream is already open. In that
- * case, it returns immediately with RS_RET_OK
+/* do the physical open() call on a file.
*/
-static rsRetVal strmOpenFile(strm_t *pThis)
+static rsRetVal
+doPhysOpen(strm_t *pThis)
{
- DEFiRet;
int iFlags;
-
- ASSERT(pThis != NULL);
-
- if(pThis->fd != -1)
- ABORT_FINALIZE(RS_RET_OK);
-
- if(pThis->pszFName == NULL)
- ABORT_FINALIZE(RS_RET_FILE_PREFIX_MISSING);
-
- if(pThis->sType == STREAMTYPE_FILE_CIRCULAR) {
- CHKiRet(genFileName(&pThis->pszCurrFName, pThis->pszDir, pThis->lenDir,
- pThis->pszFName, pThis->lenFName, pThis->iCurrFNum, pThis->iFileNumDigits));
- } else {
- if(pThis->pszDir == NULL) {
- if((pThis->pszCurrFName = (uchar*) strdup((char*) pThis->pszFName)) == NULL)
- ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
- } else {
- CHKiRet(genFileName(&pThis->pszCurrFName, pThis->pszDir, pThis->lenDir,
- pThis->pszFName, pThis->lenFName, -1, 0));
- }
- }
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, strm);
/* compute which flags we need to provide to open */
switch(pThis->tOperationsMode) {
@@ -222,8 +201,51 @@ static rsRetVal strmOpenFile(strm_t *pThis)
ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND);
else
ABORT_FINALIZE(RS_RET_IO_ERROR);
+ } else {
+ if(!ustrcmp(pThis->pszCurrFName, UCHAR_CONSTANT(_PATH_CONSOLE)) || isatty(pThis->fd)) {
+ DBGPRINTF("file %d is a tty-type file\n", pThis->fd);
+ pThis->bIsTTY = 1;
+ } else {
+ pThis->bIsTTY = 0;
+ }
}
+finalize_it:
+ RETiRet;
+}
+
+
+/* open a strm file
+ * It is OK to call this function when the stream is already open. In that
+ * case, it returns immediately with RS_RET_OK
+ */
+static rsRetVal strmOpenFile(strm_t *pThis)
+{
+ DEFiRet;
+
+ ASSERT(pThis != NULL);
+
+ if(pThis->fd != -1)
+ ABORT_FINALIZE(RS_RET_OK);
+
+ if(pThis->pszFName == NULL)
+ ABORT_FINALIZE(RS_RET_FILE_PREFIX_MISSING);
+
+ if(pThis->sType == STREAMTYPE_FILE_CIRCULAR) {
+ CHKiRet(genFileName(&pThis->pszCurrFName, pThis->pszDir, pThis->lenDir,
+ pThis->pszFName, pThis->lenFName, pThis->iCurrFNum, pThis->iFileNumDigits));
+ } else {
+ if(pThis->pszDir == NULL) {
+ if((pThis->pszCurrFName = (uchar*) strdup((char*) pThis->pszFName)) == NULL)
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ } else {
+ CHKiRet(genFileName(&pThis->pszCurrFName, pThis->pszDir, pThis->lenDir,
+ pThis->pszFName, pThis->lenFName, -1, 0));
+ }
+ }
+
+ CHKiRet(doPhysOpen(pThis));
+
pThis->iCurrOffs = 0;
if(pThis->tOperationsMode == STREAMMODE_WRITE_APPEND) {
/* we need to obtain the current offset */
@@ -232,8 +254,8 @@ static rsRetVal strmOpenFile(strm_t *pThis)
pThis->iCurrOffs = offset;
}
- dbgoprint((obj_t*) pThis, "opened file '%s' for %s (0x%x) as %d\n", pThis->pszCurrFName,
- (pThis->tOperationsMode == STREAMMODE_READ) ? "READ" : "WRITE", iFlags, pThis->fd);
+ dbgoprint((obj_t*) pThis, "opened file '%s' for %s as %d\n", pThis->pszCurrFName,
+ (pThis->tOperationsMode == STREAMMODE_READ) ? "READ" : "WRITE", pThis->fd);
finalize_it:
RETiRet;
@@ -255,7 +277,7 @@ static rsRetVal strmCloseFile(strm_t *pThis)
if(pThis->tOperationsMode != STREAMMODE_READ)
strmFlush(pThis);
- close(pThis->fd); // TODO: error check
+ close(pThis->fd);
pThis->fd = -1;
if(pThis->fdDir != -1) {
@@ -265,7 +287,13 @@ static rsRetVal strmCloseFile(strm_t *pThis)
}
if(pThis->bDeleteOnClose) {
- unlink((char*) pThis->pszCurrFName); // TODO: check returncode
+ if(unlink((char*) pThis->pszCurrFName) == -1) {
+ char errStr[1024];
+ int err = errno;
+ rs_strerror_r(err, errStr, sizeof(errStr));
+ DBGPRINTF("error %d unlinking '%s' - ignored: %s\n",
+ errno, pThis->pszCurrFName, errStr);
+ }
}
pThis->iCurrOffs = 0; /* we are back at begin of file */
@@ -544,13 +572,12 @@ static rsRetVal strmConstructFinalize(strm_t *pThis)
}
/* if we are aset to sync, we must obtain a file handle to the directory for fsync() purposes */
- if(pThis->bSync) {
- pThis->fdDir = open((char*)pThis->pszDir, O_RDONLY);
+ if(pThis->bSync && !pThis->bIsTTY) {
+ pThis->fdDir = open((char*)pThis->pszDir, O_RDONLY | O_CLOEXEC | O_NOCTTY);
if(pThis->fdDir == -1) {
char errStr[1024];
int err = errno;
rs_strerror_r(err, errStr, sizeof(errStr));
- // TODO: log an error message? think so...
DBGPRINTF("error %d opening directory file for fsync() use - fsync for directory disabled: %s\n",
errno, errStr);
}
@@ -606,6 +633,29 @@ finalize_it:
}
+/* try to recover a tty after a write error. This may have happend
+ * due to vhangup(), and, if so, we can simply re-open it.
+ */
+#ifdef linux
+# define ERR_TTYHUP EIO
+#else
+# define ERR_TTYHUP EBADF
+#endif
+static rsRetVal
+tryTTYRecover(strm_t *pThis, int err)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, strm);
+ if(err == ERR_TTYHUP) {
+ close(pThis->fd);
+ CHKiRet(doPhysOpen(pThis));
+ }
+
+finalize_it:
+ RETiRet;
+}
+#undef ER_TTYHUP
+
/* issue write() api calls until either the buffer is completely
* written or an error occured (it may happen that multiple writes
@@ -614,29 +664,36 @@ finalize_it:
* rgerhards, 2009-06-08
*/
static rsRetVal
-doWriteCall(int fd, uchar *pBuf, size_t *pLenBuf)
+doWriteCall(strm_t *pThis, uchar *pBuf, size_t *pLenBuf)
{
ssize_t lenBuf;
ssize_t iTotalWritten;
ssize_t iWritten;
char *pWriteBuf;
DEFiRet;
+ ISOBJ_TYPE_assert(pThis, strm);
lenBuf = *pLenBuf;
pWriteBuf = (char*) pBuf;
iTotalWritten = 0;
do {
- iWritten = write(fd, pWriteBuf, lenBuf);
+ iWritten = write(pThis->fd, pWriteBuf, lenBuf);
if(iWritten < 0) {
char errStr[1024];
int err = errno;
rs_strerror_r(err, errStr, sizeof(errStr));
- DBGPRINTF("log file (%d) write error %d: %s\n", fd, err, errStr);
+ DBGPRINTF("log file (%d) write error %d: %s\n", pThis->fd, err, errStr);
if(err == EINTR) {
/*NO ERROR, just continue */;
} else {
- ABORT_FINALIZE(RS_RET_IO_ERROR);
- // TODO: cover more error cases!
+ if(pThis->bIsTTY) {
+ CHKiRet(tryTTYRecover(pThis, err));
+ } else {
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ /* Would it make sense to cover more error cases? So far, I
+ * do not see good reason to do so.
+ */
+ }
}
}
/* advance buffer to next write position */
@@ -653,7 +710,10 @@ finalize_it:
/* sync the file to disk, so that any unwritten data is persisted. This
* also syncs the directory and thus makes sure that the file survives
- * fatal failure. -- rgerhards, 2009-06-08
+ * fatal failure. Note that we do NOT return an error status if the
+ * sync fails. Doing so would probably cause more trouble than it
+ * is worth (read: data loss may occur where we otherwise might not
+ * have it). -- rgerhards, 2009-06-08
*/
static rsRetVal
syncFile(strm_t *pThis)
@@ -661,6 +721,9 @@ syncFile(strm_t *pThis)
int ret;
DEFiRet;
+ if(pThis->bIsTTY)
+ FINALIZE; /* TTYs can not be synced */
+
DBGPRINTF("syncing file %d\n", pThis->fd);
ret = fdatasync(pThis->fd);
if(ret != 0) {
@@ -670,19 +733,20 @@ syncFile(strm_t *pThis)
DBGPRINTF("sync failed for file %d with error (%d): %s - ignoring\n",
pThis->fd, err, errStr);
}
- // TODO: check error!
if(pThis->fdDir != -1) {
ret = fsync(pThis->fdDir);
-dbgprintf("sync on dir (fd %d) requested, return code %d\n", pThis->fdDir, ret);
}
+finalize_it:
RETiRet;
}
/* physically write to the output file. the provided data is ready for
* writing (e.g. zipped if we are requested to do that).
+ * Note that if the write() API fails, we do not reset any pointers, but return
+ * an error code. That means we may redo work in the next iteration.
* rgerhards, 2009-06-04
*/
static rsRetVal
@@ -690,24 +754,15 @@ strmPhysWrite(strm_t *pThis, uchar *pBuf, size_t lenBuf)
{
size_t iWritten;
DEFiRet;
-
- ASSERT(pThis != NULL);
+ ISOBJ_TYPE_assert(pThis, strm);
if(pThis->fd == -1)
CHKiRet(strmOpenFile(pThis));
iWritten = lenBuf;
- CHKiRet(doWriteCall(pThis->fd, pBuf, &iWritten));
+ CHKiRet(doWriteCall(pThis, pBuf, &iWritten));
dbgoprint((obj_t*) pThis, "file %d write wrote %d bytes\n", pThis->fd, (int) iWritten);
- /* Now indicate buffer empty again. We do this in any case, because there
- * is no way we could react more intelligently to an error during write.
- * This MUST be done BEFORE strCheckNextOutputFile(), otherwise we have an
- * endless loop. We reset the buffer pointer also in finalize_it - this is
- * necessary if we run into problems. Not resetting it would again cause an
- * endless loop. So it is better to loose some data (which also justifies
- * duplicating that code, too...) -- rgerhards, 2008-01-10
- */
pThis->iBufPtr = 0;
pThis->iCurrOffs += iWritten;
/* update user counter, if provided */
@@ -725,8 +780,6 @@ strmPhysWrite(strm_t *pThis, uchar *pBuf, size_t lenBuf)
}
finalize_it:
- pThis->iBufPtr = 0; /* see comment above */
-
RETiRet;
}
@@ -995,7 +1048,6 @@ strmSetFName(strm_t *pThis, uchar *pszName, size_t iLenName)
ASSERT(pThis != NULL);
ASSERT(pszName != NULL);
-dbgprintf("XXX: strm setFname: '%s'\n", pszName);
if(iLenName < 1)
ABORT_FINALIZE(RS_RET_FILE_PREFIX_MISSING);