summaryrefslogtreecommitdiffstats
path: root/src/log/log-error-buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/log/log-error-buffer.c')
-rw-r--r--src/log/log-error-buffer.c122
1 files changed, 122 insertions, 0 deletions
diff --git a/src/log/log-error-buffer.c b/src/log/log-error-buffer.c
new file mode 100644
index 0000000..608d1ad
--- /dev/null
+++ b/src/log/log-error-buffer.c
@@ -0,0 +1,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);
+}