blob: 6d31be6c36f6936f1c7eb9814def5c72a3a5c474 [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
Lei YU93fd8a32022-03-30 10:15:25 +080017#define _GNU_SOURCE
Jeremy Kerr3f54de42016-03-09 18:10:15 +080018#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
33struct log_handler {
Jeremy Kerrf733c852017-02-07 18:40:10 +080034 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;
Lei YU93fd8a32022-03-30 10:15:25 +080041 char *log_filename;
42 char *rotate_filename;
Jeremy Kerr3f54de42016-03-09 18:10:15 +080043};
44
45
Jeremy Kerre440a402016-03-17 16:34:14 +080046static const char *default_filename = LOCALSTATEDIR "/log/obmc-console.log";
Kun Yi6424cc32018-06-14 14:09:28 -070047static const size_t default_logsize = 16 * 1024;
Jeremy Kerr3f54de42016-03-09 18:10:15 +080048
49static struct log_handler *to_log_handler(struct handler *handler)
50{
51 return container_of(handler, struct log_handler, handler);
52}
53
Andrew Jefferyfd048322023-04-18 12:02:01 +093054static int log_trim(struct log_handler *lh)
Jeremy Kerr3f54de42016-03-09 18:10:15 +080055{
Lei YU93fd8a32022-03-30 10:15:25 +080056 int rc;
Jeremy Kerr3f54de42016-03-09 18:10:15 +080057
Lei YU93fd8a32022-03-30 10:15:25 +080058 /* 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 }
Jeremy Kerr3f54de42016-03-09 18:10:15 +080065
Lei YU93fd8a32022-03-30 10:15:25 +080066 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);
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);
Jeremy Kerr3f54de42016-03-09 18:10:15 +080088 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
Jeremy Kerrf733c852017-02-07 18:40:10 +0800101static 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
126static int log_init(struct handler *handler, struct console *console,
Kun Yi6424cc32018-06-14 14:09:28 -0700127 struct config *config)
Jeremy Kerrf733c852017-02-07 18:40:10 +0800128{
129 struct log_handler *lh = to_log_handler(handler);
Kun Yi6424cc32018-06-14 14:09:28 -0700130 const char *filename, *logsize_str;
Kun Yi18644352018-08-27 11:37:42 -0700131 size_t logsize = default_logsize;
Jeremy Kerrf733c852017-02-07 18:40:10 +0800132 int rc;
133
134 lh->console = console;
Jeremy Kerrf733c852017-02-07 18:40:10 +0800135 lh->pagesize = 4096;
136 lh->size = 0;
Lei YU93fd8a32022-03-30 10:15:25 +0800137 lh->log_filename = NULL;
138 lh->rotate_filename = NULL;
Jeremy Kerrf733c852017-02-07 18:40:10 +0800139
Kun Yi6424cc32018-06-14 14:09:28 -0700140 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
Jeremy Kerrf733c852017-02-07 18:40:10 +0800149 filename = config_get_value(config, "logfile");
150 if (!filename)
151 filename = default_filename;
152
Lei YU93fd8a32022-03-30 10:15:25 +0800153 lh->fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
Jeremy Kerrf733c852017-02-07 18:40:10 +0800154 if (lh->fd < 0) {
155 warn("Can't open log buffer file %s", filename);
156 return -1;
157 }
Lei YU93fd8a32022-03-30 10:15:25 +0800158
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");
Jeremy Kerrf733c852017-02-07 18:40:10 +0800164 return -1;
165 }
166
167 lh->rbc = console_ringbuffer_consumer_register(console,
168 log_ringbuffer_poll, lh);
169
170 return 0;
171}
172
Jeremy Kerr3f54de42016-03-09 18:10:15 +0800173static void log_fini(struct handler *handler)
174{
175 struct log_handler *lh = to_log_handler(handler);
Jeremy Kerrf733c852017-02-07 18:40:10 +0800176 ringbuffer_consumer_unregister(lh->rbc);
Jeremy Kerr3f54de42016-03-09 18:10:15 +0800177 close(lh->fd);
Lei YU93fd8a32022-03-30 10:15:25 +0800178 free(lh->log_filename);
179 free(lh->rotate_filename);
Jeremy Kerr3f54de42016-03-09 18:10:15 +0800180}
181
182static struct log_handler log_handler = {
183 .handler = {
184 .name = "log",
185 .init = log_init,
Jeremy Kerr3f54de42016-03-09 18:10:15 +0800186 .fini = log_fini,
187 },
188};
189
Jeremy Kerr55c97122017-02-07 17:06:46 +0800190console_handler_register(&log_handler.handler);
Jeremy Kerr3f54de42016-03-09 18:10:15 +0800191