1 /*
2  * Logging - Filtered file log target
3  * Copyright (C) 2019 Cumulus Networks, Inc.
4  *                    Stephen Worley
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 2 of the License, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; see the file COPYING; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <zebra.h>
22 
23 #include "frr_pthread.h"
24 #include "log.h"
25 
26 static pthread_mutex_t logfilterlock = PTHREAD_MUTEX_INITIALIZER;
27 static char zlog_filters[ZLOG_FILTERS_MAX][ZLOG_FILTER_LENGTH_MAX + 1];
28 static uint8_t zlog_filter_count;
29 
30 /*
31  * look for a match on the filter in the current filters,
32  * logfilterlock must be held
33  */
zlog_filter_lookup(const char * lookup)34 static int zlog_filter_lookup(const char *lookup)
35 {
36 	for (int i = 0; i < zlog_filter_count; i++) {
37 		if (strncmp(lookup, zlog_filters[i], sizeof(zlog_filters[0]))
38 		    == 0)
39 			return i;
40 	}
41 	return -1;
42 }
43 
zlog_filter_clear(void)44 void zlog_filter_clear(void)
45 {
46 	frr_with_mutex(&logfilterlock) {
47 		zlog_filter_count = 0;
48 	}
49 }
50 
zlog_filter_add(const char * filter)51 int zlog_filter_add(const char *filter)
52 {
53 	frr_with_mutex(&logfilterlock) {
54 		if (zlog_filter_count >= ZLOG_FILTERS_MAX)
55 			return 1;
56 
57 		if (zlog_filter_lookup(filter) != -1)
58 			/* Filter already present */
59 			return -1;
60 
61 		strlcpy(zlog_filters[zlog_filter_count], filter,
62 			sizeof(zlog_filters[0]));
63 
64 		if (zlog_filters[zlog_filter_count][0] == '\0')
65 			/* Filter was either empty or didn't get copied
66 			 * correctly
67 			 */
68 			return -1;
69 
70 		zlog_filter_count++;
71 	}
72 	return 0;
73 }
74 
zlog_filter_del(const char * filter)75 int zlog_filter_del(const char *filter)
76 {
77 	frr_with_mutex(&logfilterlock) {
78 		int found_idx = zlog_filter_lookup(filter);
79 		int last_idx = zlog_filter_count - 1;
80 
81 		if (found_idx == -1)
82 			/* Didn't find the filter to delete */
83 			return -1;
84 
85 		/* Adjust the filter array */
86 		memmove(zlog_filters[found_idx], zlog_filters[found_idx + 1],
87 			(last_idx - found_idx) * sizeof(zlog_filters[0]));
88 
89 		zlog_filter_count--;
90 	}
91 	return 0;
92 }
93 
94 /* Dump all filters to buffer, delimited by new line */
zlog_filter_dump(char * buf,size_t max_size)95 int zlog_filter_dump(char *buf, size_t max_size)
96 {
97 	int len = 0;
98 
99 	frr_with_mutex(&logfilterlock) {
100 		for (int i = 0; i < zlog_filter_count; i++) {
101 			int ret;
102 
103 			ret = snprintf(buf + len, max_size - len, " %s\n",
104 				       zlog_filters[i]);
105 			len += ret;
106 			if ((ret < 0) || ((size_t)len >= max_size))
107 				return -1;
108 		}
109 	}
110 
111 	return len;
112 }
113 
search_buf(const char * buf)114 static int search_buf(const char *buf)
115 {
116 	char *found = NULL;
117 
118 	frr_with_mutex(&logfilterlock) {
119 		for (int i = 0; i < zlog_filter_count; i++) {
120 			found = strstr(buf, zlog_filters[i]);
121 			if (found != NULL)
122 				return 0;
123 		}
124 	}
125 
126 	return -1;
127 }
128 
zlog_filterfile_fd(struct zlog_target * zt,struct zlog_msg * msgs[],size_t nmsgs)129 static void zlog_filterfile_fd(struct zlog_target *zt, struct zlog_msg *msgs[],
130 			       size_t nmsgs)
131 {
132 	struct zlog_msg *msgfilt[nmsgs];
133 	size_t i, o = 0;
134 
135 	for (i = 0; i < nmsgs; i++) {
136 		if (zlog_msg_prio(msgs[i]) >= LOG_DEBUG
137 		    && search_buf(zlog_msg_text(msgs[i], NULL)) < 0)
138 			continue;
139 
140 		msgfilt[o++] = msgs[i];
141 	}
142 
143 	if (o)
144 		zlog_fd(zt, msgfilt, o);
145 }
146 
zlog_filterfile_init(struct zlog_cfg_filterfile * zcf)147 void zlog_filterfile_init(struct zlog_cfg_filterfile *zcf)
148 {
149 	zlog_file_init(&zcf->parent);
150 	zcf->parent.zlog_wrap = zlog_filterfile_fd;
151 }
152 
zlog_filterfile_fini(struct zlog_cfg_filterfile * zcf)153 void zlog_filterfile_fini(struct zlog_cfg_filterfile *zcf)
154 {
155 	zlog_file_fini(&zcf->parent);
156 }
157