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 17*93fd8a39SLei YU #define _GNU_SOURCE 183f54de4cSJeremy Kerr #include <endian.h> 193f54de4cSJeremy Kerr #include <err.h> 203f54de4cSJeremy Kerr #include <fcntl.h> 213f54de4cSJeremy Kerr #include <stdbool.h> 223f54de4cSJeremy Kerr #include <stdio.h> 233f54de4cSJeremy Kerr #include <stdlib.h> 243f54de4cSJeremy Kerr #include <string.h> 253f54de4cSJeremy Kerr #include <unistd.h> 263f54de4cSJeremy Kerr 273f54de4cSJeremy Kerr #include <sys/mman.h> 283f54de4cSJeremy Kerr 293f54de4cSJeremy Kerr #include <linux/types.h> 303f54de4cSJeremy Kerr 313f54de4cSJeremy Kerr #include "console-server.h" 323f54de4cSJeremy Kerr 333f54de4cSJeremy Kerr struct log_handler { 343f54de4cSJeremy Kerr struct handler handler; 353f54de4cSJeremy Kerr struct console *console; 36f733c85aSJeremy Kerr struct ringbuffer_consumer *rbc; 373f54de4cSJeremy Kerr int fd; 383f54de4cSJeremy Kerr size_t size; 393f54de4cSJeremy Kerr size_t maxsize; 403f54de4cSJeremy Kerr int pagesize; 41*93fd8a39SLei YU char *log_filename; 42*93fd8a39SLei YU char *rotate_filename; 433f54de4cSJeremy Kerr }; 443f54de4cSJeremy Kerr 453f54de4cSJeremy Kerr 46e440a407SJeremy Kerr static const char *default_filename = LOCALSTATEDIR "/log/obmc-console.log"; 476424cc3bSKun Yi static const size_t default_logsize = 16 * 1024; 483f54de4cSJeremy Kerr 493f54de4cSJeremy Kerr static struct log_handler *to_log_handler(struct handler *handler) 503f54de4cSJeremy Kerr { 513f54de4cSJeremy Kerr return container_of(handler, struct log_handler, handler); 523f54de4cSJeremy Kerr } 533f54de4cSJeremy Kerr 543f54de4cSJeremy Kerr static int log_trim(struct log_handler *lh, size_t space) 553f54de4cSJeremy Kerr { 56*93fd8a39SLei YU int rc; 573f54de4cSJeremy Kerr 58*93fd8a39SLei YU /* Move the log buffer file to the rotate file */ 59*93fd8a39SLei YU close(lh->fd); 60*93fd8a39SLei YU rc = rename(lh->log_filename, lh->rotate_filename); 61*93fd8a39SLei YU if (rc) { 62*93fd8a39SLei YU warn("Failed to rename %s to %s", lh->log_filename, lh->rotate_filename); 63*93fd8a39SLei YU /* don't return, as we need to re-open the logfile */ 64*93fd8a39SLei YU } 653f54de4cSJeremy Kerr 66*93fd8a39SLei YU lh->fd = open(lh->log_filename, O_RDWR | O_CREAT | O_TRUNC, 0644); 67*93fd8a39SLei YU if (lh->fd < 0) { 68*93fd8a39SLei YU warn("Can't open log buffer file %s", lh->log_filename); 693f54de4cSJeremy Kerr return -1; 70*93fd8a39SLei YU } 713f54de4cSJeremy Kerr 72*93fd8a39SLei YU lh->size = 0; 733f54de4cSJeremy Kerr 743f54de4cSJeremy Kerr return 0; 753f54de4cSJeremy Kerr } 763f54de4cSJeremy Kerr 77f733c85aSJeremy Kerr static int log_data(struct log_handler *lh, uint8_t *buf, size_t len) 783f54de4cSJeremy Kerr { 793f54de4cSJeremy Kerr int rc; 803f54de4cSJeremy Kerr 813f54de4cSJeremy Kerr if (len > lh->maxsize) { 823f54de4cSJeremy Kerr buf += len - lh->maxsize; 833f54de4cSJeremy Kerr len = lh->maxsize; 843f54de4cSJeremy Kerr } 853f54de4cSJeremy Kerr 863f54de4cSJeremy Kerr if (lh->size + len > lh->maxsize) { 873f54de4cSJeremy Kerr rc = log_trim(lh, len); 883f54de4cSJeremy Kerr if (rc) 893f54de4cSJeremy Kerr return rc; 903f54de4cSJeremy Kerr } 913f54de4cSJeremy Kerr 923f54de4cSJeremy Kerr rc = write_buf_to_fd(lh->fd, buf, len); 933f54de4cSJeremy Kerr if (rc) 943f54de4cSJeremy Kerr return rc; 953f54de4cSJeremy Kerr 963f54de4cSJeremy Kerr lh->size += len; 973f54de4cSJeremy Kerr 983f54de4cSJeremy Kerr return 0; 993f54de4cSJeremy Kerr } 1003f54de4cSJeremy Kerr 101f733c85aSJeremy Kerr static enum ringbuffer_poll_ret log_ringbuffer_poll(void *arg, 102f733c85aSJeremy Kerr size_t force_len __attribute__((unused))) 103f733c85aSJeremy Kerr { 104f733c85aSJeremy Kerr struct log_handler *lh = arg; 105f733c85aSJeremy Kerr uint8_t *buf; 106f733c85aSJeremy Kerr size_t len; 107f733c85aSJeremy Kerr int rc; 108f733c85aSJeremy Kerr 109f733c85aSJeremy Kerr /* we log synchronously, so just dequeue everything we can, and 110f733c85aSJeremy Kerr * commit straight away. */ 111f733c85aSJeremy Kerr for (;;) { 112f733c85aSJeremy Kerr len = ringbuffer_dequeue_peek(lh->rbc, 0, &buf); 113f733c85aSJeremy Kerr if (!len) 114f733c85aSJeremy Kerr break; 115f733c85aSJeremy Kerr 116f733c85aSJeremy Kerr rc = log_data(lh, buf, len); 117f733c85aSJeremy Kerr if (rc) 118f733c85aSJeremy Kerr return RINGBUFFER_POLL_REMOVE; 119f733c85aSJeremy Kerr 120f733c85aSJeremy Kerr ringbuffer_dequeue_commit(lh->rbc, len); 121f733c85aSJeremy Kerr } 122f733c85aSJeremy Kerr 123f733c85aSJeremy Kerr return RINGBUFFER_POLL_OK; 124f733c85aSJeremy Kerr } 125f733c85aSJeremy Kerr 126f733c85aSJeremy Kerr static int log_init(struct handler *handler, struct console *console, 1276424cc3bSKun Yi struct config *config) 128f733c85aSJeremy Kerr { 129f733c85aSJeremy Kerr struct log_handler *lh = to_log_handler(handler); 1306424cc3bSKun Yi const char *filename, *logsize_str; 13118644357SKun Yi size_t logsize = default_logsize; 132f733c85aSJeremy Kerr int rc; 133f733c85aSJeremy Kerr 134f733c85aSJeremy Kerr lh->console = console; 135f733c85aSJeremy Kerr lh->pagesize = 4096; 136f733c85aSJeremy Kerr lh->size = 0; 137*93fd8a39SLei YU lh->log_filename = NULL; 138*93fd8a39SLei YU lh->rotate_filename = NULL; 139f733c85aSJeremy Kerr 1406424cc3bSKun Yi logsize_str = config_get_value(config, "logsize"); 1416424cc3bSKun Yi rc = config_parse_logsize(logsize_str, &logsize); 1426424cc3bSKun Yi if (logsize_str != NULL && rc) { 1436424cc3bSKun Yi logsize = default_logsize; 1446424cc3bSKun Yi warn("Invalid logsize. Default to %ukB", 1456424cc3bSKun Yi (unsigned int)(logsize >> 10)); 1466424cc3bSKun Yi } 1476424cc3bSKun Yi lh->maxsize = logsize <= lh->pagesize ? lh->pagesize + 1 : logsize; 1486424cc3bSKun Yi 149f733c85aSJeremy Kerr filename = config_get_value(config, "logfile"); 150f733c85aSJeremy Kerr if (!filename) 151f733c85aSJeremy Kerr filename = default_filename; 152f733c85aSJeremy Kerr 153*93fd8a39SLei YU lh->fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644); 154f733c85aSJeremy Kerr if (lh->fd < 0) { 155f733c85aSJeremy Kerr warn("Can't open log buffer file %s", filename); 156f733c85aSJeremy Kerr return -1; 157f733c85aSJeremy Kerr } 158*93fd8a39SLei YU 159*93fd8a39SLei YU lh->log_filename = strdup(filename); 160*93fd8a39SLei YU 161*93fd8a39SLei YU rc = asprintf(&lh->rotate_filename, "%s.1", filename); 162*93fd8a39SLei YU if (rc < 0) { 163*93fd8a39SLei YU warn("Failed to construct rotate filename"); 164f733c85aSJeremy Kerr return -1; 165f733c85aSJeremy Kerr } 166f733c85aSJeremy Kerr 167f733c85aSJeremy Kerr lh->rbc = console_ringbuffer_consumer_register(console, 168f733c85aSJeremy Kerr log_ringbuffer_poll, lh); 169f733c85aSJeremy Kerr 170f733c85aSJeremy Kerr return 0; 171f733c85aSJeremy Kerr } 172f733c85aSJeremy Kerr 1733f54de4cSJeremy Kerr static void log_fini(struct handler *handler) 1743f54de4cSJeremy Kerr { 1753f54de4cSJeremy Kerr struct log_handler *lh = to_log_handler(handler); 176f733c85aSJeremy Kerr ringbuffer_consumer_unregister(lh->rbc); 1773f54de4cSJeremy Kerr close(lh->fd); 178*93fd8a39SLei YU free(lh->log_filename); 179*93fd8a39SLei YU free(lh->rotate_filename); 1803f54de4cSJeremy Kerr } 1813f54de4cSJeremy Kerr 1823f54de4cSJeremy Kerr static struct log_handler log_handler = { 1833f54de4cSJeremy Kerr .handler = { 1843f54de4cSJeremy Kerr .name = "log", 1853f54de4cSJeremy Kerr .init = log_init, 1863f54de4cSJeremy Kerr .fini = log_fini, 1873f54de4cSJeremy Kerr }, 1883f54de4cSJeremy Kerr }; 1893f54de4cSJeremy Kerr 19055c9712dSJeremy Kerr console_handler_register(&log_handler.handler); 1913f54de4cSJeremy Kerr 192