1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "module.h"
22 #include "zbxmodules.h"
23 
24 #include "log.h"
25 #include "sysinfo.h"
26 #include "zbxalgo.h"
27 
28 #define ZBX_MODULE_FUNC_INIT			"zbx_module_init"
29 #define ZBX_MODULE_FUNC_API_VERSION		"zbx_module_api_version"
30 #define ZBX_MODULE_FUNC_ITEM_LIST		"zbx_module_item_list"
31 #define ZBX_MODULE_FUNC_ITEM_PROCESS		"zbx_module_item_process"
32 #define ZBX_MODULE_FUNC_ITEM_TIMEOUT		"zbx_module_item_timeout"
33 #define ZBX_MODULE_FUNC_UNINIT			"zbx_module_uninit"
34 #define ZBX_MODULE_FUNC_HISTORY_WRITE_CBS	"zbx_module_history_write_cbs"
35 
36 static zbx_vector_ptr_t	modules;
37 
38 zbx_history_float_cb_t		*history_float_cbs = NULL;
39 zbx_history_integer_cb_t	*history_integer_cbs = NULL;
40 zbx_history_string_cb_t		*history_string_cbs = NULL;
41 zbx_history_text_cb_t		*history_text_cbs = NULL;
42 zbx_history_log_cb_t		*history_log_cbs = NULL;
43 
44 /******************************************************************************
45  *                                                                            *
46  * Function: zbx_register_module_items                                        *
47  *                                                                            *
48  * Purpose: add items supported by module                                     *
49  *                                                                            *
50  * Parameters: metrics       - list of items supported by module              *
51  *             error         - error buffer                                   *
52  *             max_error_len - error buffer size                              *
53  *                                                                            *
54  * Return value: SUCCEED - all module items were added or there were none     *
55  *               FAIL    - otherwise                                          *
56  *                                                                            *
57  ******************************************************************************/
zbx_register_module_items(ZBX_METRIC * metrics,char * error,size_t max_error_len)58 static int	zbx_register_module_items(ZBX_METRIC *metrics, char *error, size_t max_error_len)
59 {
60 	int	i;
61 
62 	for (i = 0; NULL != metrics[i].key; i++)
63 	{
64 		/* accept only CF_HAVEPARAMS flag from module items */
65 		metrics[i].flags &= CF_HAVEPARAMS;
66 		/* the flag means that the items comes from a loadable module */
67 		metrics[i].flags |= CF_MODULE;
68 
69 		if (SUCCEED != add_metric(&metrics[i], error, max_error_len))
70 			return FAIL;
71 	}
72 
73 	return SUCCEED;
74 }
75 
76 /******************************************************************************
77  *                                                                            *
78  * Function: zbx_register_module                                              *
79  *                                                                            *
80  * Purpose: add module to the list of successfully loaded modules             *
81  *                                                                            *
82  ******************************************************************************/
zbx_register_module(void * lib,char * name)83 static zbx_module_t	*zbx_register_module(void *lib, char *name)
84 {
85 	zbx_module_t	*module;
86 
87 	module = (zbx_module_t *)zbx_malloc(NULL, sizeof(zbx_module_t));
88 	module->lib = lib;
89 	module->name = zbx_strdup(NULL, name);
90 	zbx_vector_ptr_append(&modules, module);
91 
92 	return module;
93 }
94 
95 /******************************************************************************
96  *                                                                            *
97  * Function: zbx_register_history_write_cbs                                   *
98  *                                                                            *
99  * Purpose: registers callback functions for history export                   *
100  *                                                                            *
101  * Parameters: module            - module pointer for later reference         *
102  *             history_write_cbs - callbacks                                  *
103  *                                                                            *
104  ******************************************************************************/
zbx_register_history_write_cbs(zbx_module_t * module,ZBX_HISTORY_WRITE_CBS history_write_cbs)105 static void	zbx_register_history_write_cbs(zbx_module_t *module, ZBX_HISTORY_WRITE_CBS history_write_cbs)
106 {
107 	if (NULL != history_write_cbs.history_float_cb)
108 	{
109 		int	j = 0;
110 
111 		if (NULL == history_float_cbs)
112 		{
113 			history_float_cbs = (zbx_history_float_cb_t *)zbx_malloc(history_float_cbs, sizeof(zbx_history_float_cb_t));
114 			history_float_cbs[0].module = NULL;
115 		}
116 
117 		while (NULL != history_float_cbs[j].module)
118 			j++;
119 
120 		history_float_cbs = (zbx_history_float_cb_t *)zbx_realloc(history_float_cbs, (j + 2) * sizeof(zbx_history_float_cb_t));
121 		history_float_cbs[j].module = module;
122 		history_float_cbs[j].history_float_cb = history_write_cbs.history_float_cb;
123 		history_float_cbs[j + 1].module = NULL;
124 	}
125 
126 	if (NULL != history_write_cbs.history_integer_cb)
127 	{
128 		int	j = 0;
129 
130 		if (NULL == history_integer_cbs)
131 		{
132 			history_integer_cbs = (zbx_history_integer_cb_t *)zbx_malloc(history_integer_cbs, sizeof(zbx_history_integer_cb_t));
133 			history_integer_cbs[0].module = NULL;
134 		}
135 
136 		while (NULL != history_integer_cbs[j].module)
137 			j++;
138 
139 		history_integer_cbs = (zbx_history_integer_cb_t *)zbx_realloc(history_integer_cbs, (j + 2) * sizeof(zbx_history_integer_cb_t));
140 		history_integer_cbs[j].module = module;
141 		history_integer_cbs[j].history_integer_cb = history_write_cbs.history_integer_cb;
142 		history_integer_cbs[j + 1].module = NULL;
143 	}
144 
145 	if (NULL != history_write_cbs.history_string_cb)
146 	{
147 		int	j = 0;
148 
149 		if (NULL == history_string_cbs)
150 		{
151 			history_string_cbs = (zbx_history_string_cb_t *)zbx_malloc(history_string_cbs, sizeof(zbx_history_string_cb_t));
152 			history_string_cbs[0].module = NULL;
153 		}
154 
155 		while (NULL != history_string_cbs[j].module)
156 			j++;
157 
158 		history_string_cbs = (zbx_history_string_cb_t *)zbx_realloc(history_string_cbs, (j + 2) * sizeof(zbx_history_string_cb_t));
159 		history_string_cbs[j].module = module;
160 		history_string_cbs[j].history_string_cb = history_write_cbs.history_string_cb;
161 		history_string_cbs[j + 1].module = NULL;
162 	}
163 
164 	if (NULL != history_write_cbs.history_text_cb)
165 	{
166 		int	j = 0;
167 
168 		if (NULL == history_text_cbs)
169 		{
170 			history_text_cbs = (zbx_history_text_cb_t *)zbx_malloc(history_text_cbs, sizeof(zbx_history_text_cb_t));
171 			history_text_cbs[0].module = NULL;
172 		}
173 
174 		while (NULL != history_text_cbs[j].module)
175 			j++;
176 
177 		history_text_cbs = (zbx_history_text_cb_t *)zbx_realloc(history_text_cbs, (j + 2) * sizeof(zbx_history_text_cb_t));
178 		history_text_cbs[j].module = module;
179 		history_text_cbs[j].history_text_cb = history_write_cbs.history_text_cb;
180 		history_text_cbs[j + 1].module = NULL;
181 	}
182 
183 	if (NULL != history_write_cbs.history_log_cb)
184 	{
185 		int	j = 0;
186 
187 		if (NULL == history_log_cbs)
188 		{
189 			history_log_cbs = (zbx_history_log_cb_t *)zbx_malloc(history_log_cbs, sizeof(zbx_history_log_cb_t));
190 			history_log_cbs[0].module = NULL;
191 		}
192 
193 		while (NULL != history_log_cbs[j].module)
194 			j++;
195 
196 		history_log_cbs = (zbx_history_log_cb_t *)zbx_realloc(history_log_cbs, (j + 2) * sizeof(zbx_history_log_cb_t));
197 		history_log_cbs[j].module = module;
198 		history_log_cbs[j].history_log_cb = history_write_cbs.history_log_cb;
199 		history_log_cbs[j + 1].module = NULL;
200 	}
201 }
202 
zbx_module_compare_func(const void * d1,const void * d2)203 static int	zbx_module_compare_func(const void *d1, const void *d2)
204 {
205 	const zbx_module_t	*m1 = *(const zbx_module_t **)d1;
206 	const zbx_module_t	*m2 = *(const zbx_module_t **)d2;
207 
208 	ZBX_RETURN_IF_NOT_EQUAL(m1->lib, m2->lib);
209 
210 	return 0;
211 }
212 
213 /******************************************************************************
214  *                                                                            *
215  * Function: zbx_load_module                                                  *
216  *                                                                            *
217  * Purpose: load loadable module                                              *
218  *                                                                            *
219  * Parameters: path    - directory where modules are located                  *
220  *             name    - module name                                          *
221  *             timeout - timeout in seconds for processing of items by module *
222  *                                                                            *
223  * Return value: SUCCEED - module was successfully loaded or found amongst    *
224  *                         previously loaded                                  *
225  *               FAIL    - loading of module failed                           *
226  *                                                                            *
227  ******************************************************************************/
zbx_load_module(const char * path,char * name,int timeout)228 static int	zbx_load_module(const char *path, char *name, int timeout)
229 {
230 	void			*lib;
231 	char			full_name[MAX_STRING_LEN], error[MAX_STRING_LEN];
232 	int			(*func_init)(void), (*func_version)(void), version;
233 	ZBX_METRIC		*(*func_list)(void);
234 	void			(*func_timeout)(int);
235 	ZBX_HISTORY_WRITE_CBS	(*func_history_write_cbs)(void);
236 	zbx_module_t		*module, module_tmp;
237 
238 	if ('/' != *name)
239 		zbx_snprintf(full_name, sizeof(full_name), "%s/%s", path, name);
240 	else
241 		zbx_snprintf(full_name, sizeof(full_name), "%s", name);
242 
243 	zabbix_log(LOG_LEVEL_DEBUG, "loading module \"%s\"", full_name);
244 
245 	if (NULL == (lib = dlopen(full_name, RTLD_NOW)))
246 	{
247 		zabbix_log(LOG_LEVEL_CRIT, "cannot load module \"%s\": %s", name, dlerror());
248 		return FAIL;
249 	}
250 
251 	module_tmp.lib = lib;
252 	if (FAIL != zbx_vector_ptr_search(&modules, &module_tmp, zbx_module_compare_func))
253 	{
254 		zabbix_log(LOG_LEVEL_DEBUG, "module \"%s\" has already beed loaded", name);
255 		return SUCCEED;
256 	}
257 
258 	if (NULL == (func_version = (int (*)(void))dlsym(lib, ZBX_MODULE_FUNC_API_VERSION)))
259 	{
260 		zabbix_log(LOG_LEVEL_CRIT, "cannot find \"" ZBX_MODULE_FUNC_API_VERSION "()\""
261 				" function in module \"%s\": %s", name, dlerror());
262 		goto fail;
263 	}
264 
265 	if (ZBX_MODULE_API_VERSION != (version = func_version()))
266 	{
267 		zabbix_log(LOG_LEVEL_CRIT, "unsupported module \"%s\" version: %d", name, version);
268 		goto fail;
269 	}
270 
271 	if (NULL == (func_init = (int (*)(void))dlsym(lib, ZBX_MODULE_FUNC_INIT)))
272 	{
273 		zabbix_log(LOG_LEVEL_DEBUG, "cannot find \"" ZBX_MODULE_FUNC_INIT "()\""
274 				" function in module \"%s\": %s", name, dlerror());
275 	}
276 	else if (ZBX_MODULE_OK != func_init())
277 	{
278 		zabbix_log(LOG_LEVEL_CRIT, "cannot initialize module \"%s\"", name);
279 		goto fail;
280 	}
281 
282 	if (NULL == (func_list = (ZBX_METRIC *(*)(void))dlsym(lib, ZBX_MODULE_FUNC_ITEM_LIST)))
283 	{
284 		zabbix_log(LOG_LEVEL_DEBUG, "cannot find \"" ZBX_MODULE_FUNC_ITEM_LIST "()\""
285 				" function in module \"%s\": %s", name, dlerror());
286 	}
287 	else
288 	{
289 		if (SUCCEED != zbx_register_module_items(func_list(), error, sizeof(error)))
290 		{
291 			zabbix_log(LOG_LEVEL_CRIT, "cannot load module \"%s\": %s", name, error);
292 			goto fail;
293 		}
294 
295 		if (NULL == (func_timeout = (void (*)(int))dlsym(lib, ZBX_MODULE_FUNC_ITEM_TIMEOUT)))
296 		{
297 			zabbix_log(LOG_LEVEL_DEBUG, "cannot find \"" ZBX_MODULE_FUNC_ITEM_TIMEOUT "()\""
298 					" function in module \"%s\": %s", name, dlerror());
299 		}
300 		else
301 			func_timeout(timeout);
302 	}
303 
304 	/* module passed validation and can now be registered */
305 	module = zbx_register_module(lib, name);
306 
307 	if (NULL == (func_history_write_cbs = (ZBX_HISTORY_WRITE_CBS (*)(void))dlsym(lib,
308 			ZBX_MODULE_FUNC_HISTORY_WRITE_CBS)))
309 	{
310 		zabbix_log(LOG_LEVEL_DEBUG, "cannot find \"" ZBX_MODULE_FUNC_HISTORY_WRITE_CBS "()\""
311 				" function in module \"%s\": %s", name, dlerror());
312 	}
313 	else
314 		zbx_register_history_write_cbs(module, func_history_write_cbs());
315 
316 	return SUCCEED;
317 fail:
318 	dlclose(lib);
319 
320 	return FAIL;
321 }
322 
323 /******************************************************************************
324  *                                                                            *
325  * Function: zbx_load_modules                                                 *
326  *                                                                            *
327  * Purpose: load loadable modules (dynamic libraries)                         *
328  *                                                                            *
329  * Parameters: path - directory where modules are located                     *
330  *             file_names - list of module names                              *
331  *             timeout - timeout in seconds for processing of items by module *
332  *             verbose - output list of loaded modules                        *
333  *                                                                            *
334  * Return value: SUCCEED - all modules are successfully loaded                *
335  *               FAIL - loading of modules failed                             *
336  *                                                                            *
337  ******************************************************************************/
zbx_load_modules(const char * path,char ** file_names,int timeout,int verbose)338 int	zbx_load_modules(const char *path, char **file_names, int timeout, int verbose)
339 {
340 	char	**file_name;
341 	int	ret = SUCCEED;
342 
343 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
344 
345 	zbx_vector_ptr_create(&modules);
346 
347 	if (NULL == *file_names)
348 		goto out;
349 
350 	for (file_name = file_names; NULL != *file_name; file_name++)
351 	{
352 		if (SUCCEED != (ret = zbx_load_module(path, *file_name, timeout)))
353 			goto out;
354 	}
355 
356 	if (0 != verbose)
357 	{
358 		char	*buffer;
359 		int	i = 0;
360 
361 		/* if execution reached this point at least one module was loaded successfully */
362 		buffer = zbx_strdcat(NULL, ((zbx_module_t *)modules.values[i++])->name);
363 
364 		while (i < modules.values_num)
365 		{
366 			buffer = zbx_strdcat(buffer, ", ");
367 			buffer = zbx_strdcat(buffer, ((zbx_module_t *)modules.values[i++])->name);
368 		}
369 
370 		zabbix_log(LOG_LEVEL_WARNING, "loaded modules: %s", buffer);
371 		zbx_free(buffer);
372 	}
373 out:
374 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
375 
376 	return ret;
377 }
378 
379 /******************************************************************************
380  *                                                                            *
381  * Function: zbx_unload_module                                                *
382  *                                                                            *
383  * Purpose: unload module and free allocated resources                        *
384  *                                                                            *
385  ******************************************************************************/
zbx_unload_module(void * data)386 static void	zbx_unload_module(void *data)
387 {
388 	zbx_module_t	*module = (zbx_module_t *)data;
389 	int		(*func_uninit)(void);
390 
391 	if (NULL == (func_uninit = (int (*)(void))dlsym(module->lib, ZBX_MODULE_FUNC_UNINIT)))
392 	{
393 		zabbix_log(LOG_LEVEL_DEBUG, "cannot find \"" ZBX_MODULE_FUNC_UNINIT "()\""
394 				" function in module \"%s\": %s", module->name, dlerror());
395 	}
396 	else if (ZBX_MODULE_OK != func_uninit())
397 		zabbix_log(LOG_LEVEL_WARNING, "uninitialization of module \"%s\" failed", module->name);
398 
399 	dlclose(module->lib);
400 	zbx_free(module->name);
401 	zbx_free(module);
402 }
403 
404 /******************************************************************************
405  *                                                                            *
406  * Function: zbx_unload_modules                                               *
407  *                                                                            *
408  * Purpose: Unload already loaded loadable modules (dynamic libraries).       *
409  *          It is called on process shutdown.                                 *
410  *                                                                            *
411  ******************************************************************************/
zbx_unload_modules(void)412 void	zbx_unload_modules(void)
413 {
414 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
415 
416 	zbx_free(history_float_cbs);
417 	zbx_free(history_integer_cbs);
418 	zbx_free(history_string_cbs);
419 	zbx_free(history_text_cbs);
420 	zbx_free(history_log_cbs);
421 
422 	zbx_vector_ptr_clear_ext(&modules, zbx_unload_module);
423 	zbx_vector_ptr_destroy(&modules);
424 
425 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
426 }
427