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