blob: eb5f80f9f06091f97894b2a487c327e35947b6be [file] [log] [blame]
#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 = LOCALSTATEDIR "/log/openbmc-console.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_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,
.data_in = log_data,
.fini = log_fini,
},
};
console_register_handler(&log_handler.handler);