This will protect log files from being deleted by virtlogcleaner even if log is not being written active currently. --- src/logging/log_handler.c | 113 +++++++++++++++++++++++++++++++++----- 1 file changed, 98 insertions(+), 15 deletions(-) diff --git a/src/logging/log_handler.c b/src/logging/log_handler.c index 5c3df37415..fee4567911 100644 --- a/src/logging/log_handler.c +++ b/src/logging/log_handler.c @@ -34,6 +34,8 @@ #include <unistd.h> #include <fcntl.h> #include <poll.h> +#include <sys/types.h> +#include <utime.h> #include "configmake.h" @@ -43,6 +45,8 @@ VIR_LOG_INIT("logging.log_handler"); #define DEFAULT_MODE 0600 +#define LOG_HANDLER_TOUCH_TIMEOUT (24 * 3600 * 1000) + typedef struct _virLogHandlerLogFile virLogHandlerLogFile; struct _virLogHandlerLogFile { virRotatingFileWriter *file; @@ -65,6 +69,8 @@ struct _virLogHandler { virLogHandlerLogFile **files; size_t nfiles; + int timer; + virLogHandlerShutdownInhibitor inhibitor; void *opaque; }; @@ -102,6 +108,17 @@ virLogHandlerLogFileFree(virLogHandlerLogFile *file) } +static void +virLogHandlerCleanupTimer(virLogHandler *handler) +{ + if (handler->nfiles > 0 || handler->timer == 0) + return; + + virEventRemoveTimeout(handler->timer); + handler->timer = 0; +} + + static void virLogHandlerLogFileClose(virLogHandler *handler, virLogHandlerLogFile *file) @@ -115,6 +132,8 @@ virLogHandlerLogFileClose(virLogHandler *handler, break; } } + + virLogHandlerCleanupTimer(handler); } @@ -209,6 +228,30 @@ virLogHandlerNew(bool privileged, } +/* + * This helper aims to handle races with file deleting by log file cleaner. + * Cleaner can unlink file right after we open it for write. In this case + * let's just recreate it. + * + */ +static virRotatingFileWriter * +virLogHandlerNewWriter(const char *path, + off_t maxlen, + size_t maxbackup, + bool trunc, + mode_t mode) +{ + virRotatingFileWriter *writer; + + writer = virRotatingFileWriterNew(path, maxlen, maxbackup, trunc, mode); + if (virFileExists(path)) + return writer; + + virRotatingFileWriterFree(writer); + return virRotatingFileWriterNew(path, maxlen, maxbackup, trunc, mode); +} + + static virLogHandlerLogFile * virLogHandlerLogFilePostExecRestart(virLogHandler *handler, virJSONValue *object) @@ -253,11 +296,11 @@ virLogHandlerLogFilePostExecRestart(virLogHandler *handler, goto error; } - if ((file->file = virRotatingFileWriterNew(path, - handler->max_size, - handler->max_backups, - false, - DEFAULT_MODE)) == NULL) + if ((file->file = virLogHandlerNewWriter(path, + handler->max_size, + handler->max_backups, + false, + DEFAULT_MODE)) == NULL) goto error; if (virJSONValueObjectGetNumberInt(object, "pipefd", &file->pipefd) < 0) { @@ -280,6 +323,26 @@ virLogHandlerLogFilePostExecRestart(virLogHandler *handler, } +static void +virLogHandlerTimeout(int timer G_GNUC_UNUSED, + void *opaque) +{ + virLogHandler *handler = opaque; + size_t i; + + virObjectLock(handler); + + for (i = 0; i < handler->nfiles; i++) { + const char *path = virRotatingFileWriterGetPath(handler->files[i]->file); + + if (utime(path, NULL) < 0) + VIR_WARN("utime(%s) error: %s", path, g_strerror(errno)); + } + + virObjectUnlock(handler); +} + + virLogHandler * virLogHandlerNewPostExecRestart(virJSONValue *object, bool privileged, @@ -330,6 +393,11 @@ virLogHandlerNewPostExecRestart(virJSONValue *object, } } + if (handler->nfiles > 0 && + (handler->timer = virEventAddTimeout(LOG_HANDLER_TOUCH_TIMEOUT, + virLogHandlerTimeout, + handler, NULL) <= 0)) + goto error; return handler; @@ -349,7 +417,10 @@ virLogHandlerDispose(void *obj) handler->inhibitor(false, handler->opaque); virLogHandlerLogFileFree(handler->files[i]); } + g_free(handler->files); + handler->nfiles = 0; + virLogHandlerCleanupTimer(handler); } @@ -393,11 +464,21 @@ virLogHandlerDomainOpenLogFile(virLogHandler *handler, file->driver = g_strdup(driver); file->domname = g_strdup(domname); - if ((file->file = virRotatingFileWriterNew(path, - handler->max_size, - handler->max_backups, - trunc, - DEFAULT_MODE)) == NULL) + /* + * Touch log files every day to prevent from removing by log files + * cleaner. + */ + if (handler->nfiles == 0 && + (handler->timer = virEventAddTimeout(LOG_HANDLER_TOUCH_TIMEOUT, + virLogHandlerTimeout, + handler, NULL) <= 0)) + goto error; + + if ((file->file = virLogHandlerNewWriter(path, + handler->max_size, + handler->max_backups, + trunc, + DEFAULT_MODE)) == NULL) goto error; VIR_APPEND_ELEMENT_COPY(handler->files, handler->nfiles, file); @@ -418,6 +499,8 @@ virLogHandlerDomainOpenLogFile(virLogHandler *handler, return pipefd[1]; error: + virLogHandlerCleanupTimer(handler); + VIR_FORCE_CLOSE(pipefd[0]); VIR_FORCE_CLOSE(pipefd[1]); handler->inhibitor(false, handler->opaque); @@ -579,11 +662,11 @@ virLogHandlerDomainAppendLogFile(virLogHandler *handler, } if (!writer) { - if (!(newwriter = virRotatingFileWriterNew(path, - handler->max_size, - handler->max_backups, - false, - DEFAULT_MODE))) + if (!(newwriter = virLogHandlerNewWriter(path, + handler->max_size, + handler->max_backups, + false, + DEFAULT_MODE))) goto cleanup; writer = newwriter; -- 2.31.1