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