xref: /openbmc/obmc-console/log-handler.c (revision 93fd8a39d8d20cdf965490f594a2d6f6d90f506c)
19326d779SJeremy Kerr /**
29326d779SJeremy Kerr  * Copyright © 2016 IBM Corporation
39326d779SJeremy Kerr  *
49326d779SJeremy Kerr  * Licensed under the Apache License, Version 2.0 (the "License");
59326d779SJeremy Kerr  * you may not use this file except in compliance with the License.
69326d779SJeremy Kerr  * You may obtain a copy of the License at
79326d779SJeremy Kerr  *
89326d779SJeremy Kerr  *     http://www.apache.org/licenses/LICENSE-2.0
99326d779SJeremy Kerr  *
109326d779SJeremy Kerr  * Unless required by applicable law or agreed to in writing, software
119326d779SJeremy Kerr  * distributed under the License is distributed on an "AS IS" BASIS,
129326d779SJeremy Kerr  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139326d779SJeremy Kerr  * See the License for the specific language governing permissions and
149326d779SJeremy Kerr  * limitations under the License.
159326d779SJeremy Kerr  */
163f54de4cSJeremy Kerr 
17*93fd8a39SLei YU #define _GNU_SOURCE
183f54de4cSJeremy Kerr #include <endian.h>
193f54de4cSJeremy Kerr #include <err.h>
203f54de4cSJeremy Kerr #include <fcntl.h>
213f54de4cSJeremy Kerr #include <stdbool.h>
223f54de4cSJeremy Kerr #include <stdio.h>
233f54de4cSJeremy Kerr #include <stdlib.h>
243f54de4cSJeremy Kerr #include <string.h>
253f54de4cSJeremy Kerr #include <unistd.h>
263f54de4cSJeremy Kerr 
273f54de4cSJeremy Kerr #include <sys/mman.h>
283f54de4cSJeremy Kerr 
293f54de4cSJeremy Kerr #include <linux/types.h>
303f54de4cSJeremy Kerr 
313f54de4cSJeremy Kerr #include "console-server.h"
323f54de4cSJeremy Kerr 
333f54de4cSJeremy Kerr struct log_handler {
343f54de4cSJeremy Kerr 	struct handler			handler;
353f54de4cSJeremy Kerr 	struct console			*console;
36f733c85aSJeremy Kerr 	struct ringbuffer_consumer	*rbc;
373f54de4cSJeremy Kerr 	int				fd;
383f54de4cSJeremy Kerr 	size_t				size;
393f54de4cSJeremy Kerr 	size_t				maxsize;
403f54de4cSJeremy Kerr 	int				pagesize;
41*93fd8a39SLei YU 	char				*log_filename;
42*93fd8a39SLei YU 	char				*rotate_filename;
433f54de4cSJeremy Kerr };
443f54de4cSJeremy Kerr 
453f54de4cSJeremy Kerr 
46e440a407SJeremy Kerr static const char *default_filename = LOCALSTATEDIR "/log/obmc-console.log";
476424cc3bSKun Yi static const size_t default_logsize = 16 * 1024;
483f54de4cSJeremy Kerr 
493f54de4cSJeremy Kerr static struct log_handler *to_log_handler(struct handler *handler)
503f54de4cSJeremy Kerr {
513f54de4cSJeremy Kerr 	return container_of(handler, struct log_handler, handler);
523f54de4cSJeremy Kerr }
533f54de4cSJeremy Kerr 
543f54de4cSJeremy Kerr static int log_trim(struct log_handler *lh, size_t space)
553f54de4cSJeremy Kerr {
56*93fd8a39SLei YU 	int rc;
573f54de4cSJeremy Kerr 
58*93fd8a39SLei YU 	/* Move the log buffer file to the rotate file */
59*93fd8a39SLei YU 	close(lh->fd);
60*93fd8a39SLei YU 	rc = rename(lh->log_filename, lh->rotate_filename);
61*93fd8a39SLei YU 	if (rc) {
62*93fd8a39SLei YU 		warn("Failed to rename %s to %s", lh->log_filename, lh->rotate_filename);
63*93fd8a39SLei YU 		/* don't return, as we need to re-open the logfile */
64*93fd8a39SLei YU 	}
653f54de4cSJeremy Kerr 
66*93fd8a39SLei YU 	lh->fd = open(lh->log_filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
67*93fd8a39SLei YU 	if (lh->fd < 0) {
68*93fd8a39SLei YU 		warn("Can't open log buffer file %s", lh->log_filename);
693f54de4cSJeremy Kerr 		return -1;
70*93fd8a39SLei YU 	}
713f54de4cSJeremy Kerr 
72*93fd8a39SLei YU 	lh->size = 0;
733f54de4cSJeremy Kerr 
743f54de4cSJeremy Kerr 	return 0;
753f54de4cSJeremy Kerr }
763f54de4cSJeremy Kerr 
77f733c85aSJeremy Kerr static int log_data(struct log_handler *lh, uint8_t *buf, size_t len)
783f54de4cSJeremy Kerr {
793f54de4cSJeremy Kerr 	int rc;
803f54de4cSJeremy Kerr 
813f54de4cSJeremy Kerr 	if (len > lh->maxsize) {
823f54de4cSJeremy Kerr 		buf += len - lh->maxsize;
833f54de4cSJeremy Kerr 		len = lh->maxsize;
843f54de4cSJeremy Kerr 	}
853f54de4cSJeremy Kerr 
863f54de4cSJeremy Kerr 	if (lh->size + len > lh->maxsize) {
873f54de4cSJeremy Kerr 		rc = log_trim(lh, len);
883f54de4cSJeremy Kerr 		if (rc)
893f54de4cSJeremy Kerr 			return rc;
903f54de4cSJeremy Kerr 	}
913f54de4cSJeremy Kerr 
923f54de4cSJeremy Kerr 	rc = write_buf_to_fd(lh->fd, buf, len);
933f54de4cSJeremy Kerr 	if (rc)
943f54de4cSJeremy Kerr 		return rc;
953f54de4cSJeremy Kerr 
963f54de4cSJeremy Kerr 	lh->size += len;
973f54de4cSJeremy Kerr 
983f54de4cSJeremy Kerr 	return 0;
993f54de4cSJeremy Kerr }
1003f54de4cSJeremy Kerr 
101f733c85aSJeremy Kerr static enum ringbuffer_poll_ret log_ringbuffer_poll(void *arg,
102f733c85aSJeremy Kerr 		size_t force_len __attribute__((unused)))
103f733c85aSJeremy Kerr {
104f733c85aSJeremy Kerr 	struct log_handler *lh = arg;
105f733c85aSJeremy Kerr 	uint8_t *buf;
106f733c85aSJeremy Kerr 	size_t len;
107f733c85aSJeremy Kerr 	int rc;
108f733c85aSJeremy Kerr 
109f733c85aSJeremy Kerr 	/* we log synchronously, so just dequeue everything we can, and
110f733c85aSJeremy Kerr 	 * commit straight away. */
111f733c85aSJeremy Kerr 	for (;;) {
112f733c85aSJeremy Kerr 		len = ringbuffer_dequeue_peek(lh->rbc, 0, &buf);
113f733c85aSJeremy Kerr 		if (!len)
114f733c85aSJeremy Kerr 			break;
115f733c85aSJeremy Kerr 
116f733c85aSJeremy Kerr 		rc = log_data(lh, buf, len);
117f733c85aSJeremy Kerr 		if (rc)
118f733c85aSJeremy Kerr 			return RINGBUFFER_POLL_REMOVE;
119f733c85aSJeremy Kerr 
120f733c85aSJeremy Kerr 		ringbuffer_dequeue_commit(lh->rbc, len);
121f733c85aSJeremy Kerr 	}
122f733c85aSJeremy Kerr 
123f733c85aSJeremy Kerr 	return RINGBUFFER_POLL_OK;
124f733c85aSJeremy Kerr }
125f733c85aSJeremy Kerr 
126f733c85aSJeremy Kerr static int log_init(struct handler *handler, struct console *console,
1276424cc3bSKun Yi 		struct config *config)
128f733c85aSJeremy Kerr {
129f733c85aSJeremy Kerr 	struct log_handler *lh = to_log_handler(handler);
1306424cc3bSKun Yi 	const char *filename, *logsize_str;
13118644357SKun Yi 	size_t logsize = default_logsize;
132f733c85aSJeremy Kerr 	int rc;
133f733c85aSJeremy Kerr 
134f733c85aSJeremy Kerr 	lh->console = console;
135f733c85aSJeremy Kerr 	lh->pagesize = 4096;
136f733c85aSJeremy Kerr 	lh->size = 0;
137*93fd8a39SLei YU 	lh->log_filename = NULL;
138*93fd8a39SLei YU 	lh->rotate_filename = NULL;
139f733c85aSJeremy Kerr 
1406424cc3bSKun Yi 	logsize_str = config_get_value(config, "logsize");
1416424cc3bSKun Yi 	rc = config_parse_logsize(logsize_str, &logsize);
1426424cc3bSKun Yi 	if (logsize_str != NULL && rc) {
1436424cc3bSKun Yi 		logsize = default_logsize;
1446424cc3bSKun Yi 		warn("Invalid logsize. Default to %ukB",
1456424cc3bSKun Yi                      (unsigned int)(logsize >> 10));
1466424cc3bSKun Yi 	}
1476424cc3bSKun Yi 	lh->maxsize = logsize <= lh->pagesize ? lh->pagesize + 1 : logsize;
1486424cc3bSKun Yi 
149f733c85aSJeremy Kerr 	filename = config_get_value(config, "logfile");
150f733c85aSJeremy Kerr 	if (!filename)
151f733c85aSJeremy Kerr 		filename = default_filename;
152f733c85aSJeremy Kerr 
153*93fd8a39SLei YU 	lh->fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
154f733c85aSJeremy Kerr 	if (lh->fd < 0) {
155f733c85aSJeremy Kerr 		warn("Can't open log buffer file %s", filename);
156f733c85aSJeremy Kerr 		return -1;
157f733c85aSJeremy Kerr 	}
158*93fd8a39SLei YU 
159*93fd8a39SLei YU 	lh->log_filename = strdup(filename);
160*93fd8a39SLei YU 
161*93fd8a39SLei YU 	rc = asprintf(&lh->rotate_filename, "%s.1", filename);
162*93fd8a39SLei YU 	if (rc < 0) {
163*93fd8a39SLei YU 		warn("Failed to construct rotate filename");
164f733c85aSJeremy Kerr 		return -1;
165f733c85aSJeremy Kerr 	}
166f733c85aSJeremy Kerr 
167f733c85aSJeremy Kerr 	lh->rbc = console_ringbuffer_consumer_register(console,
168f733c85aSJeremy Kerr 			log_ringbuffer_poll, lh);
169f733c85aSJeremy Kerr 
170f733c85aSJeremy Kerr 	return 0;
171f733c85aSJeremy Kerr }
172f733c85aSJeremy Kerr 
1733f54de4cSJeremy Kerr static void log_fini(struct handler *handler)
1743f54de4cSJeremy Kerr {
1753f54de4cSJeremy Kerr 	struct log_handler *lh = to_log_handler(handler);
176f733c85aSJeremy Kerr 	ringbuffer_consumer_unregister(lh->rbc);
1773f54de4cSJeremy Kerr 	close(lh->fd);
178*93fd8a39SLei YU 	free(lh->log_filename);
179*93fd8a39SLei YU 	free(lh->rotate_filename);
1803f54de4cSJeremy Kerr }
1813f54de4cSJeremy Kerr 
1823f54de4cSJeremy Kerr static struct log_handler log_handler = {
1833f54de4cSJeremy Kerr 	.handler = {
1843f54de4cSJeremy Kerr 		.name		= "log",
1853f54de4cSJeremy Kerr 		.init		= log_init,
1863f54de4cSJeremy Kerr 		.fini		= log_fini,
1873f54de4cSJeremy Kerr 	},
1883f54de4cSJeremy Kerr };
1893f54de4cSJeremy Kerr 
19055c9712dSJeremy Kerr console_handler_register(&log_handler.handler);
1913f54de4cSJeremy Kerr 
192