19326d779SJeremy Kerr /** 29326d779SJeremy Kerr * Copyright © 2016 IBM Corporation 39326d779SJeremy Kerr * 49326d779SJeremy Kerr * Licensed under the Apache License, Version 2.0 (the "License"); 59326d779SJeremy Kerr * you may not use this file except in compliance with the License. 69326d779SJeremy Kerr * You may obtain a copy of the License at 79326d779SJeremy Kerr * 89326d779SJeremy Kerr * http://www.apache.org/licenses/LICENSE-2.0 99326d779SJeremy Kerr * 109326d779SJeremy Kerr * Unless required by applicable law or agreed to in writing, software 119326d779SJeremy Kerr * distributed under the License is distributed on an "AS IS" BASIS, 129326d779SJeremy Kerr * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139326d779SJeremy Kerr * See the License for the specific language governing permissions and 149326d779SJeremy Kerr * limitations under the License. 159326d779SJeremy Kerr */ 163f54de4cSJeremy Kerr 173f54de4cSJeremy Kerr #include <endian.h> 183f54de4cSJeremy Kerr #include <err.h> 193f54de4cSJeremy Kerr #include <fcntl.h> 203f54de4cSJeremy Kerr #include <stdbool.h> 213f54de4cSJeremy Kerr #include <stdio.h> 223f54de4cSJeremy Kerr #include <stdlib.h> 233f54de4cSJeremy Kerr #include <string.h> 243f54de4cSJeremy Kerr #include <unistd.h> 253f54de4cSJeremy Kerr 263f54de4cSJeremy Kerr #include <sys/mman.h> 273f54de4cSJeremy Kerr 283f54de4cSJeremy Kerr #include <linux/types.h> 293f54de4cSJeremy Kerr 303f54de4cSJeremy Kerr #include "console-server.h" 313f54de4cSJeremy Kerr 323f54de4cSJeremy Kerr struct log_handler { 333f54de4cSJeremy Kerr struct handler handler; 343f54de4cSJeremy Kerr struct console *console; 35*f733c85aSJeremy Kerr struct ringbuffer_consumer *rbc; 363f54de4cSJeremy Kerr int fd; 373f54de4cSJeremy Kerr size_t size; 383f54de4cSJeremy Kerr size_t maxsize; 393f54de4cSJeremy Kerr int pagesize; 403f54de4cSJeremy Kerr }; 413f54de4cSJeremy Kerr 423f54de4cSJeremy Kerr 43e440a407SJeremy Kerr static const char *default_filename = LOCALSTATEDIR "/log/obmc-console.log"; 44df94dc12SJeremy Kerr 453f54de4cSJeremy Kerr static const size_t logsize = 16 * 1024; 463f54de4cSJeremy Kerr 473f54de4cSJeremy Kerr static struct log_handler *to_log_handler(struct handler *handler) 483f54de4cSJeremy Kerr { 493f54de4cSJeremy Kerr return container_of(handler, struct log_handler, handler); 503f54de4cSJeremy Kerr } 513f54de4cSJeremy Kerr 523f54de4cSJeremy Kerr static int log_trim(struct log_handler *lh, size_t space) 533f54de4cSJeremy Kerr { 543f54de4cSJeremy Kerr int rc, n_shift_pages, shift_len, shift_start; 553f54de4cSJeremy Kerr off_t pos; 563f54de4cSJeremy Kerr void *buf; 573f54de4cSJeremy Kerr 583f54de4cSJeremy Kerr pos = lseek(lh->fd, 0, SEEK_CUR); 593f54de4cSJeremy Kerr 603f54de4cSJeremy Kerr n_shift_pages = (space + lh->pagesize - 1) / lh->pagesize; 613f54de4cSJeremy Kerr shift_start = n_shift_pages * lh->pagesize; 623f54de4cSJeremy Kerr shift_len = pos - (n_shift_pages * lh->pagesize); 633f54de4cSJeremy Kerr 643f54de4cSJeremy Kerr buf = mmap(NULL, pos, PROT_READ | PROT_WRITE, MAP_SHARED, lh->fd, 0); 653f54de4cSJeremy Kerr if (buf == MAP_FAILED) 663f54de4cSJeremy Kerr return -1; 673f54de4cSJeremy Kerr 683f54de4cSJeremy Kerr memmove(buf, buf + shift_start, shift_len); 693f54de4cSJeremy Kerr 703f54de4cSJeremy Kerr munmap(buf, pos); 713f54de4cSJeremy Kerr 723f54de4cSJeremy Kerr lh->size = shift_len; 733f54de4cSJeremy Kerr rc = ftruncate(lh->fd, lh->size); 743f54de4cSJeremy Kerr if (rc) 753f54de4cSJeremy Kerr warn("failed to truncate file"); 763f54de4cSJeremy Kerr lseek(lh->fd, 0, SEEK_END); 773f54de4cSJeremy Kerr 783f54de4cSJeremy Kerr return 0; 793f54de4cSJeremy Kerr 803f54de4cSJeremy Kerr } 813f54de4cSJeremy Kerr 82*f733c85aSJeremy Kerr static int log_data(struct log_handler *lh, uint8_t *buf, size_t len) 833f54de4cSJeremy Kerr { 843f54de4cSJeremy Kerr int rc; 853f54de4cSJeremy Kerr 863f54de4cSJeremy Kerr if (len > lh->maxsize) { 873f54de4cSJeremy Kerr buf += len - lh->maxsize; 883f54de4cSJeremy Kerr len = lh->maxsize; 893f54de4cSJeremy Kerr } 903f54de4cSJeremy Kerr 913f54de4cSJeremy Kerr if (lh->size + len > lh->maxsize) { 923f54de4cSJeremy Kerr rc = log_trim(lh, len); 933f54de4cSJeremy Kerr if (rc) 943f54de4cSJeremy Kerr return rc; 953f54de4cSJeremy Kerr } 963f54de4cSJeremy Kerr 973f54de4cSJeremy Kerr rc = write_buf_to_fd(lh->fd, buf, len); 983f54de4cSJeremy Kerr if (rc) 993f54de4cSJeremy Kerr return rc; 1003f54de4cSJeremy Kerr 1013f54de4cSJeremy Kerr lh->size += len; 1023f54de4cSJeremy Kerr 1033f54de4cSJeremy Kerr return 0; 1043f54de4cSJeremy Kerr } 1053f54de4cSJeremy Kerr 106*f733c85aSJeremy Kerr static enum ringbuffer_poll_ret log_ringbuffer_poll(void *arg, 107*f733c85aSJeremy Kerr size_t force_len __attribute__((unused))) 108*f733c85aSJeremy Kerr { 109*f733c85aSJeremy Kerr struct log_handler *lh = arg; 110*f733c85aSJeremy Kerr uint8_t *buf; 111*f733c85aSJeremy Kerr size_t len; 112*f733c85aSJeremy Kerr int rc; 113*f733c85aSJeremy Kerr 114*f733c85aSJeremy Kerr /* we log synchronously, so just dequeue everything we can, and 115*f733c85aSJeremy Kerr * commit straight away. */ 116*f733c85aSJeremy Kerr for (;;) { 117*f733c85aSJeremy Kerr len = ringbuffer_dequeue_peek(lh->rbc, 0, &buf); 118*f733c85aSJeremy Kerr if (!len) 119*f733c85aSJeremy Kerr break; 120*f733c85aSJeremy Kerr 121*f733c85aSJeremy Kerr rc = log_data(lh, buf, len); 122*f733c85aSJeremy Kerr if (rc) 123*f733c85aSJeremy Kerr return RINGBUFFER_POLL_REMOVE; 124*f733c85aSJeremy Kerr 125*f733c85aSJeremy Kerr ringbuffer_dequeue_commit(lh->rbc, len); 126*f733c85aSJeremy Kerr } 127*f733c85aSJeremy Kerr 128*f733c85aSJeremy Kerr return RINGBUFFER_POLL_OK; 129*f733c85aSJeremy Kerr } 130*f733c85aSJeremy Kerr 131*f733c85aSJeremy Kerr static int log_init(struct handler *handler, struct console *console, 132*f733c85aSJeremy Kerr struct config *config __attribute__((unused))) 133*f733c85aSJeremy Kerr { 134*f733c85aSJeremy Kerr struct log_handler *lh = to_log_handler(handler); 135*f733c85aSJeremy Kerr const char *filename; 136*f733c85aSJeremy Kerr int rc; 137*f733c85aSJeremy Kerr 138*f733c85aSJeremy Kerr lh->console = console; 139*f733c85aSJeremy Kerr lh->maxsize = logsize; 140*f733c85aSJeremy Kerr lh->pagesize = 4096; 141*f733c85aSJeremy Kerr lh->size = 0; 142*f733c85aSJeremy Kerr 143*f733c85aSJeremy Kerr filename = config_get_value(config, "logfile"); 144*f733c85aSJeremy Kerr if (!filename) 145*f733c85aSJeremy Kerr filename = default_filename; 146*f733c85aSJeremy Kerr 147*f733c85aSJeremy Kerr lh->fd = open(filename, O_RDWR | O_CREAT, 0644); 148*f733c85aSJeremy Kerr if (lh->fd < 0) { 149*f733c85aSJeremy Kerr warn("Can't open log buffer file %s", filename); 150*f733c85aSJeremy Kerr return -1; 151*f733c85aSJeremy Kerr } 152*f733c85aSJeremy Kerr rc = ftruncate(lh->fd, 0); 153*f733c85aSJeremy Kerr if (rc) { 154*f733c85aSJeremy Kerr warn("Can't truncate file %s", filename); 155*f733c85aSJeremy Kerr close(lh->fd); 156*f733c85aSJeremy Kerr return -1; 157*f733c85aSJeremy Kerr } 158*f733c85aSJeremy Kerr 159*f733c85aSJeremy Kerr lh->rbc = console_ringbuffer_consumer_register(console, 160*f733c85aSJeremy Kerr log_ringbuffer_poll, lh); 161*f733c85aSJeremy Kerr 162*f733c85aSJeremy Kerr return 0; 163*f733c85aSJeremy Kerr } 164*f733c85aSJeremy Kerr 1653f54de4cSJeremy Kerr static void log_fini(struct handler *handler) 1663f54de4cSJeremy Kerr { 1673f54de4cSJeremy Kerr struct log_handler *lh = to_log_handler(handler); 168*f733c85aSJeremy Kerr ringbuffer_consumer_unregister(lh->rbc); 1693f54de4cSJeremy Kerr close(lh->fd); 1703f54de4cSJeremy Kerr } 1713f54de4cSJeremy Kerr 1723f54de4cSJeremy Kerr static struct log_handler log_handler = { 1733f54de4cSJeremy Kerr .handler = { 1743f54de4cSJeremy Kerr .name = "log", 1753f54de4cSJeremy Kerr .init = log_init, 1763f54de4cSJeremy Kerr .fini = log_fini, 1773f54de4cSJeremy Kerr }, 1783f54de4cSJeremy Kerr }; 1793f54de4cSJeremy Kerr 18055c9712dSJeremy Kerr console_handler_register(&log_handler.handler); 1813f54de4cSJeremy Kerr 182