xref: /openbmc/obmc-console/log-handler.c (revision e440a407463dc0f5301430e52c2d6ee33d2e4eae)
13f54de4cSJeremy Kerr 
23f54de4cSJeremy Kerr #include <endian.h>
33f54de4cSJeremy Kerr #include <err.h>
43f54de4cSJeremy Kerr #include <fcntl.h>
53f54de4cSJeremy Kerr #include <stdbool.h>
63f54de4cSJeremy Kerr #include <stdio.h>
73f54de4cSJeremy Kerr #include <stdlib.h>
83f54de4cSJeremy Kerr #include <string.h>
93f54de4cSJeremy Kerr #include <unistd.h>
103f54de4cSJeremy Kerr 
113f54de4cSJeremy Kerr #include <sys/mman.h>
123f54de4cSJeremy Kerr 
133f54de4cSJeremy Kerr #include <linux/types.h>
143f54de4cSJeremy Kerr 
153f54de4cSJeremy Kerr #include "console-server.h"
163f54de4cSJeremy Kerr 
173f54de4cSJeremy Kerr struct log_handler {
183f54de4cSJeremy Kerr 	struct handler	handler;
193f54de4cSJeremy Kerr 	struct console	*console;
203f54de4cSJeremy Kerr 	int		fd;
213f54de4cSJeremy Kerr 	size_t		size;
223f54de4cSJeremy Kerr 	size_t		maxsize;
233f54de4cSJeremy Kerr 	int		pagesize;
243f54de4cSJeremy Kerr };
253f54de4cSJeremy Kerr 
263f54de4cSJeremy Kerr 
27*e440a407SJeremy Kerr static const char *default_filename = LOCALSTATEDIR "/log/obmc-console.log";
28df94dc12SJeremy Kerr 
293f54de4cSJeremy Kerr static const size_t logsize = 16 * 1024;
303f54de4cSJeremy Kerr 
313f54de4cSJeremy Kerr static struct log_handler *to_log_handler(struct handler *handler)
323f54de4cSJeremy Kerr {
333f54de4cSJeremy Kerr 	return container_of(handler, struct log_handler, handler);
343f54de4cSJeremy Kerr }
353f54de4cSJeremy Kerr 
36d47963e5SJeremy Kerr static int log_init(struct handler *handler, struct console *console,
37d47963e5SJeremy Kerr 		struct config *config __attribute__((unused)))
383f54de4cSJeremy Kerr {
393f54de4cSJeremy Kerr 	struct log_handler *lh = to_log_handler(handler);
40b8f2845bSJeremy Kerr 	const char *filename;
413f54de4cSJeremy Kerr 	int rc;
423f54de4cSJeremy Kerr 
433f54de4cSJeremy Kerr 	lh->console = console;
443f54de4cSJeremy Kerr 	lh->maxsize = logsize;
453f54de4cSJeremy Kerr 	lh->pagesize = 4096;
463f54de4cSJeremy Kerr 	lh->size = 0;
473f54de4cSJeremy Kerr 
48b8f2845bSJeremy Kerr 	filename = config_get_value(config, "logfile");
49b8f2845bSJeremy Kerr 	if (!filename)
50b8f2845bSJeremy Kerr 		filename = default_filename;
51b8f2845bSJeremy Kerr 
523f54de4cSJeremy Kerr 	lh->fd = open(filename, O_RDWR | O_CREAT, 0644);
533f54de4cSJeremy Kerr 	if (lh->fd < 0) {
543f54de4cSJeremy Kerr 		warn("Can't open log buffer file %s", filename);
553f54de4cSJeremy Kerr 		return -1;
563f54de4cSJeremy Kerr 	}
573f54de4cSJeremy Kerr 	rc = ftruncate(lh->fd, 0);
583f54de4cSJeremy Kerr 	if (rc) {
593f54de4cSJeremy Kerr 		warn("Can't truncate file %s", filename);
603f54de4cSJeremy Kerr 		close(lh->fd);
613f54de4cSJeremy Kerr 		return -1;
623f54de4cSJeremy Kerr 	}
633f54de4cSJeremy Kerr 
643f54de4cSJeremy Kerr 	return 0;
653f54de4cSJeremy Kerr }
663f54de4cSJeremy Kerr 
673f54de4cSJeremy Kerr static int log_trim(struct log_handler *lh, size_t space)
683f54de4cSJeremy Kerr {
693f54de4cSJeremy Kerr 	int rc, n_shift_pages, shift_len, shift_start;
703f54de4cSJeremy Kerr 	off_t pos;
713f54de4cSJeremy Kerr 	void *buf;
723f54de4cSJeremy Kerr 
733f54de4cSJeremy Kerr 	pos = lseek(lh->fd, 0, SEEK_CUR);
743f54de4cSJeremy Kerr 
753f54de4cSJeremy Kerr 	n_shift_pages = (space + lh->pagesize - 1) / lh->pagesize;
763f54de4cSJeremy Kerr 	shift_start = n_shift_pages * lh->pagesize;
773f54de4cSJeremy Kerr 	shift_len = pos - (n_shift_pages * lh->pagesize);
783f54de4cSJeremy Kerr 
793f54de4cSJeremy Kerr 	buf = mmap(NULL, pos, PROT_READ | PROT_WRITE, MAP_SHARED, lh->fd, 0);
803f54de4cSJeremy Kerr 	if (buf == MAP_FAILED)
813f54de4cSJeremy Kerr 		return -1;
823f54de4cSJeremy Kerr 
833f54de4cSJeremy Kerr 	memmove(buf, buf + shift_start, shift_len);
843f54de4cSJeremy Kerr 
853f54de4cSJeremy Kerr 	munmap(buf, pos);
863f54de4cSJeremy Kerr 
873f54de4cSJeremy Kerr 	lh->size = shift_len;
883f54de4cSJeremy Kerr 	rc = ftruncate(lh->fd, lh->size);
893f54de4cSJeremy Kerr 	if (rc)
903f54de4cSJeremy Kerr 		warn("failed to truncate file");
913f54de4cSJeremy Kerr 	lseek(lh->fd, 0, SEEK_END);
923f54de4cSJeremy Kerr 
933f54de4cSJeremy Kerr 	return 0;
943f54de4cSJeremy Kerr 
953f54de4cSJeremy Kerr }
963f54de4cSJeremy Kerr 
973f54de4cSJeremy Kerr static int log_data(struct handler *handler, uint8_t *buf, size_t len)
983f54de4cSJeremy Kerr {
993f54de4cSJeremy Kerr 	struct log_handler *lh = to_log_handler(handler);
1003f54de4cSJeremy Kerr 	int rc;
1013f54de4cSJeremy Kerr 
1023f54de4cSJeremy Kerr 	if (len > lh->maxsize) {
1033f54de4cSJeremy Kerr 		buf += len - lh->maxsize;
1043f54de4cSJeremy Kerr 		len = lh->maxsize;
1053f54de4cSJeremy Kerr 	}
1063f54de4cSJeremy Kerr 
1073f54de4cSJeremy Kerr 	if (lh->size + len > lh->maxsize) {
1083f54de4cSJeremy Kerr 		rc = log_trim(lh, len);
1093f54de4cSJeremy Kerr 		if (rc)
1103f54de4cSJeremy Kerr 			return rc;
1113f54de4cSJeremy Kerr 	}
1123f54de4cSJeremy Kerr 
1133f54de4cSJeremy Kerr 	rc = write_buf_to_fd(lh->fd, buf, len);
1143f54de4cSJeremy Kerr 	if (rc)
1153f54de4cSJeremy Kerr 		return rc;
1163f54de4cSJeremy Kerr 
1173f54de4cSJeremy Kerr 	lh->size += len;
1183f54de4cSJeremy Kerr 
1193f54de4cSJeremy Kerr 	return 0;
1203f54de4cSJeremy Kerr }
1213f54de4cSJeremy Kerr 
1223f54de4cSJeremy Kerr static void log_fini(struct handler *handler)
1233f54de4cSJeremy Kerr {
1243f54de4cSJeremy Kerr 	struct log_handler *lh = to_log_handler(handler);
1253f54de4cSJeremy Kerr 	close(lh->fd);
1263f54de4cSJeremy Kerr }
1273f54de4cSJeremy Kerr 
1283f54de4cSJeremy Kerr static struct log_handler log_handler = {
1293f54de4cSJeremy Kerr 	.handler = {
1303f54de4cSJeremy Kerr 		.name		= "log",
1313f54de4cSJeremy Kerr 		.init		= log_init,
1323f54de4cSJeremy Kerr 		.data_in	= log_data,
1333f54de4cSJeremy Kerr 		.fini		= log_fini,
1343f54de4cSJeremy Kerr 	},
1353f54de4cSJeremy Kerr };
1363f54de4cSJeremy Kerr 
1373f54de4cSJeremy Kerr console_register_handler(&log_handler.handler);
1383f54de4cSJeremy Kerr 
139