xref: /openbmc/obmc-console/log-handler.c (revision 9326d7791043193b381698f0027dd0d4d92eac07)
1*9326d779SJeremy Kerr /**
2*9326d779SJeremy Kerr  * Copyright © 2016 IBM Corporation
3*9326d779SJeremy Kerr  *
4*9326d779SJeremy Kerr  * Licensed under the Apache License, Version 2.0 (the "License");
5*9326d779SJeremy Kerr  * you may not use this file except in compliance with the License.
6*9326d779SJeremy Kerr  * You may obtain a copy of the License at
7*9326d779SJeremy Kerr  *
8*9326d779SJeremy Kerr  *     http://www.apache.org/licenses/LICENSE-2.0
9*9326d779SJeremy Kerr  *
10*9326d779SJeremy Kerr  * Unless required by applicable law or agreed to in writing, software
11*9326d779SJeremy Kerr  * distributed under the License is distributed on an "AS IS" BASIS,
12*9326d779SJeremy Kerr  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*9326d779SJeremy Kerr  * See the License for the specific language governing permissions and
14*9326d779SJeremy Kerr  * limitations under the License.
15*9326d779SJeremy Kerr  */
163f54de4cSJeremy Kerr 
173f54de4cSJeremy Kerr #include <endian.h>
183f54de4cSJeremy Kerr #include <err.h>
193f54de4cSJeremy Kerr #include <fcntl.h>
203f54de4cSJeremy Kerr #include <stdbool.h>
213f54de4cSJeremy Kerr #include <stdio.h>
223f54de4cSJeremy Kerr #include <stdlib.h>
233f54de4cSJeremy Kerr #include <string.h>
243f54de4cSJeremy Kerr #include <unistd.h>
253f54de4cSJeremy Kerr 
263f54de4cSJeremy Kerr #include <sys/mman.h>
273f54de4cSJeremy Kerr 
283f54de4cSJeremy Kerr #include <linux/types.h>
293f54de4cSJeremy Kerr 
303f54de4cSJeremy Kerr #include "console-server.h"
313f54de4cSJeremy Kerr 
323f54de4cSJeremy Kerr struct log_handler {
333f54de4cSJeremy Kerr 	struct handler	handler;
343f54de4cSJeremy Kerr 	struct console	*console;
353f54de4cSJeremy Kerr 	int		fd;
363f54de4cSJeremy Kerr 	size_t		size;
373f54de4cSJeremy Kerr 	size_t		maxsize;
383f54de4cSJeremy Kerr 	int		pagesize;
393f54de4cSJeremy Kerr };
403f54de4cSJeremy Kerr 
413f54de4cSJeremy Kerr 
42e440a407SJeremy Kerr static const char *default_filename = LOCALSTATEDIR "/log/obmc-console.log";
43df94dc12SJeremy Kerr 
443f54de4cSJeremy Kerr static const size_t logsize = 16 * 1024;
453f54de4cSJeremy Kerr 
463f54de4cSJeremy Kerr static struct log_handler *to_log_handler(struct handler *handler)
473f54de4cSJeremy Kerr {
483f54de4cSJeremy Kerr 	return container_of(handler, struct log_handler, handler);
493f54de4cSJeremy Kerr }
503f54de4cSJeremy Kerr 
51d47963e5SJeremy Kerr static int log_init(struct handler *handler, struct console *console,
52d47963e5SJeremy Kerr 		struct config *config __attribute__((unused)))
533f54de4cSJeremy Kerr {
543f54de4cSJeremy Kerr 	struct log_handler *lh = to_log_handler(handler);
55b8f2845bSJeremy Kerr 	const char *filename;
563f54de4cSJeremy Kerr 	int rc;
573f54de4cSJeremy Kerr 
583f54de4cSJeremy Kerr 	lh->console = console;
593f54de4cSJeremy Kerr 	lh->maxsize = logsize;
603f54de4cSJeremy Kerr 	lh->pagesize = 4096;
613f54de4cSJeremy Kerr 	lh->size = 0;
623f54de4cSJeremy Kerr 
63b8f2845bSJeremy Kerr 	filename = config_get_value(config, "logfile");
64b8f2845bSJeremy Kerr 	if (!filename)
65b8f2845bSJeremy Kerr 		filename = default_filename;
66b8f2845bSJeremy Kerr 
673f54de4cSJeremy Kerr 	lh->fd = open(filename, O_RDWR | O_CREAT, 0644);
683f54de4cSJeremy Kerr 	if (lh->fd < 0) {
693f54de4cSJeremy Kerr 		warn("Can't open log buffer file %s", filename);
703f54de4cSJeremy Kerr 		return -1;
713f54de4cSJeremy Kerr 	}
723f54de4cSJeremy Kerr 	rc = ftruncate(lh->fd, 0);
733f54de4cSJeremy Kerr 	if (rc) {
743f54de4cSJeremy Kerr 		warn("Can't truncate file %s", filename);
753f54de4cSJeremy Kerr 		close(lh->fd);
763f54de4cSJeremy Kerr 		return -1;
773f54de4cSJeremy Kerr 	}
783f54de4cSJeremy Kerr 
793f54de4cSJeremy Kerr 	return 0;
803f54de4cSJeremy Kerr }
813f54de4cSJeremy Kerr 
823f54de4cSJeremy Kerr static int log_trim(struct log_handler *lh, size_t space)
833f54de4cSJeremy Kerr {
843f54de4cSJeremy Kerr 	int rc, n_shift_pages, shift_len, shift_start;
853f54de4cSJeremy Kerr 	off_t pos;
863f54de4cSJeremy Kerr 	void *buf;
873f54de4cSJeremy Kerr 
883f54de4cSJeremy Kerr 	pos = lseek(lh->fd, 0, SEEK_CUR);
893f54de4cSJeremy Kerr 
903f54de4cSJeremy Kerr 	n_shift_pages = (space + lh->pagesize - 1) / lh->pagesize;
913f54de4cSJeremy Kerr 	shift_start = n_shift_pages * lh->pagesize;
923f54de4cSJeremy Kerr 	shift_len = pos - (n_shift_pages * lh->pagesize);
933f54de4cSJeremy Kerr 
943f54de4cSJeremy Kerr 	buf = mmap(NULL, pos, PROT_READ | PROT_WRITE, MAP_SHARED, lh->fd, 0);
953f54de4cSJeremy Kerr 	if (buf == MAP_FAILED)
963f54de4cSJeremy Kerr 		return -1;
973f54de4cSJeremy Kerr 
983f54de4cSJeremy Kerr 	memmove(buf, buf + shift_start, shift_len);
993f54de4cSJeremy Kerr 
1003f54de4cSJeremy Kerr 	munmap(buf, pos);
1013f54de4cSJeremy Kerr 
1023f54de4cSJeremy Kerr 	lh->size = shift_len;
1033f54de4cSJeremy Kerr 	rc = ftruncate(lh->fd, lh->size);
1043f54de4cSJeremy Kerr 	if (rc)
1053f54de4cSJeremy Kerr 		warn("failed to truncate file");
1063f54de4cSJeremy Kerr 	lseek(lh->fd, 0, SEEK_END);
1073f54de4cSJeremy Kerr 
1083f54de4cSJeremy Kerr 	return 0;
1093f54de4cSJeremy Kerr 
1103f54de4cSJeremy Kerr }
1113f54de4cSJeremy Kerr 
1123f54de4cSJeremy Kerr static int log_data(struct handler *handler, uint8_t *buf, size_t len)
1133f54de4cSJeremy Kerr {
1143f54de4cSJeremy Kerr 	struct log_handler *lh = to_log_handler(handler);
1153f54de4cSJeremy Kerr 	int rc;
1163f54de4cSJeremy Kerr 
1173f54de4cSJeremy Kerr 	if (len > lh->maxsize) {
1183f54de4cSJeremy Kerr 		buf += len - lh->maxsize;
1193f54de4cSJeremy Kerr 		len = lh->maxsize;
1203f54de4cSJeremy Kerr 	}
1213f54de4cSJeremy Kerr 
1223f54de4cSJeremy Kerr 	if (lh->size + len > lh->maxsize) {
1233f54de4cSJeremy Kerr 		rc = log_trim(lh, len);
1243f54de4cSJeremy Kerr 		if (rc)
1253f54de4cSJeremy Kerr 			return rc;
1263f54de4cSJeremy Kerr 	}
1273f54de4cSJeremy Kerr 
1283f54de4cSJeremy Kerr 	rc = write_buf_to_fd(lh->fd, buf, len);
1293f54de4cSJeremy Kerr 	if (rc)
1303f54de4cSJeremy Kerr 		return rc;
1313f54de4cSJeremy Kerr 
1323f54de4cSJeremy Kerr 	lh->size += len;
1333f54de4cSJeremy Kerr 
1343f54de4cSJeremy Kerr 	return 0;
1353f54de4cSJeremy Kerr }
1363f54de4cSJeremy Kerr 
1373f54de4cSJeremy Kerr static void log_fini(struct handler *handler)
1383f54de4cSJeremy Kerr {
1393f54de4cSJeremy Kerr 	struct log_handler *lh = to_log_handler(handler);
1403f54de4cSJeremy Kerr 	close(lh->fd);
1413f54de4cSJeremy Kerr }
1423f54de4cSJeremy Kerr 
1433f54de4cSJeremy Kerr static struct log_handler log_handler = {
1443f54de4cSJeremy Kerr 	.handler = {
1453f54de4cSJeremy Kerr 		.name		= "log",
1463f54de4cSJeremy Kerr 		.init		= log_init,
1473f54de4cSJeremy Kerr 		.data_in	= log_data,
1483f54de4cSJeremy Kerr 		.fini		= log_fini,
1493f54de4cSJeremy Kerr 	},
1503f54de4cSJeremy Kerr };
1513f54de4cSJeremy Kerr 
1523f54de4cSJeremy Kerr console_register_handler(&log_handler.handler);
1533f54de4cSJeremy Kerr 
154