summaryrefslogtreecommitdiffstats
path: root/lib/log_filter.c
blob: e8d99d79254d67f0a551a6a306fd0efe8f0662e7 (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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Logging - Filtered file log target
 * Copyright (C) 2019 Cumulus Networks, Inc.
 *                    Stephen Worley
 */

#include <zebra.h>

#include "frr_pthread.h"
#include "log.h"

static pthread_mutex_t logfilterlock = PTHREAD_MUTEX_INITIALIZER;
static char zlog_filters[ZLOG_FILTERS_MAX][ZLOG_FILTER_LENGTH_MAX + 1];
static uint8_t zlog_filter_count;

/*
 * look for a match on the filter in the current filters,
 * logfilterlock must be held
 */
static int zlog_filter_lookup(const char *lookup)
{
	for (int i = 0; i < zlog_filter_count; i++) {
		if (strncmp(lookup, zlog_filters[i], sizeof(zlog_filters[0]))
		    == 0)
			return i;
	}
	return -1;
}

void zlog_filter_clear(void)
{
	frr_with_mutex (&logfilterlock) {
		zlog_filter_count = 0;
	}
}

int zlog_filter_add(const char *filter)
{
	frr_with_mutex (&logfilterlock) {
		if (zlog_filter_count >= ZLOG_FILTERS_MAX)
			return 1;

		if (zlog_filter_lookup(filter) != -1)
			/* Filter already present */
			return -1;

		strlcpy(zlog_filters[zlog_filter_count], filter,
			sizeof(zlog_filters[0]));

		if (zlog_filters[zlog_filter_count][0] == '\0')
			/* Filter was either empty or didn't get copied
			 * correctly
			 */
			return -1;

		zlog_filter_count++;
	}
	return 0;
}

int zlog_filter_del(const char *filter)
{
	frr_with_mutex (&logfilterlock) {
		int found_idx = zlog_filter_lookup(filter);
		int last_idx = zlog_filter_count - 1;

		if (found_idx == -1)
			/* Didn't find the filter to delete */
			return -1;

		/* Adjust the filter array */
		memmove(zlog_filters[found_idx], zlog_filters[found_idx + 1],
			(last_idx - found_idx) * sizeof(zlog_filters[0]));

		zlog_filter_count--;
	}
	return 0;
}

/* Dump all filters to buffer, delimited by new line */
int zlog_filter_dump(char *buf, size_t max_size)
{
	int len = 0;

	frr_with_mutex (&logfilterlock) {
		for (int i = 0; i < zlog_filter_count; i++) {
			int ret;

			ret = snprintf(buf + len, max_size - len, " %s\n",
				       zlog_filters[i]);
			len += ret;
			if ((ret < 0) || ((size_t)len >= max_size))
				return -1;
		}
	}

	return len;
}

static int search_buf(const char *buf, size_t len)
{
	char *found = NULL;

	frr_with_mutex (&logfilterlock) {
		for (int i = 0; i < zlog_filter_count; i++) {
			found = memmem(buf, len, zlog_filters[i],
				       strlen(zlog_filters[i]));
			if (found != NULL)
				return 0;
		}
	}

	return -1;
}

static void zlog_filterfile_fd(struct zlog_target *zt, struct zlog_msg *msgs[],
			       size_t nmsgs)
{
	struct zlog_msg *msgfilt[nmsgs];
	size_t i, o = 0;
	const char *text;
	size_t text_len;

	for (i = 0; i < nmsgs; i++) {
		if (zlog_msg_prio(msgs[i]) >= LOG_DEBUG) {
			text = zlog_msg_text(msgs[i], &text_len);
			if (search_buf(text, text_len) < 0)
				continue;
		}
		msgfilt[o++] = msgs[i];
	}

	if (o)
		zlog_fd(zt, msgfilt, o);
}

void zlog_filterfile_init(struct zlog_cfg_filterfile *zcf)
{
	zlog_file_init(&zcf->parent);
	zcf->parent.zlog_wrap = zlog_filterfile_fd;
}

void zlog_filterfile_fini(struct zlog_cfg_filterfile *zcf)
{
	zlog_file_fini(&zcf->parent);
}