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

Reply via email to