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