blob: 0eb95531806fcca0709c9da00602b3674dda4906 [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
27static const char *filename = "uart.log";
28static const size_t logsize = 16 * 1024;
29
30static struct log_handler *to_log_handler(struct handler *handler)
31{
32 return container_of(handler, struct log_handler, handler);
33}
34
35static int log_init(struct handler *handler, struct console *console)
36{
37 struct log_handler *lh = to_log_handler(handler);
38 int rc;
39
40 lh->console = console;
41 lh->maxsize = logsize;
42 lh->pagesize = 4096;
43 lh->size = 0;
44
45 lh->fd = open(filename, O_RDWR | O_CREAT, 0644);
46 if (lh->fd < 0) {
47 warn("Can't open log buffer file %s", filename);
48 return -1;
49 }
50 rc = ftruncate(lh->fd, 0);
51 if (rc) {
52 warn("Can't truncate file %s", filename);
53 close(lh->fd);
54 return -1;
55 }
56
57 return 0;
58}
59
60static int log_init_poll(struct handler *handler, struct pollfd *pollfd)
61{
62 (void)handler;
63 pollfd->fd = -1;
64 pollfd->events = 0;
65 return 0;
66}
67
68static int log_trim(struct log_handler *lh, size_t space)
69{
70 int rc, n_shift_pages, shift_len, shift_start;
71 off_t pos;
72 void *buf;
73
74 pos = lseek(lh->fd, 0, SEEK_CUR);
75
76 n_shift_pages = (space + lh->pagesize - 1) / lh->pagesize;
77 shift_start = n_shift_pages * lh->pagesize;
78 shift_len = pos - (n_shift_pages * lh->pagesize);
79
80 buf = mmap(NULL, pos, PROT_READ | PROT_WRITE, MAP_SHARED, lh->fd, 0);
81 if (buf == MAP_FAILED)
82 return -1;
83
84 memmove(buf, buf + shift_start, shift_len);
85
86 munmap(buf, pos);
87
88 lh->size = shift_len;
89 rc = ftruncate(lh->fd, lh->size);
90 if (rc)
91 warn("failed to truncate file");
92 lseek(lh->fd, 0, SEEK_END);
93
94 return 0;
95
96}
97
98static int log_data(struct handler *handler, uint8_t *buf, size_t len)
99{
100 struct log_handler *lh = to_log_handler(handler);
101 int rc;
102
103 if (len > lh->maxsize) {
104 buf += len - lh->maxsize;
105 len = lh->maxsize;
106 }
107
108 if (lh->size + len > lh->maxsize) {
109 rc = log_trim(lh, len);
110 if (rc)
111 return rc;
112 }
113
114 rc = write_buf_to_fd(lh->fd, buf, len);
115 if (rc)
116 return rc;
117
118 lh->size += len;
119
120 return 0;
121}
122
123static void log_fini(struct handler *handler)
124{
125 struct log_handler *lh = to_log_handler(handler);
126 close(lh->fd);
127}
128
129static struct log_handler log_handler = {
130 .handler = {
131 .name = "log",
132 .init = log_init,
133 .init_poll = log_init_poll,
134 .data_in = log_data,
135 .fini = log_fini,
136 },
137};
138
139console_register_handler(&log_handler.handler);
140