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