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
27 #define ZBX_MODULE_FUNC_INIT "zbx_module_init"
28 #define ZBX_MODULE_FUNC_API_VERSION "zbx_module_api_version"
29 #define ZBX_MODULE_FUNC_ITEM_LIST "zbx_module_item_list"
30 #define ZBX_MODULE_FUNC_ITEM_PROCESS "zbx_module_item_process"
31 #define ZBX_MODULE_FUNC_ITEM_TIMEOUT "zbx_module_item_timeout"
32 #define ZBX_MODULE_FUNC_UNINIT "zbx_module_uninit"
33
34 static void **modules = NULL;
35
36 /******************************************************************************
37 * *
38 * Function: register_module *
39 * *
40 * Purpose: Add module to the list of loaded modules (dynamic libraries). *
41 * It skips a module if it is already registered. *
42 * *
43 * Parameters: module - library handler *
44 * *
45 * Return value: SUCCEED - if module is successfully registered *
46 * FAIL - if module is already registered *
47 * *
48 ******************************************************************************/
register_module(void * module)49 static int register_module(void *module)
50 {
51 const char *__function_name = "register_module";
52
53 int i = 0, ret = FAIL;
54
55 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
56
57 if (NULL == modules)
58 {
59 modules = zbx_malloc(modules, sizeof(void *));
60 modules[0] = NULL;
61 }
62
63 while (NULL != modules[i])
64 {
65 if (module == modules[i]) /* a module is already registered */
66 goto out;
67 i++;
68 }
69
70 modules = zbx_realloc(modules, (i + 2) * sizeof(void *));
71 modules[i] = module;
72 modules[i + 1] = NULL;
73
74 ret = SUCCEED;
75 out:
76 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
77
78 return ret;
79 }
80
81 /******************************************************************************
82 * *
83 * Function: load_modules *
84 * *
85 * Purpose: load loadable modules (dynamic libraries) *
86 * It skips a module in case of any errors *
87 * *
88 * Parameters: path - directory where modules are located *
89 * file_names - list of module names *
90 * timeout - timeout in seconds for processing of items by module *
91 * verbose - output list of loaded modules *
92 * *
93 * Return value: SUCCEED - all modules is successfully loaded *
94 * FAIL - loading of modules failed *
95 * *
96 ******************************************************************************/
load_modules(const char * path,char ** file_names,int timeout,int verbose)97 int load_modules(const char *path, char **file_names, int timeout, int verbose)
98 {
99 const char *__function_name = "load_modules";
100
101 char **file_name, *buffer = NULL;
102 void *lib;
103 char full_name[MAX_STRING_LEN], error[MAX_STRING_LEN];
104 int (*func_init)(), (*func_version)();
105 ZBX_METRIC *(*func_list)();
106 void (*func_timeout)();
107 int i, ret = FAIL;
108
109 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
110
111 for (file_name = file_names; NULL != *file_name; file_name++)
112 {
113 zbx_snprintf(full_name, sizeof(full_name), "%s/%s", path, *file_name);
114
115 zabbix_log(LOG_LEVEL_DEBUG, "loading module \"%s\"", full_name);
116
117 if (NULL == (lib = dlopen(full_name, RTLD_NOW)))
118 {
119 zabbix_log(LOG_LEVEL_CRIT, "cannot load module \"%s\": %s", *file_name, dlerror());
120 goto fail;
121 }
122
123 func_version = (int (*)(void))dlsym(lib, ZBX_MODULE_FUNC_API_VERSION);
124 if (NULL == func_version)
125 {
126 zabbix_log(LOG_LEVEL_CRIT, "cannot find \"" ZBX_MODULE_FUNC_API_VERSION "()\""
127 " function in module \"%s\": %s", *file_name, dlerror());
128 dlclose(lib);
129 goto fail;
130 }
131
132 if (ZBX_MODULE_API_VERSION_ONE != (i = func_version()))
133 {
134 zabbix_log(LOG_LEVEL_CRIT, "unsupported module \"%s\" version: %d", *file_name, i);
135 dlclose(lib);
136 goto fail;
137 }
138
139 func_init = (int (*)(void))dlsym(lib, ZBX_MODULE_FUNC_INIT);
140 if (NULL == func_init)
141 {
142 zabbix_log(LOG_LEVEL_CRIT, "cannot find \"" ZBX_MODULE_FUNC_INIT "()\""
143 " function in module \"%s\": %s", *file_name, dlerror());
144 dlclose(lib);
145 goto fail;
146 }
147
148 if (ZBX_MODULE_OK != func_init())
149 {
150 zabbix_log(LOG_LEVEL_CRIT, "cannot initialize module \"%s\"", *file_name);
151 dlclose(lib);
152 goto fail;
153 }
154
155 /* the function is optional, zabbix will load the module even if it is missing */
156 func_timeout = (void (*)(void))dlsym(lib, ZBX_MODULE_FUNC_ITEM_TIMEOUT);
157 if (NULL == func_timeout)
158 {
159 zabbix_log(LOG_LEVEL_DEBUG, "cannot find \"" ZBX_MODULE_FUNC_ITEM_TIMEOUT "()\""
160 " function in module \"%s\": %s", *file_name, dlerror());
161 }
162 else
163 func_timeout(timeout);
164
165 func_list = (ZBX_METRIC *(*)(void))dlsym(lib, ZBX_MODULE_FUNC_ITEM_LIST);
166 if (NULL == func_list)
167 {
168 zabbix_log(LOG_LEVEL_WARNING, "cannot find \"" ZBX_MODULE_FUNC_ITEM_LIST "()\""
169 " function in module \"%s\": %s", *file_name, dlerror());
170 dlclose(lib);
171 continue;
172 }
173
174 if (SUCCEED == register_module(lib))
175 {
176 ZBX_METRIC *metrics;
177
178 metrics = func_list();
179
180 for (i = 0; NULL != metrics[i].key; i++)
181 {
182 /* accept only CF_HAVEPARAMS flag from module items */
183 metrics[i].flags &= CF_HAVEPARAMS;
184 /* the flag means that the items comes from a loadable module */
185 metrics[i].flags |= CF_MODULE;
186 if (SUCCEED != add_metric(&metrics[i], error, sizeof(error)))
187 {
188 zabbix_log(LOG_LEVEL_CRIT, "cannot load module \"%s\": %s", *file_name, error);
189 exit(EXIT_FAILURE);
190 }
191 }
192
193 if (1 == verbose)
194 {
195 if (NULL != buffer)
196 buffer = zbx_strdcat(buffer, ", ");
197 buffer = zbx_strdcat(buffer, *file_name);
198 }
199 }
200 }
201
202 if (NULL != buffer)
203 zabbix_log(LOG_LEVEL_WARNING, "loaded modules: %s", buffer);
204
205 ret = SUCCEED;
206 fail:
207 zbx_free(buffer);
208
209 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
210
211 return ret;
212 }
213
214 /******************************************************************************
215 * *
216 * Function: unload_modules *
217 * *
218 * Purpose: Unload already loaded loadable modules (dynamic libraries). *
219 * It is called on process shutdown. *
220 * *
221 ******************************************************************************/
unload_modules()222 void unload_modules()
223 {
224 const char *__function_name = "unload_modules";
225
226 int (*func_uninit)();
227 void **module;
228
229 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
230
231 /* there are no registered modules */
232 if (NULL == modules)
233 goto out;
234
235 for (module = modules; NULL != *module; module++)
236 {
237 func_uninit = (int (*)(void))dlsym(*module, ZBX_MODULE_FUNC_UNINIT);
238 if (NULL == func_uninit)
239 {
240 zabbix_log(LOG_LEVEL_DEBUG, "cannot find \"" ZBX_MODULE_FUNC_UNINIT "()\" function: %s",
241 dlerror());
242 dlclose(*module);
243 continue;
244 }
245
246 if (ZBX_MODULE_OK != func_uninit())
247 zabbix_log(LOG_LEVEL_WARNING, "uninitialization failed");
248
249 dlclose(*module);
250 }
251
252 zbx_free(modules);
253 out:
254 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
255 }
256