xref: /openbmc/obmc-console/log-handler.c (revision 3f54de4cf052b7706723a9bb46acf8e0a2cff294)
1*3f54de4cSJeremy Kerr 
2*3f54de4cSJeremy Kerr #include <endian.h>
3*3f54de4cSJeremy Kerr #include <err.h>
4*3f54de4cSJeremy Kerr #include <fcntl.h>
5*3f54de4cSJeremy Kerr #include <stdbool.h>
6*3f54de4cSJeremy Kerr #include <stdio.h>
7*3f54de4cSJeremy Kerr #include <stdlib.h>
8*3f54de4cSJeremy Kerr #include <string.h>
9*3f54de4cSJeremy Kerr #include <unistd.h>
10*3f54de4cSJeremy Kerr 
11*3f54de4cSJeremy Kerr #include <sys/mman.h>
12*3f54de4cSJeremy Kerr 
13*3f54de4cSJeremy Kerr #include <linux/types.h>
14*3f54de4cSJeremy Kerr 
15*3f54de4cSJeremy Kerr #include "console-server.h"
16*3f54de4cSJeremy Kerr 
17*3f54de4cSJeremy Kerr struct log_handler {
18*3f54de4cSJeremy Kerr 	struct handler	handler;
19*3f54de4cSJeremy Kerr 	struct console	*console;
20*3f54de4cSJeremy Kerr 	int		fd;
21*3f54de4cSJeremy Kerr 	size_t		size;
22*3f54de4cSJeremy Kerr 	size_t		maxsize;
23*3f54de4cSJeremy Kerr 	int		pagesize;
24*3f54de4cSJeremy Kerr };
25*3f54de4cSJeremy Kerr 
26*3f54de4cSJeremy Kerr 
27*3f54de4cSJeremy Kerr static const char *filename = "uart.log";
28*3f54de4cSJeremy Kerr static const size_t logsize = 16 * 1024;
29*3f54de4cSJeremy Kerr 
30*3f54de4cSJeremy Kerr static struct log_handler *to_log_handler(struct handler *handler)
31*3f54de4cSJeremy Kerr {
32*3f54de4cSJeremy Kerr 	return container_of(handler, struct log_handler, handler);
33*3f54de4cSJeremy Kerr }
34*3f54de4cSJeremy Kerr 
35*3f54de4cSJeremy Kerr static int log_init(struct handler *handler, struct console *console)
36*3f54de4cSJeremy Kerr {
37*3f54de4cSJeremy Kerr 	struct log_handler *lh = to_log_handler(handler);
38*3f54de4cSJeremy Kerr 	int rc;
39*3f54de4cSJeremy Kerr 
40*3f54de4cSJeremy Kerr 	lh->console = console;
41*3f54de4cSJeremy Kerr 	lh->maxsize = logsize;
42*3f54de4cSJeremy Kerr 	lh->pagesize = 4096;
43*3f54de4cSJeremy Kerr 	lh->size = 0;
44*3f54de4cSJeremy Kerr 
45*3f54de4cSJeremy Kerr 	lh->fd = open(filename, O_RDWR | O_CREAT, 0644);
46*3f54de4cSJeremy Kerr 	if (lh->fd < 0) {
47*3f54de4cSJeremy Kerr 		warn("Can't open log buffer file %s", filename);
48*3f54de4cSJeremy Kerr 		return -1;
49*3f54de4cSJeremy Kerr 	}
50*3f54de4cSJeremy Kerr 	rc = ftruncate(lh->fd, 0);
51*3f54de4cSJeremy Kerr 	if (rc) {
52*3f54de4cSJeremy Kerr 		warn("Can't truncate file %s", filename);
53*3f54de4cSJeremy Kerr 		close(lh->fd);
54*3f54de4cSJeremy Kerr 		return -1;
55*3f54de4cSJeremy Kerr 	}
56*3f54de4cSJeremy Kerr 
57*3f54de4cSJeremy Kerr 	return 0;
58*3f54de4cSJeremy Kerr }
59*3f54de4cSJeremy Kerr 
60*3f54de4cSJeremy Kerr static int log_init_poll(struct handler *handler, struct pollfd *pollfd)
61*3f54de4cSJeremy Kerr {
62*3f54de4cSJeremy Kerr 	(void)handler;
63*3f54de4cSJeremy Kerr 	pollfd->fd = -1;
64*3f54de4cSJeremy Kerr 	pollfd->events = 0;
65*3f54de4cSJeremy Kerr 	return 0;
66*3f54de4cSJeremy Kerr }
67*3f54de4cSJeremy Kerr 
68*3f54de4cSJeremy Kerr static int log_trim(struct log_handler *lh, size_t space)
69*3f54de4cSJeremy Kerr {
70*3f54de4cSJeremy Kerr 	int rc, n_shift_pages, shift_len, shift_start;
71*3f54de4cSJeremy Kerr 	off_t pos;
72*3f54de4cSJeremy Kerr 	void *buf;
73*3f54de4cSJeremy Kerr 
74*3f54de4cSJeremy Kerr 	pos = lseek(lh->fd, 0, SEEK_CUR);
75*3f54de4cSJeremy Kerr 
76*3f54de4cSJeremy Kerr 	n_shift_pages = (space + lh->pagesize - 1) / lh->pagesize;
77*3f54de4cSJeremy Kerr 	shift_start = n_shift_pages * lh->pagesize;
78*3f54de4cSJeremy Kerr 	shift_len = pos - (n_shift_pages * lh->pagesize);
79*3f54de4cSJeremy Kerr 
80*3f54de4cSJeremy Kerr 	buf = mmap(NULL, pos, PROT_READ | PROT_WRITE, MAP_SHARED, lh->fd, 0);
81*3f54de4cSJeremy Kerr 	if (buf == MAP_FAILED)
82*3f54de4cSJeremy Kerr 		return -1;
83*3f54de4cSJeremy Kerr 
84*3f54de4cSJeremy Kerr 	memmove(buf, buf + shift_start, shift_len);
85*3f54de4cSJeremy Kerr 
86*3f54de4cSJeremy Kerr 	munmap(buf, pos);
87*3f54de4cSJeremy Kerr 
88*3f54de4cSJeremy Kerr 	lh->size = shift_len;
89*3f54de4cSJeremy Kerr 	rc = ftruncate(lh->fd, lh->size);
90*3f54de4cSJeremy Kerr 	if (rc)
91*3f54de4cSJeremy Kerr 		warn("failed to truncate file");
92*3f54de4cSJeremy Kerr 	lseek(lh->fd, 0, SEEK_END);
93*3f54de4cSJeremy Kerr 
94*3f54de4cSJeremy Kerr 	return 0;
95*3f54de4cSJeremy Kerr 
96*3f54de4cSJeremy Kerr }
97*3f54de4cSJeremy Kerr 
98*3f54de4cSJeremy Kerr static int log_data(struct handler *handler, uint8_t *buf, size_t len)
99*3f54de4cSJeremy Kerr {
100*3f54de4cSJeremy Kerr 	struct log_handler *lh = to_log_handler(handler);
101*3f54de4cSJeremy Kerr 	int rc;
102*3f54de4cSJeremy Kerr 
103*3f54de4cSJeremy Kerr 	if (len > lh->maxsize) {
104*3f54de4cSJeremy Kerr 		buf += len - lh->maxsize;
105*3f54de4cSJeremy Kerr 		len = lh->maxsize;
106*3f54de4cSJeremy Kerr 	}
107*3f54de4cSJeremy Kerr 
108*3f54de4cSJeremy Kerr 	if (lh->size + len > lh->maxsize) {
109*3f54de4cSJeremy Kerr 		rc = log_trim(lh, len);
110*3f54de4cSJeremy Kerr 		if (rc)
111*3f54de4cSJeremy Kerr 			return rc;
112*3f54de4cSJeremy Kerr 	}
113*3f54de4cSJeremy Kerr 
114*3f54de4cSJeremy Kerr 	rc = write_buf_to_fd(lh->fd, buf, len);
115*3f54de4cSJeremy Kerr 	if (rc)
116*3f54de4cSJeremy Kerr 		return rc;
117*3f54de4cSJeremy Kerr 
118*3f54de4cSJeremy Kerr 	lh->size += len;
119*3f54de4cSJeremy Kerr 
120*3f54de4cSJeremy Kerr 	return 0;
121*3f54de4cSJeremy Kerr }
122*3f54de4cSJeremy Kerr 
123*3f54de4cSJeremy Kerr static void log_fini(struct handler *handler)
124*3f54de4cSJeremy Kerr {
125*3f54de4cSJeremy Kerr 	struct log_handler *lh = to_log_handler(handler);
126*3f54de4cSJeremy Kerr 	close(lh->fd);
127*3f54de4cSJeremy Kerr }
128*3f54de4cSJeremy Kerr 
129*3f54de4cSJeremy Kerr static struct log_handler log_handler = {
130*3f54de4cSJeremy Kerr 	.handler = {
131*3f54de4cSJeremy Kerr 		.name		= "log",
132*3f54de4cSJeremy Kerr 		.init		= log_init,
133*3f54de4cSJeremy Kerr 		.init_poll	= log_init_poll,
134*3f54de4cSJeremy Kerr 		.data_in	= log_data,
135*3f54de4cSJeremy Kerr 		.fini		= log_fini,
136*3f54de4cSJeremy Kerr 	},
137*3f54de4cSJeremy Kerr };
138*3f54de4cSJeremy Kerr 
139*3f54de4cSJeremy Kerr console_register_handler(&log_handler.handler);
140*3f54de4cSJeremy Kerr 
141