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