blob: b77dd82d4ce7c427c71c01340d5706c45a765283 [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"
31
32struct log_handler {
Andrew Jefferya72711a2023-04-18 18:19:41 +093033 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;
Jeremy Kerr3f54de42016-03-09 18:10:15 +080042};
43
Jeremy Kerre440a402016-03-17 16:34:14 +080044static const char *default_filename = LOCALSTATEDIR "/log/obmc-console.log";
Andrew Jeffery5db8c792023-04-18 21:48:24 +093045static const size_t default_logsize = 16ul * 1024ul;
Jeremy Kerr3f54de42016-03-09 18:10:15 +080046
47static struct log_handler *to_log_handler(struct handler *handler)
48{
49 return container_of(handler, struct log_handler, handler);
50}
51
Andrew Jefferyfd048322023-04-18 12:02:01 +093052static int log_trim(struct log_handler *lh)
Jeremy Kerr3f54de42016-03-09 18:10:15 +080053{
Lei YU93fd8a32022-03-30 10:15:25 +080054 int rc;
Jeremy Kerr3f54de42016-03-09 18:10:15 +080055
Lei YU93fd8a32022-03-30 10:15:25 +080056 /* 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) {
Andrew Jefferya72711a2023-04-18 18:19:41 +093060 warn("Failed to rename %s to %s", lh->log_filename,
61 lh->rotate_filename);
Lei YU93fd8a32022-03-30 10:15:25 +080062 /* don't return, as we need to re-open the logfile */
63 }
Jeremy Kerr3f54de42016-03-09 18:10:15 +080064
John Wang46d9ef22023-01-16 11:04:51 +080065 lh->fd = open(lh->log_filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
Lei YU93fd8a32022-03-30 10:15:25 +080066 if (lh->fd < 0) {
67 warn("Can't open log buffer file %s", lh->log_filename);
Jeremy Kerr3f54de42016-03-09 18:10:15 +080068 return -1;
Lei YU93fd8a32022-03-30 10:15:25 +080069 }
Jeremy Kerr3f54de42016-03-09 18:10:15 +080070
Lei YU93fd8a32022-03-30 10:15:25 +080071 lh->size = 0;
Jeremy Kerr3f54de42016-03-09 18:10:15 +080072
73 return 0;
Jeremy Kerr3f54de42016-03-09 18:10:15 +080074}
75
Jeremy Kerrf733c852017-02-07 18:40:10 +080076static int log_data(struct log_handler *lh, uint8_t *buf, size_t len)
Jeremy Kerr3f54de42016-03-09 18:10:15 +080077{
Jeremy Kerr3f54de42016-03-09 18:10:15 +080078 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) {
Andrew Jefferyfd048322023-04-18 12:02:01 +093086 rc = log_trim(lh);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093087 if (rc) {
Jeremy Kerr3f54de42016-03-09 18:10:15 +080088 return rc;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093089 }
Jeremy Kerr3f54de42016-03-09 18:10:15 +080090 }
91
92 rc = write_buf_to_fd(lh->fd, buf, len);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093093 if (rc) {
Jeremy Kerr3f54de42016-03-09 18:10:15 +080094 return rc;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093095 }
Jeremy Kerr3f54de42016-03-09 18:10:15 +080096
97 lh->size += len;
98
99 return 0;
100}
101
Andrew Jefferya72711a2023-04-18 18:19:41 +0930102static enum ringbuffer_poll_ret log_ringbuffer_poll(void *arg, size_t force_len
103 __attribute__((unused)))
Jeremy Kerrf733c852017-02-07 18:40:10 +0800104{
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);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930114 if (!len) {
Jeremy Kerrf733c852017-02-07 18:40:10 +0800115 break;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930116 }
Jeremy Kerrf733c852017-02-07 18:40:10 +0800117
118 rc = log_data(lh, buf, len);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930119 if (rc) {
Jeremy Kerrf733c852017-02-07 18:40:10 +0800120 return RINGBUFFER_POLL_REMOVE;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930121 }
Jeremy Kerrf733c852017-02-07 18:40:10 +0800122
123 ringbuffer_dequeue_commit(lh->rbc, len);
124 }
125
126 return RINGBUFFER_POLL_OK;
127}
128
John Wang46d9ef22023-01-16 11:04:51 +0800129static int log_create(struct log_handler *lh)
130{
131 off_t pos;
132
133 lh->fd = open(lh->log_filename, O_WRONLY | O_CREAT | O_APPEND, 0644);
134 if (lh->fd < 0) {
135 warn("Can't open log buffer file %s", lh->log_filename);
136 return -1;
137 }
138 pos = lseek(lh->fd, 0, SEEK_CUR);
139 if (pos < 0) {
140 warn("Can't query log position for file %s", lh->log_filename);
141 close(lh->fd);
142 return -1;
143 }
144 lh->size = pos;
145 if ((size_t)pos >= lh->maxsize) {
146 return log_trim(lh);
147 }
148
149 return 0;
150}
151
Jeremy Kerre2826c72024-07-05 10:54:21 +0800152static struct handler *log_init(const struct handler_type *type
153 __attribute__((unused)),
154 struct console *console, struct config *config)
Jeremy Kerrf733c852017-02-07 18:40:10 +0800155{
Jeremy Kerre2826c72024-07-05 10:54:21 +0800156 struct log_handler *lh;
Andrew Jefferyb70f8712023-04-19 12:53:34 +0930157 const char *filename;
158 const char *logsize_str;
Kun Yi18644352018-08-27 11:37:42 -0700159 size_t logsize = default_logsize;
Jeremy Kerrf733c852017-02-07 18:40:10 +0800160 int rc;
161
Jeremy Kerre2826c72024-07-05 10:54:21 +0800162 lh = malloc(sizeof(*lh));
163 if (!lh) {
164 return NULL;
165 }
166
Jeremy Kerrf733c852017-02-07 18:40:10 +0800167 lh->console = console;
Jeremy Kerrf733c852017-02-07 18:40:10 +0800168 lh->pagesize = 4096;
169 lh->size = 0;
Lei YU93fd8a32022-03-30 10:15:25 +0800170 lh->log_filename = NULL;
171 lh->rotate_filename = NULL;
Jeremy Kerrf733c852017-02-07 18:40:10 +0800172
Kun Yi6424cc32018-06-14 14:09:28 -0700173 logsize_str = config_get_value(config, "logsize");
Medicine Yehd6e8b642024-03-18 01:49:17 -0700174 rc = config_parse_bytesize(logsize_str, &logsize);
Kun Yi6424cc32018-06-14 14:09:28 -0700175 if (logsize_str != NULL && rc) {
176 logsize = default_logsize;
177 warn("Invalid logsize. Default to %ukB",
Andrew Jefferya72711a2023-04-18 18:19:41 +0930178 (unsigned int)(logsize >> 10));
Kun Yi6424cc32018-06-14 14:09:28 -0700179 }
180 lh->maxsize = logsize <= lh->pagesize ? lh->pagesize + 1 : logsize;
181
Jeremy Kerrf733c852017-02-07 18:40:10 +0800182 filename = config_get_value(config, "logfile");
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930183 if (!filename) {
Jeremy Kerrf733c852017-02-07 18:40:10 +0800184 filename = default_filename;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930185 }
Jeremy Kerrf733c852017-02-07 18:40:10 +0800186
Lei YU93fd8a32022-03-30 10:15:25 +0800187 lh->log_filename = strdup(filename);
188
189 rc = asprintf(&lh->rotate_filename, "%s.1", filename);
190 if (rc < 0) {
191 warn("Failed to construct rotate filename");
Jeremy Kerre2826c72024-07-05 10:54:21 +0800192 goto err_free;
Jeremy Kerrf733c852017-02-07 18:40:10 +0800193 }
194
John Wang46d9ef22023-01-16 11:04:51 +0800195 rc = log_create(lh);
196 if (rc < 0) {
Jeremy Kerre2826c72024-07-05 10:54:21 +0800197 goto err_free;
John Wang46d9ef22023-01-16 11:04:51 +0800198 }
Jeremy Kerrf733c852017-02-07 18:40:10 +0800199 lh->rbc = console_ringbuffer_consumer_register(console,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930200 log_ringbuffer_poll, lh);
Jeremy Kerrf733c852017-02-07 18:40:10 +0800201
Jeremy Kerre2826c72024-07-05 10:54:21 +0800202 return &lh->handler;
203
204err_free:
Andrew Jeffery48d1f532024-07-09 14:46:14 +0930205 free(lh->rotate_filename);
Jeremy Kerre2826c72024-07-05 10:54:21 +0800206 free(lh->log_filename);
207 free(lh);
208 return NULL;
Jeremy Kerrf733c852017-02-07 18:40:10 +0800209}
210
Jeremy Kerr3f54de42016-03-09 18:10:15 +0800211static void log_fini(struct handler *handler)
212{
213 struct log_handler *lh = to_log_handler(handler);
Jeremy Kerrf733c852017-02-07 18:40:10 +0800214 ringbuffer_consumer_unregister(lh->rbc);
Jeremy Kerr3f54de42016-03-09 18:10:15 +0800215 close(lh->fd);
Lei YU93fd8a32022-03-30 10:15:25 +0800216 free(lh->log_filename);
217 free(lh->rotate_filename);
Jeremy Kerre2826c72024-07-05 10:54:21 +0800218 free(lh);
Jeremy Kerr3f54de42016-03-09 18:10:15 +0800219}
220
Jeremy Kerre2826c72024-07-05 10:54:21 +0800221static const struct handler_type log_handler = {
222 .name = "log",
223 .init = log_init,
224 .fini = log_fini,
Jeremy Kerr3f54de42016-03-09 18:10:15 +0800225};
226
Jeremy Kerre2826c72024-07-05 10:54:21 +0800227console_handler_register(&log_handler);