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 "zbxself.h"
21 #include "common.h"
22 
23 #ifndef _WINDOWS
24 #	include "mutexs.h"
25 #	include "ipc.h"
26 #	include "log.h"
27 
28 #	define MAX_HISTORY	60
29 
30 typedef struct
31 {
32 	unsigned short	h_counter[ZBX_PROCESS_STATE_COUNT][MAX_HISTORY];
33 	unsigned short	counter[ZBX_PROCESS_STATE_COUNT];
34 	clock_t		last_ticks;
35 	unsigned char	last_state;
36 }
37 zbx_stat_process_t;
38 
39 typedef struct
40 {
41 	zbx_stat_process_t	**process;
42 	int			first;
43 	int			count;
44 }
45 zbx_selfmon_collector_t;
46 
47 static zbx_selfmon_collector_t	*collector = NULL;
48 static int			shm_id;
49 
50 #	define LOCK_SM		zbx_mutex_lock(&sm_lock)
51 #	define UNLOCK_SM	zbx_mutex_unlock(&sm_lock)
52 
53 static ZBX_MUTEX	sm_lock = ZBX_MUTEX_NULL;
54 #endif
55 
56 extern char	*CONFIG_FILE;
57 extern int	CONFIG_POLLER_FORKS;
58 extern int	CONFIG_UNREACHABLE_POLLER_FORKS;
59 extern int	CONFIG_IPMIPOLLER_FORKS;
60 extern int	CONFIG_PINGER_FORKS;
61 extern int	CONFIG_JAVAPOLLER_FORKS;
62 extern int	CONFIG_HTTPPOLLER_FORKS;
63 extern int	CONFIG_TRAPPER_FORKS;
64 extern int	CONFIG_SNMPTRAPPER_FORKS;
65 extern int	CONFIG_PROXYPOLLER_FORKS;
66 extern int	CONFIG_ESCALATOR_FORKS;
67 extern int	CONFIG_HISTSYNCER_FORKS;
68 extern int	CONFIG_DISCOVERER_FORKS;
69 extern int	CONFIG_ALERTER_FORKS;
70 extern int	CONFIG_TIMER_FORKS;
71 extern int	CONFIG_HOUSEKEEPER_FORKS;
72 extern int	CONFIG_WATCHDOG_FORKS;
73 extern int	CONFIG_DATASENDER_FORKS;
74 extern int	CONFIG_CONFSYNCER_FORKS;
75 extern int	CONFIG_HEARTBEAT_FORKS;
76 extern int	CONFIG_SELFMON_FORKS;
77 extern int	CONFIG_VMWARE_FORKS;
78 extern int	CONFIG_COLLECTOR_FORKS;
79 extern int	CONFIG_PASSIVE_FORKS;
80 extern int	CONFIG_ACTIVE_FORKS;
81 
82 extern unsigned char	process_type;
83 extern int		process_num;
84 
85 /******************************************************************************
86  *                                                                            *
87  * Function: get_process_type_forks                                           *
88  *                                                                            *
89  * Purpose: Returns number of processes depending on process type             *
90  *                                                                            *
91  * Parameters: process_type - [IN] process type; ZBX_PROCESS_TYPE_*           *
92  *                                                                            *
93  * Return value: number of processes                                          *
94  *                                                                            *
95  * Author: Alexander Vladishev                                                *
96  *                                                                            *
97  ******************************************************************************/
get_process_type_forks(unsigned char proc_type)98 int	get_process_type_forks(unsigned char proc_type)
99 {
100 	switch (proc_type)
101 	{
102 		case ZBX_PROCESS_TYPE_POLLER:
103 			return CONFIG_POLLER_FORKS;
104 		case ZBX_PROCESS_TYPE_UNREACHABLE:
105 			return CONFIG_UNREACHABLE_POLLER_FORKS;
106 		case ZBX_PROCESS_TYPE_IPMIPOLLER:
107 			return CONFIG_IPMIPOLLER_FORKS;
108 		case ZBX_PROCESS_TYPE_PINGER:
109 			return CONFIG_PINGER_FORKS;
110 		case ZBX_PROCESS_TYPE_JAVAPOLLER:
111 			return CONFIG_JAVAPOLLER_FORKS;
112 		case ZBX_PROCESS_TYPE_HTTPPOLLER:
113 			return CONFIG_HTTPPOLLER_FORKS;
114 		case ZBX_PROCESS_TYPE_TRAPPER:
115 			return CONFIG_TRAPPER_FORKS;
116 		case ZBX_PROCESS_TYPE_SNMPTRAPPER:
117 			return CONFIG_SNMPTRAPPER_FORKS;
118 		case ZBX_PROCESS_TYPE_PROXYPOLLER:
119 			return CONFIG_PROXYPOLLER_FORKS;
120 		case ZBX_PROCESS_TYPE_ESCALATOR:
121 			return CONFIG_ESCALATOR_FORKS;
122 		case ZBX_PROCESS_TYPE_HISTSYNCER:
123 			return CONFIG_HISTSYNCER_FORKS;
124 		case ZBX_PROCESS_TYPE_DISCOVERER:
125 			return CONFIG_DISCOVERER_FORKS;
126 		case ZBX_PROCESS_TYPE_ALERTER:
127 			return CONFIG_ALERTER_FORKS;
128 		case ZBX_PROCESS_TYPE_TIMER:
129 			return CONFIG_TIMER_FORKS;
130 		case ZBX_PROCESS_TYPE_HOUSEKEEPER:
131 			return CONFIG_HOUSEKEEPER_FORKS;
132 		case ZBX_PROCESS_TYPE_WATCHDOG:
133 			return CONFIG_WATCHDOG_FORKS;
134 		case ZBX_PROCESS_TYPE_DATASENDER:
135 			return CONFIG_DATASENDER_FORKS;
136 		case ZBX_PROCESS_TYPE_CONFSYNCER:
137 			return CONFIG_CONFSYNCER_FORKS;
138 		case ZBX_PROCESS_TYPE_HEARTBEAT:
139 			return CONFIG_HEARTBEAT_FORKS;
140 		case ZBX_PROCESS_TYPE_SELFMON:
141 			return CONFIG_SELFMON_FORKS;
142 		case ZBX_PROCESS_TYPE_VMWARE:
143 			return CONFIG_VMWARE_FORKS;
144 		case ZBX_PROCESS_TYPE_COLLECTOR:
145 			return CONFIG_COLLECTOR_FORKS;
146 		case ZBX_PROCESS_TYPE_LISTENER:
147 			return CONFIG_PASSIVE_FORKS;
148 		case ZBX_PROCESS_TYPE_ACTIVE_CHECKS:
149 			return CONFIG_ACTIVE_FORKS;
150 	}
151 
152 	THIS_SHOULD_NEVER_HAPPEN;
153 	exit(EXIT_FAILURE);
154 }
155 
156 /******************************************************************************
157  *                                                                            *
158  * Function: get_process_type_string                                          *
159  *                                                                            *
160  * Purpose: Returns process name                                              *
161  *                                                                            *
162  * Parameters: process_type - [IN] process type; ZBX_PROCESS_TYPE_*           *
163  *                                                                            *
164  * Author: Alexander Vladishev                                                *
165  *                                                                            *
166  * Comments: used in internals checks zabbix["process",...], process titles   *
167  *           and log files                                                    *
168  *                                                                            *
169  ******************************************************************************/
get_process_type_string(unsigned char proc_type)170 const char	*get_process_type_string(unsigned char proc_type)
171 {
172 	switch (proc_type)
173 	{
174 		case ZBX_PROCESS_TYPE_POLLER:
175 			return "poller";
176 		case ZBX_PROCESS_TYPE_UNREACHABLE:
177 			return "unreachable poller";
178 		case ZBX_PROCESS_TYPE_IPMIPOLLER:
179 			return "ipmi poller";
180 		case ZBX_PROCESS_TYPE_PINGER:
181 			return "icmp pinger";
182 		case ZBX_PROCESS_TYPE_JAVAPOLLER:
183 			return "java poller";
184 		case ZBX_PROCESS_TYPE_HTTPPOLLER:
185 			return "http poller";
186 		case ZBX_PROCESS_TYPE_TRAPPER:
187 			return "trapper";
188 		case ZBX_PROCESS_TYPE_SNMPTRAPPER:
189 			return "snmp trapper";
190 		case ZBX_PROCESS_TYPE_PROXYPOLLER:
191 			return "proxy poller";
192 		case ZBX_PROCESS_TYPE_ESCALATOR:
193 			return "escalator";
194 		case ZBX_PROCESS_TYPE_HISTSYNCER:
195 			return "history syncer";
196 		case ZBX_PROCESS_TYPE_DISCOVERER:
197 			return "discoverer";
198 		case ZBX_PROCESS_TYPE_ALERTER:
199 			return "alerter";
200 		case ZBX_PROCESS_TYPE_TIMER:
201 			return "timer";
202 		case ZBX_PROCESS_TYPE_HOUSEKEEPER:
203 			return "housekeeper";
204 		case ZBX_PROCESS_TYPE_WATCHDOG:
205 			return "db watchdog";
206 		case ZBX_PROCESS_TYPE_DATASENDER:
207 			return "data sender";
208 		case ZBX_PROCESS_TYPE_CONFSYNCER:
209 			return "configuration syncer";
210 		case ZBX_PROCESS_TYPE_HEARTBEAT:
211 			return "heartbeat sender";
212 		case ZBX_PROCESS_TYPE_SELFMON:
213 			return "self-monitoring";
214 		case ZBX_PROCESS_TYPE_VMWARE:
215 			return "vmware collector";
216 		case ZBX_PROCESS_TYPE_COLLECTOR:
217 			return "collector";
218 		case ZBX_PROCESS_TYPE_LISTENER:
219 			return "listener";
220 		case ZBX_PROCESS_TYPE_ACTIVE_CHECKS:
221 			return "active checks";
222 	}
223 
224 	THIS_SHOULD_NEVER_HAPPEN;
225 	exit(EXIT_FAILURE);
226 }
227 
get_process_type_by_name(const char * proc_type_str)228 int	get_process_type_by_name(const char *proc_type_str)
229 {
230 	int	i;
231 
232 	for (i = 0; i < ZBX_PROCESS_TYPE_COUNT; i++)
233 	{
234 		if (0 == strcmp(proc_type_str, get_process_type_string(i)))
235 			return i;
236 	}
237 
238 	return ZBX_PROCESS_TYPE_UNKNOWN;
239 }
240 
241 #ifndef _WINDOWS
242 /******************************************************************************
243  *                                                                            *
244  * Function: init_selfmon_collector                                           *
245  *                                                                            *
246  * Purpose: Initialize structures and prepare state                           *
247  *          for self-monitoring collector                                     *
248  *                                                                            *
249  * Author: Alexander Vladishev                                                *
250  *                                                                            *
251  ******************************************************************************/
init_selfmon_collector(void)252 void	init_selfmon_collector(void)
253 {
254 	const char	*__function_name = "init_selfmon_collector";
255 	size_t		sz, sz_array, sz_process[ZBX_PROCESS_TYPE_COUNT], sz_total;
256 	key_t		shm_key;
257 	char		*p;
258 	clock_t		ticks;
259 	struct tms	buf;
260 	unsigned char	proc_type;
261 	int		proc_num, process_forks;
262 
263 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
264 
265 	sz_total = sz = sizeof(zbx_selfmon_collector_t);
266 	sz_total += sz_array = sizeof(zbx_stat_process_t *) * ZBX_PROCESS_TYPE_COUNT;
267 
268 	for (proc_type = 0; ZBX_PROCESS_TYPE_COUNT > proc_type; proc_type++)
269 		sz_total += sz_process[proc_type] = sizeof(zbx_stat_process_t) * get_process_type_forks(proc_type);
270 
271 	zabbix_log(LOG_LEVEL_DEBUG, "%s() size:" ZBX_FS_SIZE_T, __function_name, (zbx_fs_size_t)sz_total);
272 
273 	if (-1 == (shm_key = zbx_ftok(CONFIG_FILE, ZBX_IPC_SELFMON_ID)))
274 	{
275 		zabbix_log(LOG_LEVEL_CRIT, "cannot create IPC key for a self-monitoring collector");
276 		exit(EXIT_FAILURE);
277 	}
278 
279 	if (FAIL == zbx_mutex_create_force(&sm_lock, ZBX_MUTEX_SELFMON))
280 	{
281 		zbx_error("unable to create mutex for a self-monitoring collector");
282 		exit(EXIT_FAILURE);
283 	}
284 
285 	if (-1 == (shm_id = zbx_shmget(shm_key, sz_total)))
286 	{
287 		zabbix_log(LOG_LEVEL_CRIT, "cannot allocate shared memory for a self-monitoring collector");
288 		exit(EXIT_FAILURE);
289 	}
290 
291 	if ((void *)(-1) == (p = shmat(shm_id, NULL, 0)))
292 	{
293 		zabbix_log(LOG_LEVEL_CRIT, "cannot attach shared memory for a self-monitoring collector: %s",
294 				zbx_strerror(errno));
295 		exit(EXIT_FAILURE);
296 	}
297 
298 	collector = (zbx_selfmon_collector_t *)p; p += sz;
299 	collector->process = (zbx_stat_process_t **)p; p += sz_array;
300 
301 	if (-1 == (ticks = times(&buf)))
302 	{
303 		zabbix_log(LOG_LEVEL_CRIT, "cannot get process times: %s", zbx_strerror(errno));
304 		exit(EXIT_FAILURE);
305 	}
306 
307 	for (proc_type = 0; ZBX_PROCESS_TYPE_COUNT > proc_type; proc_type++)
308 	{
309 		collector->process[proc_type] = (zbx_stat_process_t *)p; p += sz_process[proc_type];
310 		memset(collector->process[proc_type], 0, sz_process[proc_type]);
311 
312 		process_forks = get_process_type_forks(proc_type);
313 		for (proc_num = 0; proc_num < process_forks; proc_num++)
314 		{
315 			collector->process[proc_type][proc_num].last_ticks = ticks;
316 			collector->process[proc_type][proc_num].last_state = ZBX_PROCESS_STATE_BUSY;
317 		}
318 	}
319 
320 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s() collector:%p", __function_name, collector);
321 }
322 
323 /******************************************************************************
324  *                                                                            *
325  * Function: free_selfmon_collector                                           *
326  *                                                                            *
327  * Purpose: Free memory allocated for self-monitoring collector               *
328  *                                                                            *
329  * Author: Alexander Vladishev                                                *
330  *                                                                            *
331  ******************************************************************************/
free_selfmon_collector(void)332 void	free_selfmon_collector(void)
333 {
334 	const char	*__function_name = "free_selfmon_collector";
335 
336 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() collector:%p", __function_name, collector);
337 
338 	if (NULL == collector)
339 		return;
340 
341 	LOCK_SM;
342 
343 	collector = NULL;
344 
345 	if (-1 == shmctl(shm_id, IPC_RMID, 0))
346 	{
347 		zabbix_log(LOG_LEVEL_WARNING, "cannot remove shared memory for self-monitoring collector: %s",
348 				zbx_strerror(errno));
349 	}
350 
351 	UNLOCK_SM;
352 
353 	zbx_mutex_destroy(&sm_lock);
354 
355 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
356 }
357 
358 /******************************************************************************
359  *                                                                            *
360  * Function: update_selfmon_counter                                           *
361  *                                                                            *
362  * Parameters: state - [IN] new process state; ZBX_PROCESS_STATE_*            *
363  *                                                                            *
364  * Author: Alexander Vladishev                                                *
365  *                                                                            *
366  ******************************************************************************/
update_selfmon_counter(unsigned char state)367 void	update_selfmon_counter(unsigned char state)
368 {
369 	zbx_stat_process_t	*process;
370 	clock_t			ticks;
371 	struct tms		buf;
372 
373 	if (ZBX_PROCESS_TYPE_UNKNOWN == process_type)
374 		return;
375 
376 	process = &collector->process[process_type][process_num - 1];
377 
378 	if (-1 == (ticks = times(&buf)))
379 	{
380 		zabbix_log(LOG_LEVEL_WARNING, "cannot get process times: %s", zbx_strerror(errno));
381 		process->last_state = state;
382 		return;
383 	}
384 
385 	LOCK_SM;
386 
387 	if (ticks > process->last_ticks)
388 		process->counter[process->last_state] += ticks - process->last_ticks;
389 	process->last_ticks = ticks;
390 	process->last_state = state;
391 
392 	UNLOCK_SM;
393 }
394 
395 /******************************************************************************
396  *                                                                            *
397  * Function: collect_selfmon_stats                                            *
398  *                                                                            *
399  * Author: Alexander Vladishev                                                *
400  *                                                                            *
401  ******************************************************************************/
collect_selfmon_stats(void)402 void	collect_selfmon_stats(void)
403 {
404 	const char		*__function_name = "collect_selfmon_stats";
405 	zbx_stat_process_t	*process;
406 	clock_t			ticks;
407 	struct tms		buf;
408 	unsigned char		proc_type, state;
409 	int			proc_num, process_forks, index;
410 
411 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
412 
413 	LOCK_SM;
414 
415 	if (-1 == (ticks = times(&buf)))
416 	{
417 		zabbix_log(LOG_LEVEL_WARNING, "cannot get process times: %s", zbx_strerror(errno));
418 		goto unlock;
419 	}
420 
421 	if (MAX_HISTORY <= (index = collector->first + collector->count))
422 		index -= MAX_HISTORY;
423 
424 	if (collector->count < MAX_HISTORY)
425 		collector->count++;
426 	else if (++collector->first == MAX_HISTORY)
427 		collector->first = 0;
428 
429 	for (proc_type = 0; proc_type < ZBX_PROCESS_TYPE_COUNT; proc_type++)
430 	{
431 		process_forks = get_process_type_forks(proc_type);
432 		for (proc_num = 0; proc_num < process_forks; proc_num++)
433 		{
434 			process = &collector->process[proc_type][proc_num];
435 			for (state = 0; state < ZBX_PROCESS_STATE_COUNT; state++)
436 				process->h_counter[state][index] = process->counter[state];
437 			if (ticks > process->last_ticks)
438 				process->h_counter[process->last_state][index] += ticks - process->last_ticks;
439 		}
440 	}
441 unlock:
442 	UNLOCK_SM;
443 
444 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
445 }
446 
447 /******************************************************************************
448  *                                                                            *
449  * Function: get_selfmon_stats                                                *
450  *                                                                            *
451  * Purpose: calculate statistics for selected process                         *
452  *                                                                            *
453  * Parameters: proc_type    - [IN] type of process; ZBX_PROCESS_TYPE_*        *
454  *             aggr_func    - [IN] one of ZBX_AGGR_FUNC_*                     *
455  *             proc_num     - [IN] process number; 1 - first process;         *
456  *                                 0 - all processes                          *
457  *             state        - [IN] process state; ZBX_PROCESS_STATE_*         *
458  *             value        - [OUT] a pointer to a variable that receives     *
459  *                                  requested statistics                      *
460  *                                                                            *
461  * Author: Alexander Vladishev                                                *
462  *                                                                            *
463  ******************************************************************************/
get_selfmon_stats(unsigned char proc_type,unsigned char aggr_func,int proc_num,unsigned char state,double * value)464 void	get_selfmon_stats(unsigned char proc_type, unsigned char aggr_func, int proc_num,
465 		unsigned char state, double *value)
466 {
467 	const char	*__function_name = "get_selfmon_stats";
468 	unsigned int	total = 0, counter = 0;
469 	unsigned char	s;
470 	int		process_forks, current;
471 
472 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
473 
474 	process_forks = get_process_type_forks(proc_type);
475 
476 	switch (aggr_func)
477 	{
478 		case ZBX_AGGR_FUNC_ONE:
479 			assert(0 < proc_num && proc_num <= process_forks);
480 			process_forks = proc_num--;
481 			break;
482 		case ZBX_AGGR_FUNC_AVG:
483 		case ZBX_AGGR_FUNC_MAX:
484 		case ZBX_AGGR_FUNC_MIN:
485 			assert(0 == proc_num && 0 < process_forks);
486 			break;
487 		default:
488 			assert(0);
489 	}
490 
491 	LOCK_SM;
492 
493 	if (1 >= collector->count)
494 		goto unlock;
495 
496 	if (MAX_HISTORY <= (current = (collector->first + collector->count - 1)))
497 		current -= MAX_HISTORY;
498 
499 	for (; proc_num < process_forks; proc_num++)
500 	{
501 		zbx_stat_process_t	*process;
502 		unsigned short		one_total = 0, one_counter;
503 
504 		process = &collector->process[proc_type][proc_num];
505 
506 		for (s = 0; s < ZBX_PROCESS_STATE_COUNT; s++)
507 			one_total += process->h_counter[s][current] - process->h_counter[s][collector->first];
508 
509 		one_counter = process->h_counter[state][current] - process->h_counter[state][collector->first];
510 
511 		switch (aggr_func)
512 		{
513 			case ZBX_AGGR_FUNC_ONE:
514 			case ZBX_AGGR_FUNC_AVG:
515 				total += one_total;
516 				counter += one_counter;
517 				break;
518 			case ZBX_AGGR_FUNC_MAX:
519 				if (0 == proc_num || one_counter > counter)
520 				{
521 					counter = one_counter;
522 					total = one_total;
523 				}
524 				break;
525 			case ZBX_AGGR_FUNC_MIN:
526 				if (0 == proc_num || one_counter < counter)
527 				{
528 					counter = one_counter;
529 					total = one_total;
530 				}
531 				break;
532 		}
533 	}
534 
535 unlock:
536 	UNLOCK_SM;
537 
538 	*value = (0 == total ? 0 : 100. * (double)counter / (double)total);
539 
540 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
541 }
542 
543 static int	sleep_remains;
544 
545 /******************************************************************************
546  *                                                                            *
547  * Function: zbx_sleep_loop                                                   *
548  *                                                                            *
549  * Purpose: sleeping process                                                  *
550  *                                                                            *
551  * Parameters: sleeptime - [IN] required sleeptime, in seconds                *
552  *                                                                            *
553  * Author: Alexander Vladishev                                                *
554  *                                                                            *
555  ******************************************************************************/
zbx_sleep_loop(int sleeptime)556 void	zbx_sleep_loop(int sleeptime)
557 {
558 	if (0 >= sleeptime)
559 		return;
560 
561 	sleep_remains = sleeptime;
562 
563 	update_selfmon_counter(ZBX_PROCESS_STATE_IDLE);
564 
565 	do
566 	{
567 		sleep(1);
568 	}
569 	while (0 < --sleep_remains);
570 
571 	update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
572 }
573 
zbx_sleep_forever(void)574 void	zbx_sleep_forever(void)
575 {
576 	sleep_remains = 1;
577 
578 	update_selfmon_counter(ZBX_PROCESS_STATE_IDLE);
579 
580 	do
581 	{
582 		sleep(1);
583 	}
584 	while (0 != sleep_remains);
585 
586 	update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
587 }
588 
zbx_wakeup(void)589 void	zbx_wakeup(void)
590 {
591 	sleep_remains = 0;
592 }
593 
zbx_sleep_get_remainder(void)594 int	zbx_sleep_get_remainder(void)
595 {
596 	return sleep_remains;
597 }
598 #endif
599