summaryrefslogtreecommitdiffstats
path: root/src/log/log-error-buffer.c
blob: 608d1ad47df839bc56098711f6c96ef31c9f5650 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "log-error-buffer.h"

#define LOG_ERROR_BUFFER_MAX_LINES 1000

struct log_error_data {
	struct log_error_data *next;

	enum log_type type;
	time_t timestamp;
	unsigned char prefix_text[FLEXIBLE_ARRAY_MEMBER];
};

struct log_error_buffer {
	struct log_error_data *head, *tail;
	unsigned int count;
};

struct log_error_buffer_iter {
	struct log_error_buffer *buf;
	struct log_error_data *cur;
	struct log_error error;
};

struct log_error_buffer *log_error_buffer_init(void)
{
	struct log_error_buffer *buf;

	buf = i_new(struct log_error_buffer, 1);
	return buf;
}

static void log_error_buffer_delete_head(struct log_error_buffer *buf)
{
	struct log_error_data *data;

	i_assert(buf->head != NULL);

	buf->count--;
	data = buf->head;
	buf->head = data->next;
	if (buf->tail == data) {
		/* last one */
		buf->tail = NULL;
	}
	i_free(data);
}

void log_error_buffer_add(struct log_error_buffer *buf,
			  const struct log_error *error)
{
	size_t prefix_size = strlen(error->prefix)+1;
	size_t text_size = strlen(error->text)+1;
	struct log_error_data *data;

	if (buf->count == LOG_ERROR_BUFFER_MAX_LINES)
		log_error_buffer_delete_head(buf);

	/* @UNSAFE */
	data = i_malloc(MALLOC_ADD(sizeof(*data),
				   MALLOC_ADD(prefix_size, text_size)));
	data->type = error->type;
	data->timestamp = error->timestamp;
	memcpy(data->prefix_text, error->prefix, prefix_size);
	memcpy(data->prefix_text + prefix_size, error->text, text_size);

	if (buf->tail != NULL)
		buf->tail->next = data;
	else
		buf->head = data;
	buf->tail = data;
	buf->count++;
}

void log_error_buffer_deinit(struct log_error_buffer **_buf)
{
	struct log_error_buffer *buf = *_buf;

	*_buf = NULL;
	while (buf->count > 0)
		log_error_buffer_delete_head(buf);
	i_free(buf);
}

struct log_error_buffer_iter *
log_error_buffer_iter_init(struct log_error_buffer *buf)
{
	struct log_error_buffer_iter *iter;

	iter = i_new(struct log_error_buffer_iter, 1);
	iter->buf = buf;
	iter->cur = buf->head;
	return iter;
}

struct log_error *
log_error_buffer_iter_next(struct log_error_buffer_iter *iter)
{
	struct log_error_data *data = iter->cur;

	if (data == NULL)
		return NULL;
	iter->cur = iter->cur->next;

	iter->error.type = data->type;
	iter->error.timestamp = data->timestamp;
	iter->error.prefix = (const void *)data->prefix_text;
	iter->error.text = (const void *)(data->prefix_text +
					  strlen(iter->error.prefix) + 1);
	return &iter->error;
}

void log_error_buffer_iter_deinit(struct log_error_buffer_iter **_iter)
{
	struct log_error_buffer_iter *iter = *_iter;

	*_iter = NULL;

	i_free(iter);
}