1 /** 2 * Copyright © 2016 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define _GNU_SOURCE 18 #include <endian.h> 19 #include <err.h> 20 #include <fcntl.h> 21 #include <stdbool.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <unistd.h> 26 27 #include <sys/mman.h> 28 29 #include <linux/types.h> 30 31 #include "console-server.h" 32 33 struct log_handler { 34 struct handler handler; 35 struct console *console; 36 struct ringbuffer_consumer *rbc; 37 int fd; 38 size_t size; 39 size_t maxsize; 40 int pagesize; 41 char *log_filename; 42 char *rotate_filename; 43 }; 44 45 46 static const char *default_filename = LOCALSTATEDIR "/log/obmc-console.log"; 47 static const size_t default_logsize = 16 * 1024; 48 49 static struct log_handler *to_log_handler(struct handler *handler) 50 { 51 return container_of(handler, struct log_handler, handler); 52 } 53 54 static int log_trim(struct log_handler *lh, size_t space) 55 { 56 int rc; 57 58 /* Move the log buffer file to the rotate file */ 59 close(lh->fd); 60 rc = rename(lh->log_filename, lh->rotate_filename); 61 if (rc) { 62 warn("Failed to rename %s to %s", lh->log_filename, lh->rotate_filename); 63 /* don't return, as we need to re-open the logfile */ 64 } 65 66 lh->fd = open(lh->log_filename, O_RDWR | O_CREAT | O_TRUNC, 0644); 67 if (lh->fd < 0) { 68 warn("Can't open log buffer file %s", lh->log_filename); 69 return -1; 70 } 71 72 lh->size = 0; 73 74 return 0; 75 } 76 77 static int log_data(struct log_handler *lh, uint8_t *buf, size_t len) 78 { 79 int rc; 80 81 if (len > lh->maxsize) { 82 buf += len - lh->maxsize; 83 len = lh->maxsize; 84 } 85 86 if (lh->size + len > lh->maxsize) { 87 rc = log_trim(lh, len); 88 if (rc) 89 return rc; 90 } 91 92 rc = write_buf_to_fd(lh->fd, buf, len); 93 if (rc) 94 return rc; 95 96 lh->size += len; 97 98 return 0; 99 } 100 101 static enum ringbuffer_poll_ret log_ringbuffer_poll(void *arg, 102 size_t force_len __attribute__((unused))) 103 { 104 struct log_handler *lh = arg; 105 uint8_t *buf; 106 size_t len; 107 int rc; 108 109 /* we log synchronously, so just dequeue everything we can, and 110 * commit straight away. */ 111 for (;;) { 112 len = ringbuffer_dequeue_peek(lh->rbc, 0, &buf); 113 if (!len) 114 break; 115 116 rc = log_data(lh, buf, len); 117 if (rc) 118 return RINGBUFFER_POLL_REMOVE; 119 120 ringbuffer_dequeue_commit(lh->rbc, len); 121 } 122 123 return RINGBUFFER_POLL_OK; 124 } 125 126 static int log_init(struct handler *handler, struct console *console, 127 struct config *config) 128 { 129 struct log_handler *lh = to_log_handler(handler); 130 const char *filename, *logsize_str; 131 size_t logsize = default_logsize; 132 int rc; 133 134 lh->console = console; 135 lh->pagesize = 4096; 136 lh->size = 0; 137 lh->log_filename = NULL; 138 lh->rotate_filename = NULL; 139 140 logsize_str = config_get_value(config, "logsize"); 141 rc = config_parse_logsize(logsize_str, &logsize); 142 if (logsize_str != NULL && rc) { 143 logsize = default_logsize; 144 warn("Invalid logsize. Default to %ukB", 145 (unsigned int)(logsize >> 10)); 146 } 147 lh->maxsize = logsize <= lh->pagesize ? lh->pagesize + 1 : logsize; 148 149 filename = config_get_value(config, "logfile"); 150 if (!filename) 151 filename = default_filename; 152 153 lh->fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644); 154 if (lh->fd < 0) { 155 warn("Can't open log buffer file %s", filename); 156 return -1; 157 } 158 159 lh->log_filename = strdup(filename); 160 161 rc = asprintf(&lh->rotate_filename, "%s.1", filename); 162 if (rc < 0) { 163 warn("Failed to construct rotate filename"); 164 return -1; 165 } 166 167 lh->rbc = console_ringbuffer_consumer_register(console, 168 log_ringbuffer_poll, lh); 169 170 return 0; 171 } 172 173 static void log_fini(struct handler *handler) 174 { 175 struct log_handler *lh = to_log_handler(handler); 176 ringbuffer_consumer_unregister(lh->rbc); 177 close(lh->fd); 178 free(lh->log_filename); 179 free(lh->rotate_filename); 180 } 181 182 static struct log_handler log_handler = { 183 .handler = { 184 .name = "log", 185 .init = log_init, 186 .fini = log_fini, 187 }, 188 }; 189 190 console_handler_register(&log_handler.handler); 191 192