blob: 571fba6be5eac7befdd15c4836812dfcefc07a2d [file] [log] [blame]
Jeremy Kerr9326d772016-03-17 17:15:02 +08001/**
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 */
Jeremy Kerr3f54de42016-03-09 18:10:15 +080016
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"
Alexander Hansen1e04f442024-06-12 16:35:58 +020031#include "config.h"
Jeremy Kerr3f54de42016-03-09 18:10:15 +080032
33struct log_handler {
Andrew Jefferya72711a2023-04-18 18:19:41 +093034 struct handler handler;
35 struct console *console;
36 struct ringbuffer_consumer *rbc;
37 int fd;
38 size_t size;
39 size_t maxsize;
40 size_t pagesize;
41 char *log_filename;
42 char *rotate_filename;
Jeremy Kerr3f54de42016-03-09 18:10:15 +080043};
44
Jeremy Kerre440a402016-03-17 16:34:14 +080045static const char *default_filename = LOCALSTATEDIR "/log/obmc-console.log";
Andrew Jeffery5db8c792023-04-18 21:48:24 +093046static const size_t default_logsize = 16ul * 1024ul;
Jeremy Kerr3f54de42016-03-09 18:10:15 +080047
48static struct log_handler *to_log_handler(struct handler *handler)
49{
50 return container_of(handler, struct log_handler, handler);
51}
52
Andrew Jefferyfd048322023-04-18 12:02:01 +093053static int log_trim(struct log_handler *lh)
Jeremy Kerr3f54de42016-03-09 18:10:15 +080054{
Lei YU93fd8a32022-03-30 10:15:25 +080055 int rc;
Jeremy Kerr3f54de42016-03-09 18:10:15 +080056
Lei YU93fd8a32022-03-30 10:15:25 +080057 /* Move the log buffer file to the rotate file */
58 close(lh->fd);
59 rc = rename(lh->log_filename, lh->rotate_filename);
60 if (rc) {
Andrew Jefferya72711a2023-04-18 18:19:41 +093061 warn("Failed to rename %s to %s", lh->log_filename,
62 lh->rotate_filename);
Lei YU93fd8a32022-03-30 10:15:25 +080063 /* don't return, as we need to re-open the logfile */
64 }
Jeremy Kerr3f54de42016-03-09 18:10:15 +080065
John Wang46d9ef22023-01-16 11:04:51 +080066 lh->fd = open(lh->log_filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
Lei YU93fd8a32022-03-30 10:15:25 +080067 if (lh->fd < 0) {
68 warn("Can't open log buffer file %s", lh->log_filename);
Jeremy Kerr3f54de42016-03-09 18:10:15 +080069 return -1;
Lei YU93fd8a32022-03-30 10:15:25 +080070 }
Jeremy Kerr3f54de42016-03-09 18:10:15 +080071
Lei YU93fd8a32022-03-30 10:15:25 +080072 lh->size = 0;
Jeremy Kerr3f54de42016-03-09 18:10:15 +080073
74 return 0;
Jeremy Kerr3f54de42016-03-09 18:10:15 +080075}
76
Jeremy Kerrf733c852017-02-07 18:40:10 +080077static int log_data(struct log_handler *lh, uint8_t *buf, size_t len)
Jeremy Kerr3f54de42016-03-09 18:10:15 +080078{
Jeremy Kerr3f54de42016-03-09 18:10:15 +080079 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) {
Andrew Jefferyfd048322023-04-18 12:02:01 +093087 rc = log_trim(lh);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093088 if (rc) {
Jeremy Kerr3f54de42016-03-09 18:10:15 +080089 return rc;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093090 }
Jeremy Kerr3f54de42016-03-09 18:10:15 +080091 }
92
93 rc = write_buf_to_fd(lh->fd, buf, len);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093094 if (rc) {
Jeremy Kerr3f54de42016-03-09 18:10:15 +080095 return rc;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093096 }
Jeremy Kerr3f54de42016-03-09 18:10:15 +080097
98 lh->size += len;
99
100 return 0;
101}
102
Andrew Jefferya72711a2023-04-18 18:19:41 +0930103static enum ringbuffer_poll_ret log_ringbuffer_poll(void *arg, size_t force_len
104 __attribute__((unused)))
Jeremy Kerrf733c852017-02-07 18:40:10 +0800105{
106 struct log_handler *lh = arg;
107 uint8_t *buf;
108 size_t len;
109 int rc;
110
111 /* we log synchronously, so just dequeue everything we can, and
112 * commit straight away. */
113 for (;;) {
114 len = ringbuffer_dequeue_peek(lh->rbc, 0, &buf);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930115 if (!len) {
Jeremy Kerrf733c852017-02-07 18:40:10 +0800116 break;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930117 }
Jeremy Kerrf733c852017-02-07 18:40:10 +0800118
119 rc = log_data(lh, buf, len);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930120 if (rc) {
Jeremy Kerrf733c852017-02-07 18:40:10 +0800121 return RINGBUFFER_POLL_REMOVE;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930122 }
Jeremy Kerrf733c852017-02-07 18:40:10 +0800123
124 ringbuffer_dequeue_commit(lh->rbc, len);
125 }
126
127 return RINGBUFFER_POLL_OK;
128}
129
John Wang46d9ef22023-01-16 11:04:51 +0800130static int log_create(struct log_handler *lh)
131{
132 off_t pos;
133
134 lh->fd = open(lh->log_filename, O_WRONLY | O_CREAT | O_APPEND, 0644);
135 if (lh->fd < 0) {
136 warn("Can't open log buffer file %s", lh->log_filename);
137 return -1;
138 }
139 pos = lseek(lh->fd, 0, SEEK_CUR);
140 if (pos < 0) {
141 warn("Can't query log position for file %s", lh->log_filename);
142 close(lh->fd);
143 return -1;
144 }
145 lh->size = pos;
146 if ((size_t)pos >= lh->maxsize) {
147 return log_trim(lh);
148 }
149
150 return 0;
151}
152
Jeremy Kerre2826c72024-07-05 10:54:21 +0800153static struct handler *log_init(const struct handler_type *type
154 __attribute__((unused)),
155 struct console *console, struct config *config)
Jeremy Kerrf733c852017-02-07 18:40:10 +0800156{
Jeremy Kerre2826c72024-07-05 10:54:21 +0800157 struct log_handler *lh;
Andrew Jefferyb70f8712023-04-19 12:53:34 +0930158 const char *filename;
159 const char *logsize_str;
Kun Yi18644352018-08-27 11:37:42 -0700160 size_t logsize = default_logsize;
Jeremy Kerrf733c852017-02-07 18:40:10 +0800161 int rc;
162
Jeremy Kerre2826c72024-07-05 10:54:21 +0800163 lh = malloc(sizeof(*lh));
164 if (!lh) {
165 return NULL;
166 }
167
Jeremy Kerrf733c852017-02-07 18:40:10 +0800168 lh->console = console;
Jeremy Kerrf733c852017-02-07 18:40:10 +0800169 lh->pagesize = 4096;
170 lh->size = 0;
Lei YU93fd8a32022-03-30 10:15:25 +0800171 lh->log_filename = NULL;
172 lh->rotate_filename = NULL;
Jeremy Kerrf733c852017-02-07 18:40:10 +0800173
Kun Yi6424cc32018-06-14 14:09:28 -0700174 logsize_str = config_get_value(config, "logsize");
Medicine Yehd6e8b642024-03-18 01:49:17 -0700175 rc = config_parse_bytesize(logsize_str, &logsize);
Kun Yi6424cc32018-06-14 14:09:28 -0700176 if (logsize_str != NULL && rc) {
177 logsize = default_logsize;
178 warn("Invalid logsize. Default to %ukB",
Andrew Jefferya72711a2023-04-18 18:19:41 +0930179 (unsigned int)(logsize >> 10));
Kun Yi6424cc32018-06-14 14:09:28 -0700180 }
181 lh->maxsize = logsize <= lh->pagesize ? lh->pagesize + 1 : logsize;
182
Alexander Hansena6b29102024-07-10 15:33:37 +0200183 filename = config_get_section_value(config, console->console_id,
184 "logfile");
185
Alexander Hansen6498f9f2024-09-13 17:15:33 +0200186 if (!filename && config_count_sections(config) == 0) {
Alexander Hansena6b29102024-07-10 15:33:37 +0200187 filename = config_get_value(config, "logfile");
188 }
189
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930190 if (!filename) {
Jeremy Kerrf733c852017-02-07 18:40:10 +0800191 filename = default_filename;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930192 }
Jeremy Kerrf733c852017-02-07 18:40:10 +0800193
Lei YU93fd8a32022-03-30 10:15:25 +0800194 lh->log_filename = strdup(filename);
195
196 rc = asprintf(&lh->rotate_filename, "%s.1", filename);
197 if (rc < 0) {
198 warn("Failed to construct rotate filename");
Jeremy Kerre2826c72024-07-05 10:54:21 +0800199 goto err_free;
Jeremy Kerrf733c852017-02-07 18:40:10 +0800200 }
201
John Wang46d9ef22023-01-16 11:04:51 +0800202 rc = log_create(lh);
203 if (rc < 0) {
Jeremy Kerre2826c72024-07-05 10:54:21 +0800204 goto err_free;
John Wang46d9ef22023-01-16 11:04:51 +0800205 }
Jeremy Kerrf733c852017-02-07 18:40:10 +0800206 lh->rbc = console_ringbuffer_consumer_register(console,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930207 log_ringbuffer_poll, lh);
Jeremy Kerrf733c852017-02-07 18:40:10 +0800208
Jeremy Kerre2826c72024-07-05 10:54:21 +0800209 return &lh->handler;
210
211err_free:
Andrew Jeffery48d1f532024-07-09 14:46:14 +0930212 free(lh->rotate_filename);
Jeremy Kerre2826c72024-07-05 10:54:21 +0800213 free(lh->log_filename);
214 free(lh);
215 return NULL;
Jeremy Kerrf733c852017-02-07 18:40:10 +0800216}
217
Jeremy Kerr3f54de42016-03-09 18:10:15 +0800218static void log_fini(struct handler *handler)
219{
220 struct log_handler *lh = to_log_handler(handler);
Jeremy Kerrf733c852017-02-07 18:40:10 +0800221 ringbuffer_consumer_unregister(lh->rbc);
Jeremy Kerr3f54de42016-03-09 18:10:15 +0800222 close(lh->fd);
Lei YU93fd8a32022-03-30 10:15:25 +0800223 free(lh->log_filename);
224 free(lh->rotate_filename);
Jeremy Kerre2826c72024-07-05 10:54:21 +0800225 free(lh);
Jeremy Kerr3f54de42016-03-09 18:10:15 +0800226}
227
Jeremy Kerre2826c72024-07-05 10:54:21 +0800228static const struct handler_type log_handler = {
229 .name = "log",
230 .init = log_init,
231 .fini = log_fini,
Jeremy Kerr3f54de42016-03-09 18:10:15 +0800232};
233
Jeremy Kerre2826c72024-07-05 10:54:21 +0800234console_handler_register(&log_handler);