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