Add a handler to log UART data
This change adds a new handler, to log UART data to a size-limited log
file.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
diff --git a/Makefile b/Makefile
index 544e18a..ed46115 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
all: console-server
-console-server: console-server.o util.o stdio-handler.o
+console-server: console-server.o util.o stdio-handler.o log-handler.o
clean:
rm -f console-server *.o
diff --git a/log-handler.c b/log-handler.c
new file mode 100644
index 0000000..0eb9553
--- /dev/null
+++ b/log-handler.c
@@ -0,0 +1,140 @@
+
+#include <endian.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+
+#include <linux/types.h>
+
+#include "console-server.h"
+
+struct log_handler {
+ struct handler handler;
+ struct console *console;
+ int fd;
+ size_t size;
+ size_t maxsize;
+ int pagesize;
+};
+
+
+static const char *filename = "uart.log";
+static const size_t logsize = 16 * 1024;
+
+static struct log_handler *to_log_handler(struct handler *handler)
+{
+ return container_of(handler, struct log_handler, handler);
+}
+
+static int log_init(struct handler *handler, struct console *console)
+{
+ struct log_handler *lh = to_log_handler(handler);
+ int rc;
+
+ lh->console = console;
+ lh->maxsize = logsize;
+ lh->pagesize = 4096;
+ lh->size = 0;
+
+ lh->fd = open(filename, O_RDWR | O_CREAT, 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);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int log_init_poll(struct handler *handler, struct pollfd *pollfd)
+{
+ (void)handler;
+ pollfd->fd = -1;
+ pollfd->events = 0;
+ return 0;
+}
+
+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;
+
+ pos = lseek(lh->fd, 0, SEEK_CUR);
+
+ 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)
+ 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);
+
+ return 0;
+
+}
+
+static int log_data(struct handler *handler, uint8_t *buf, size_t len)
+{
+ struct log_handler *lh = to_log_handler(handler);
+ int rc;
+
+ if (len > lh->maxsize) {
+ buf += len - lh->maxsize;
+ len = lh->maxsize;
+ }
+
+ if (lh->size + len > lh->maxsize) {
+ rc = log_trim(lh, len);
+ if (rc)
+ return rc;
+ }
+
+ rc = write_buf_to_fd(lh->fd, buf, len);
+ if (rc)
+ return rc;
+
+ lh->size += len;
+
+ return 0;
+}
+
+static void log_fini(struct handler *handler)
+{
+ struct log_handler *lh = to_log_handler(handler);
+ close(lh->fd);
+}
+
+static struct log_handler log_handler = {
+ .handler = {
+ .name = "log",
+ .init = log_init,
+ .init_poll = log_init_poll,
+ .data_in = log_data,
+ .fini = log_fini,
+ },
+};
+
+console_register_handler(&log_handler.handler);
+