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 #include <endian.h> 18 #include <err.h> 19 #include <fcntl.h> 20 #include <stdbool.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <unistd.h> 25 26 #include <sys/mman.h> 27 28 #include <linux/types.h> 29 30 #include "console-server.h" 31 32 struct log_handler { 33 struct handler handler; 34 struct console *console; 35 struct ringbuffer_consumer *rbc; 36 int fd; 37 size_t size; 38 size_t maxsize; 39 size_t pagesize; 40 char *log_filename; 41 char *rotate_filename; 42 }; 43 44 static const char *default_filename = LOCALSTATEDIR "/log/obmc-console.log"; 45 static const size_t default_logsize = 16ul * 1024ul; 46 47 static struct log_handler *to_log_handler(struct handler *handler) 48 { 49 return container_of(handler, struct log_handler, handler); 50 } 51 52 static int log_trim(struct log_handler *lh) 53 { 54 int rc; 55 56 /* Move the log buffer file to the rotate file */ 57 close(lh->fd); 58 rc = rename(lh->log_filename, lh->rotate_filename); 59 if (rc) { 60 warn("Failed to rename %s to %s", lh->log_filename, 61 lh->rotate_filename); 62 /* don't return, as we need to re-open the logfile */ 63 } 64 65 lh->fd = open(lh->log_filename, O_RDWR | O_CREAT | O_TRUNC, 0644); 66 if (lh->fd < 0) { 67 warn("Can't open log buffer file %s", lh->log_filename); 68 return -1; 69 } 70 71 lh->size = 0; 72 73 return 0; 74 } 75 76 static int log_data(struct log_handler *lh, uint8_t *buf, size_t len) 77 { 78 int rc; 79 80 if (len > lh->maxsize) { 81 buf += len - lh->maxsize; 82 len = lh->maxsize; 83 } 84 85 if (lh->size + len > lh->maxsize) { 86 rc = log_trim(lh); 87 if (rc) { 88 return rc; 89 } 90 } 91 92 rc = write_buf_to_fd(lh->fd, buf, len); 93 if (rc) { 94 return rc; 95 } 96 97 lh->size += len; 98 99 return 0; 100 } 101 102 static enum ringbuffer_poll_ret log_ringbuffer_poll(void *arg, size_t force_len 103 __attribute__((unused))) 104 { 105 struct log_handler *lh = arg; 106 uint8_t *buf; 107 size_t len; 108 int rc; 109 110 /* we log synchronously, so just dequeue everything we can, and 111 * commit straight away. */ 112 for (;;) { 113 len = ringbuffer_dequeue_peek(lh->rbc, 0, &buf); 114 if (!len) { 115 break; 116 } 117 118 rc = log_data(lh, buf, len); 119 if (rc) { 120 return RINGBUFFER_POLL_REMOVE; 121 } 122 123 ringbuffer_dequeue_commit(lh->rbc, len); 124 } 125 126 return RINGBUFFER_POLL_OK; 127 } 128 129 static int log_init(struct handler *handler, struct console *console, 130 struct config *config) 131 { 132 struct log_handler *lh = to_log_handler(handler); 133 const char *filename; 134 const char *logsize_str; 135 size_t logsize = default_logsize; 136 int rc; 137 138 lh->console = console; 139 lh->pagesize = 4096; 140 lh->size = 0; 141 lh->log_filename = NULL; 142 lh->rotate_filename = NULL; 143 144 logsize_str = config_get_value(config, "logsize"); 145 rc = config_parse_logsize(logsize_str, &logsize); 146 if (logsize_str != NULL && rc) { 147 logsize = default_logsize; 148 warn("Invalid logsize. Default to %ukB", 149 (unsigned int)(logsize >> 10)); 150 } 151 lh->maxsize = logsize <= lh->pagesize ? lh->pagesize + 1 : logsize; 152 153 filename = config_get_value(config, "logfile"); 154 if (!filename) { 155 filename = default_filename; 156 } 157 158 lh->fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644); 159 if (lh->fd < 0) { 160 warn("Can't open log buffer file %s", filename); 161 return -1; 162 } 163 164 lh->log_filename = strdup(filename); 165 166 rc = asprintf(&lh->rotate_filename, "%s.1", filename); 167 if (rc < 0) { 168 warn("Failed to construct rotate filename"); 169 return -1; 170 } 171 172 lh->rbc = console_ringbuffer_consumer_register(console, 173 log_ringbuffer_poll, lh); 174 175 return 0; 176 } 177 178 static void log_fini(struct handler *handler) 179 { 180 struct log_handler *lh = to_log_handler(handler); 181 ringbuffer_consumer_unregister(lh->rbc); 182 close(lh->fd); 183 free(lh->log_filename); 184 free(lh->rotate_filename); 185 } 186 187 static struct log_handler log_handler = { 188 .handler = { 189 .name = "log", 190 .init = log_init, 191 .fini = log_fini, 192 }, 193 }; 194 195 console_handler_register(&log_handler.handler); 196