log_trim: Rotate log instead of truncate

When the log buffer file's size exceeds, the log_trim() was using
moving the file's content and truncate it to a specific size.
This results in a behavior that the log file is always changing its
whole content when log_trim() is called.

It could be better to change the behavior like logrotate, that move the
original file to a new one, and create a new log file for log buffer.
This way it makes sure that the log file is always appended with new
content and thus is friendly to rsyslog.

Tested: Verify rsyslog could use imfile module to handle this log file
        normally. Before this change, rsyslog will handle it incorrectly
	when log_trim() is called.

Signed-off-by: Lei YU <mine260309@gmail.com>
Change-Id: I7647b8e21747ea98f68e4bc7c5bbf1339354bd75
diff --git a/log-handler.c b/log-handler.c
index 275cc81..2e0df6e 100644
--- a/log-handler.c
+++ b/log-handler.c
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#define _GNU_SOURCE
 #include <endian.h>
 #include <err.h>
 #include <fcntl.h>
@@ -37,6 +38,8 @@
 	size_t				size;
 	size_t				maxsize;
 	int				pagesize;
+	char				*log_filename;
+	char				*rotate_filename;
 };
 
 
@@ -50,32 +53,25 @@
 
 static int log_trim(struct log_handler *lh, size_t space)
 {
-	int rc, n_shift_pages, shift_len, shift_start;
-	off_t pos;
-	void *buf;
+	int rc;
 
-	pos = lseek(lh->fd, 0, SEEK_CUR);
+	/* Move the log buffer file to the rotate file */
+	close(lh->fd);
+	rc = rename(lh->log_filename, lh->rotate_filename);
+	if (rc) {
+		warn("Failed to rename %s to %s", lh->log_filename, lh->rotate_filename);
+		/* don't return, as we need to re-open the logfile */
+	}
 
-	n_shift_pages = (space + lh->pagesize - 1) / lh->pagesize;
-	shift_start = n_shift_pages * lh->pagesize;
-	shift_len = pos - (n_shift_pages * lh->pagesize);
-
-	buf = mmap(NULL, pos, PROT_READ | PROT_WRITE, MAP_SHARED, lh->fd, 0);
-	if (buf == MAP_FAILED)
+	lh->fd = open(lh->log_filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
+	if (lh->fd < 0) {
+		warn("Can't open log buffer file %s", lh->log_filename);
 		return -1;
+	}
 
-	memmove(buf, buf + shift_start, shift_len);
-
-	munmap(buf, pos);
-
-	lh->size = shift_len;
-	rc = ftruncate(lh->fd, lh->size);
-	if (rc)
-		warn("failed to truncate file");
-	lseek(lh->fd, 0, SEEK_END);
+	lh->size = 0;
 
 	return 0;
-
 }
 
 static int log_data(struct log_handler *lh, uint8_t *buf, size_t len)
@@ -138,6 +134,8 @@
 	lh->console = console;
 	lh->pagesize = 4096;
 	lh->size = 0;
+	lh->log_filename = NULL;
+	lh->rotate_filename = NULL;
 
 	logsize_str = config_get_value(config, "logsize");
 	rc = config_parse_logsize(logsize_str, &logsize);
@@ -152,15 +150,17 @@
 	if (!filename)
 		filename = default_filename;
 
-	lh->fd = open(filename, O_RDWR | O_CREAT, 0644);
+	lh->fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
 	if (lh->fd < 0) {
 		warn("Can't open log buffer file %s", filename);
 		return -1;
 	}
-	rc = ftruncate(lh->fd, 0);
-	if (rc) {
-		warn("Can't truncate file %s", filename);
-		close(lh->fd);
+
+	lh->log_filename = strdup(filename);
+
+	rc = asprintf(&lh->rotate_filename, "%s.1", filename);
+	if (rc < 0) {
+		warn("Failed to construct rotate filename");
 		return -1;
 	}
 
@@ -175,6 +175,8 @@
 	struct log_handler *lh = to_log_handler(handler);
 	ringbuffer_consumer_unregister(lh->rbc);
 	close(lh->fd);
+	free(lh->log_filename);
+	free(lh->rotate_filename);
 }
 
 static struct log_handler log_handler = {