diff options
Diffstat (limited to 'runtime/stream.c')
-rw-r--r-- | runtime/stream.c | 162 |
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); |