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; 35f733c85aSJeremy Kerr struct ringbuffer_consumer *rbc; 363f54de4cSJeremy Kerr int fd; 373f54de4cSJeremy Kerr size_t size; 383f54de4cSJeremy Kerr size_t maxsize; 398f548f6cSAndrew Jeffery size_t pagesize; 4093fd8a39SLei YU char *log_filename; 4193fd8a39SLei YU char *rotate_filename; 423f54de4cSJeremy Kerr }; 433f54de4cSJeremy Kerr 44e440a407SJeremy Kerr static const char *default_filename = LOCALSTATEDIR "/log/obmc-console.log"; 455db8c792SAndrew Jeffery static const size_t default_logsize = 16ul * 1024ul; 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 52fd048328SAndrew Jeffery static int log_trim(struct log_handler *lh) 533f54de4cSJeremy Kerr { 5493fd8a39SLei YU int rc; 553f54de4cSJeremy Kerr 5693fd8a39SLei YU /* Move the log buffer file to the rotate file */ 5793fd8a39SLei YU close(lh->fd); 5893fd8a39SLei YU rc = rename(lh->log_filename, lh->rotate_filename); 5993fd8a39SLei YU if (rc) { 60a72711afSAndrew Jeffery warn("Failed to rename %s to %s", lh->log_filename, 61a72711afSAndrew Jeffery lh->rotate_filename); 6293fd8a39SLei YU /* don't return, as we need to re-open the logfile */ 6393fd8a39SLei YU } 643f54de4cSJeremy Kerr 6546d9ef29SJohn Wang lh->fd = open(lh->log_filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); 6693fd8a39SLei YU if (lh->fd < 0) { 6793fd8a39SLei YU warn("Can't open log buffer file %s", lh->log_filename); 683f54de4cSJeremy Kerr return -1; 6993fd8a39SLei YU } 703f54de4cSJeremy Kerr 7193fd8a39SLei YU lh->size = 0; 723f54de4cSJeremy Kerr 733f54de4cSJeremy Kerr return 0; 743f54de4cSJeremy Kerr } 753f54de4cSJeremy Kerr 76f733c85aSJeremy Kerr static int log_data(struct log_handler *lh, uint8_t *buf, size_t len) 773f54de4cSJeremy Kerr { 783f54de4cSJeremy Kerr int rc; 793f54de4cSJeremy Kerr 803f54de4cSJeremy Kerr if (len > lh->maxsize) { 813f54de4cSJeremy Kerr buf += len - lh->maxsize; 823f54de4cSJeremy Kerr len = lh->maxsize; 833f54de4cSJeremy Kerr } 843f54de4cSJeremy Kerr 853f54de4cSJeremy Kerr if (lh->size + len > lh->maxsize) { 86fd048328SAndrew Jeffery rc = log_trim(lh); 872834c5b1SAndrew Jeffery if (rc) { 883f54de4cSJeremy Kerr return rc; 893f54de4cSJeremy Kerr } 902834c5b1SAndrew Jeffery } 913f54de4cSJeremy Kerr 923f54de4cSJeremy Kerr rc = write_buf_to_fd(lh->fd, buf, len); 932834c5b1SAndrew Jeffery if (rc) { 943f54de4cSJeremy Kerr return rc; 952834c5b1SAndrew Jeffery } 963f54de4cSJeremy Kerr 973f54de4cSJeremy Kerr lh->size += len; 983f54de4cSJeremy Kerr 993f54de4cSJeremy Kerr return 0; 1003f54de4cSJeremy Kerr } 1013f54de4cSJeremy Kerr 102a72711afSAndrew Jeffery static enum ringbuffer_poll_ret log_ringbuffer_poll(void *arg, size_t force_len 103a72711afSAndrew Jeffery __attribute__((unused))) 104f733c85aSJeremy Kerr { 105f733c85aSJeremy Kerr struct log_handler *lh = arg; 106f733c85aSJeremy Kerr uint8_t *buf; 107f733c85aSJeremy Kerr size_t len; 108f733c85aSJeremy Kerr int rc; 109f733c85aSJeremy Kerr 110f733c85aSJeremy Kerr /* we log synchronously, so just dequeue everything we can, and 111f733c85aSJeremy Kerr * commit straight away. */ 112f733c85aSJeremy Kerr for (;;) { 113f733c85aSJeremy Kerr len = ringbuffer_dequeue_peek(lh->rbc, 0, &buf); 1142834c5b1SAndrew Jeffery if (!len) { 115f733c85aSJeremy Kerr break; 1162834c5b1SAndrew Jeffery } 117f733c85aSJeremy Kerr 118f733c85aSJeremy Kerr rc = log_data(lh, buf, len); 1192834c5b1SAndrew Jeffery if (rc) { 120f733c85aSJeremy Kerr return RINGBUFFER_POLL_REMOVE; 1212834c5b1SAndrew Jeffery } 122f733c85aSJeremy Kerr 123f733c85aSJeremy Kerr ringbuffer_dequeue_commit(lh->rbc, len); 124f733c85aSJeremy Kerr } 125f733c85aSJeremy Kerr 126f733c85aSJeremy Kerr return RINGBUFFER_POLL_OK; 127f733c85aSJeremy Kerr } 128f733c85aSJeremy Kerr 12946d9ef29SJohn Wang static int log_create(struct log_handler *lh) 13046d9ef29SJohn Wang { 13146d9ef29SJohn Wang off_t pos; 13246d9ef29SJohn Wang 13346d9ef29SJohn Wang lh->fd = open(lh->log_filename, O_WRONLY | O_CREAT | O_APPEND, 0644); 13446d9ef29SJohn Wang if (lh->fd < 0) { 13546d9ef29SJohn Wang warn("Can't open log buffer file %s", lh->log_filename); 13646d9ef29SJohn Wang return -1; 13746d9ef29SJohn Wang } 13846d9ef29SJohn Wang pos = lseek(lh->fd, 0, SEEK_CUR); 13946d9ef29SJohn Wang if (pos < 0) { 14046d9ef29SJohn Wang warn("Can't query log position for file %s", lh->log_filename); 14146d9ef29SJohn Wang close(lh->fd); 14246d9ef29SJohn Wang return -1; 14346d9ef29SJohn Wang } 14446d9ef29SJohn Wang lh->size = pos; 14546d9ef29SJohn Wang if ((size_t)pos >= lh->maxsize) { 14646d9ef29SJohn Wang return log_trim(lh); 14746d9ef29SJohn Wang } 14846d9ef29SJohn Wang 14946d9ef29SJohn Wang return 0; 15046d9ef29SJohn Wang } 15146d9ef29SJohn Wang 152e2826c7dSJeremy Kerr static struct handler *log_init(const struct handler_type *type 153e2826c7dSJeremy Kerr __attribute__((unused)), 154e2826c7dSJeremy Kerr struct console *console, struct config *config) 155f733c85aSJeremy Kerr { 156e2826c7dSJeremy Kerr struct log_handler *lh; 157b70f8713SAndrew Jeffery const char *filename; 158b70f8713SAndrew Jeffery const char *logsize_str; 15918644357SKun Yi size_t logsize = default_logsize; 160f733c85aSJeremy Kerr int rc; 161f733c85aSJeremy Kerr 162e2826c7dSJeremy Kerr lh = malloc(sizeof(*lh)); 163e2826c7dSJeremy Kerr if (!lh) { 164e2826c7dSJeremy Kerr return NULL; 165e2826c7dSJeremy Kerr } 166e2826c7dSJeremy Kerr 167f733c85aSJeremy Kerr lh->console = console; 168f733c85aSJeremy Kerr lh->pagesize = 4096; 169f733c85aSJeremy Kerr lh->size = 0; 17093fd8a39SLei YU lh->log_filename = NULL; 17193fd8a39SLei YU lh->rotate_filename = NULL; 172f733c85aSJeremy Kerr 1736424cc3bSKun Yi logsize_str = config_get_value(config, "logsize"); 174d6e8b64aSMedicine Yeh rc = config_parse_bytesize(logsize_str, &logsize); 1756424cc3bSKun Yi if (logsize_str != NULL && rc) { 1766424cc3bSKun Yi logsize = default_logsize; 1776424cc3bSKun Yi warn("Invalid logsize. Default to %ukB", 1786424cc3bSKun Yi (unsigned int)(logsize >> 10)); 1796424cc3bSKun Yi } 1806424cc3bSKun Yi lh->maxsize = logsize <= lh->pagesize ? lh->pagesize + 1 : logsize; 1816424cc3bSKun Yi 182f733c85aSJeremy Kerr filename = config_get_value(config, "logfile"); 1832834c5b1SAndrew Jeffery if (!filename) { 184f733c85aSJeremy Kerr filename = default_filename; 1852834c5b1SAndrew Jeffery } 186f733c85aSJeremy Kerr 18793fd8a39SLei YU lh->log_filename = strdup(filename); 18893fd8a39SLei YU 18993fd8a39SLei YU rc = asprintf(&lh->rotate_filename, "%s.1", filename); 19093fd8a39SLei YU if (rc < 0) { 19193fd8a39SLei YU warn("Failed to construct rotate filename"); 192e2826c7dSJeremy Kerr goto err_free; 193f733c85aSJeremy Kerr } 194f733c85aSJeremy Kerr 19546d9ef29SJohn Wang rc = log_create(lh); 19646d9ef29SJohn Wang if (rc < 0) { 197e2826c7dSJeremy Kerr goto err_free; 19846d9ef29SJohn Wang } 199f733c85aSJeremy Kerr lh->rbc = console_ringbuffer_consumer_register(console, 200f733c85aSJeremy Kerr log_ringbuffer_poll, lh); 201f733c85aSJeremy Kerr 202e2826c7dSJeremy Kerr return &lh->handler; 203e2826c7dSJeremy Kerr 204e2826c7dSJeremy Kerr err_free: 205*48d1f533SAndrew Jeffery free(lh->rotate_filename); 206e2826c7dSJeremy Kerr free(lh->log_filename); 207e2826c7dSJeremy Kerr free(lh); 208e2826c7dSJeremy Kerr return NULL; 209f733c85aSJeremy Kerr } 210f733c85aSJeremy Kerr 2113f54de4cSJeremy Kerr static void log_fini(struct handler *handler) 2123f54de4cSJeremy Kerr { 2133f54de4cSJeremy Kerr struct log_handler *lh = to_log_handler(handler); 214f733c85aSJeremy Kerr ringbuffer_consumer_unregister(lh->rbc); 2153f54de4cSJeremy Kerr close(lh->fd); 21693fd8a39SLei YU free(lh->log_filename); 21793fd8a39SLei YU free(lh->rotate_filename); 218e2826c7dSJeremy Kerr free(lh); 2193f54de4cSJeremy Kerr } 2203f54de4cSJeremy Kerr 221e2826c7dSJeremy Kerr static const struct handler_type log_handler = { 2223f54de4cSJeremy Kerr .name = "log", 2233f54de4cSJeremy Kerr .init = log_init, 2243f54de4cSJeremy Kerr .fini = log_fini, 2253f54de4cSJeremy Kerr }; 2263f54de4cSJeremy Kerr 227e2826c7dSJeremy Kerr console_handler_register(&log_handler); 228