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 "sysinfo.h"
23 #include "log.h"
24 #include "cfg.h"
25 #include "alias.h"
26 #include "threads.h"
27 #include "sighandler.h"
28
29 #ifdef WITH_AGENT_METRICS
30 # include "agent/agent.h"
31 #endif
32
33 #ifdef WITH_COMMON_METRICS
34 # include "common/common.h"
35 #endif
36
37 #ifdef WITH_SIMPLE_METRICS
38 # include "simple/simple.h"
39 #endif
40
41 #ifdef WITH_SPECIFIC_METRICS
42 # include "specsysinfo.h"
43 #endif
44
45 #ifdef WITH_HOSTNAME_METRIC
46 extern ZBX_METRIC parameter_hostname;
47 #endif
48
49 static ZBX_METRIC *commands = NULL;
50
51 #define ZBX_COMMAND_ERROR 0
52 #define ZBX_COMMAND_WITHOUT_PARAMS 1
53 #define ZBX_COMMAND_WITH_PARAMS 2
54
55 /******************************************************************************
56 * *
57 * Function: parse_command_dyn *
58 * *
59 * Purpose: parses item key and splits it into command and parameters *
60 * *
61 * Return value: ZBX_COMMAND_ERROR - error *
62 * ZBX_COMMAND_WITHOUT_PARAMS - command without parameters *
63 * ZBX_COMMAND_WITH_PARAMS - command with parameters *
64 * *
65 ******************************************************************************/
parse_command_dyn(const char * command,char ** cmd,char ** param)66 static int parse_command_dyn(const char *command, char **cmd, char **param)
67 {
68 const char *pl, *pr;
69 size_t cmd_alloc = 0, param_alloc = 0,
70 cmd_offset = 0, param_offset = 0;
71
72 for (pl = command; SUCCEED == is_key_char(*pl); pl++)
73 ;
74
75 if (pl == command)
76 return ZBX_COMMAND_ERROR;
77
78 zbx_strncpy_alloc(cmd, &cmd_alloc, &cmd_offset, command, pl - command);
79
80 if ('\0' == *pl) /* no parameters specified */
81 return ZBX_COMMAND_WITHOUT_PARAMS;
82
83 if ('[' != *pl) /* unsupported character */
84 return ZBX_COMMAND_ERROR;
85
86 for (pr = ++pl; '\0' != *pr; pr++)
87 ;
88
89 if (']' != *--pr)
90 return ZBX_COMMAND_ERROR;
91
92 zbx_strncpy_alloc(param, ¶m_alloc, ¶m_offset, pl, pr - pl);
93
94 return ZBX_COMMAND_WITH_PARAMS;
95 }
96
97 /******************************************************************************
98 * *
99 * Function: add_metric *
100 * *
101 * Purpose: registers a new item key into the system *
102 * *
103 ******************************************************************************/
add_metric(ZBX_METRIC * metric,char * error,size_t max_error_len)104 int add_metric(ZBX_METRIC *metric, char *error, size_t max_error_len)
105 {
106 int i = 0;
107
108 while (NULL != commands[i].key)
109 {
110 if (0 == strcmp(commands[i].key, metric->key))
111 {
112 zbx_snprintf(error, max_error_len, "key \"%s\" already exists", metric->key);
113 return FAIL; /* metric already exists */
114 }
115 i++;
116 }
117
118 commands[i].key = zbx_strdup(NULL, metric->key);
119 commands[i].flags = metric->flags;
120 commands[i].function = metric->function;
121 commands[i].test_param = (NULL == metric->test_param ? NULL : zbx_strdup(NULL, metric->test_param));
122
123 commands = (ZBX_METRIC *)zbx_realloc(commands, (i + 2) * sizeof(ZBX_METRIC));
124 memset(&commands[i + 1], 0, sizeof(ZBX_METRIC));
125
126 return SUCCEED;
127 }
128
add_user_parameter(const char * itemkey,char * command,char * error,size_t max_error_len)129 int add_user_parameter(const char *itemkey, char *command, char *error, size_t max_error_len)
130 {
131 int ret;
132 unsigned flags = CF_USERPARAMETER;
133 ZBX_METRIC metric;
134 AGENT_REQUEST request;
135
136 init_request(&request);
137
138 if (SUCCEED == (ret = parse_item_key(itemkey, &request)))
139 {
140 if (1 == get_rparams_num(&request) && 0 == strcmp("[*]", itemkey + strlen(get_rkey(&request))))
141 flags |= CF_HAVEPARAMS;
142 else if (0 != get_rparams_num(&request))
143 ret = FAIL;
144 }
145
146 if (SUCCEED == ret)
147 {
148 metric.key = get_rkey(&request);
149 metric.flags = flags;
150 metric.function = &EXECUTE_USER_PARAMETER;
151 metric.test_param = command;
152
153 ret = add_metric(&metric, error, max_error_len);
154 }
155 else
156 zbx_strlcpy(error, "syntax error", max_error_len);
157
158 free_request(&request);
159
160 return ret;
161 }
162
init_metrics(void)163 void init_metrics(void)
164 {
165 int i;
166 char error[MAX_STRING_LEN];
167
168 commands = (ZBX_METRIC *)zbx_malloc(commands, sizeof(ZBX_METRIC));
169 commands[0].key = NULL;
170
171 #ifdef WITH_AGENT_METRICS
172 for (i = 0; NULL != parameters_agent[i].key; i++)
173 {
174 if (SUCCEED != add_metric(¶meters_agent[i], error, sizeof(error)))
175 {
176 zabbix_log(LOG_LEVEL_CRIT, "cannot add item key: %s", error);
177 exit(EXIT_FAILURE);
178 }
179 }
180 #endif
181
182 #ifdef WITH_COMMON_METRICS
183 for (i = 0; NULL != parameters_common[i].key; i++)
184 {
185 if (SUCCEED != add_metric(¶meters_common[i], error, sizeof(error)))
186 {
187 zabbix_log(LOG_LEVEL_CRIT, "cannot add item key: %s", error);
188 exit(EXIT_FAILURE);
189 }
190 }
191 #endif
192
193 #ifdef WITH_SPECIFIC_METRICS
194 for (i = 0; NULL != parameters_specific[i].key; i++)
195 {
196 if (SUCCEED != add_metric(¶meters_specific[i], error, sizeof(error)))
197 {
198 zabbix_log(LOG_LEVEL_CRIT, "cannot add item key: %s", error);
199 exit(EXIT_FAILURE);
200 }
201 }
202 #endif
203
204 #ifdef WITH_SIMPLE_METRICS
205 for (i = 0; NULL != parameters_simple[i].key; i++)
206 {
207 if (SUCCEED != add_metric(¶meters_simple[i], error, sizeof(error)))
208 {
209 zabbix_log(LOG_LEVEL_CRIT, "cannot add item key: %s", error);
210 exit(EXIT_FAILURE);
211 }
212 }
213 #endif
214
215 #ifdef WITH_HOSTNAME_METRIC
216 if (SUCCEED != add_metric(¶meter_hostname, error, sizeof(error)))
217 {
218 zabbix_log(LOG_LEVEL_CRIT, "cannot add item key: %s", error);
219 exit(EXIT_FAILURE);
220 }
221 #endif
222 }
223
free_metrics(void)224 void free_metrics(void)
225 {
226 if (NULL != commands)
227 {
228 int i;
229
230 for (i = 0; NULL != commands[i].key; i++)
231 {
232 zbx_free(commands[i].key);
233 zbx_free(commands[i].test_param);
234 }
235
236 zbx_free(commands);
237 }
238 }
239
zbx_log_init(zbx_log_t * log)240 static void zbx_log_init(zbx_log_t *log)
241 {
242 log->value = NULL;
243 log->source = NULL;
244 log->timestamp = 0;
245 log->severity = 0;
246 log->logeventid = 0;
247 }
248
init_result(AGENT_RESULT * result)249 void init_result(AGENT_RESULT *result)
250 {
251 memset(result, 0, sizeof(AGENT_RESULT));
252 }
253
zbx_log_clean(zbx_log_t * log)254 static void zbx_log_clean(zbx_log_t *log)
255 {
256 zbx_free(log->source);
257 zbx_free(log->value);
258 }
259
zbx_log_free(zbx_log_t * log)260 void zbx_log_free(zbx_log_t *log)
261 {
262 zbx_log_clean(log);
263 zbx_free(log);
264 }
265
free_result(AGENT_RESULT * result)266 void free_result(AGENT_RESULT *result)
267 {
268 UNSET_UI64_RESULT(result);
269 UNSET_DBL_RESULT(result);
270 UNSET_STR_RESULT(result);
271 UNSET_TEXT_RESULT(result);
272 UNSET_LOG_RESULT(result);
273 UNSET_MSG_RESULT(result);
274 }
275
276 /******************************************************************************
277 * *
278 * Function: init_request *
279 * *
280 * Purpose: initialize the request structure *
281 * *
282 * Parameters: request - pointer to the structure *
283 * *
284 ******************************************************************************/
init_request(AGENT_REQUEST * request)285 void init_request(AGENT_REQUEST *request)
286 {
287 request->key = NULL;
288 request->nparam = 0;
289 request->params = NULL;
290 request->types = NULL;
291 request->lastlogsize = 0;
292 request->mtime = 0;
293 }
294
295 /******************************************************************************
296 * *
297 * Function: free_request_params *
298 * *
299 * Purpose: free memory used by the request parameters *
300 * *
301 * Parameters: request - pointer to the request structure *
302 * *
303 ******************************************************************************/
free_request_params(AGENT_REQUEST * request)304 static void free_request_params(AGENT_REQUEST *request)
305 {
306 int i;
307
308 for (i = 0; i < request->nparam; i++)
309 zbx_free(request->params[i]);
310 zbx_free(request->params);
311 zbx_free(request->types);
312
313 request->nparam = 0;
314 }
315
316 /******************************************************************************
317 * *
318 * Function: free_request *
319 * *
320 * Purpose: free memory used by the request *
321 * *
322 * Parameters: request - pointer to the request structure *
323 * *
324 ******************************************************************************/
free_request(AGENT_REQUEST * request)325 void free_request(AGENT_REQUEST *request)
326 {
327 zbx_free(request->key);
328 free_request_params(request);
329 }
330
331 /******************************************************************************
332 * *
333 * Function: add_request_param *
334 * *
335 * Purpose: add a new parameter *
336 * *
337 * Parameters: request - [OUT] pointer to the request structure *
338 * pvalue - [IN] parameter value string *
339 * type - [IN] parameter type *
340 * *
341 ******************************************************************************/
add_request_param(AGENT_REQUEST * request,char * pvalue,zbx_request_parameter_type_t type)342 static void add_request_param(AGENT_REQUEST *request, char *pvalue, zbx_request_parameter_type_t type)
343 {
344 request->nparam++;
345 request->params = (char **)zbx_realloc(request->params, request->nparam * sizeof(char *));
346 request->params[request->nparam - 1] = pvalue;
347 request->types = (zbx_request_parameter_type_t*)zbx_realloc(request->types,
348 request->nparam * sizeof(zbx_request_parameter_type_t));
349 request->types[request->nparam - 1] = type;
350 }
351
352 /******************************************************************************
353 * *
354 * Function: parse_item_key *
355 * *
356 * Purpose: parse item command (key) and fill AGENT_REQUEST structure *
357 * *
358 * Parameters: itemkey - complete item key *
359 * *
360 * Return value: request - structure filled with data from item key *
361 * *
362 ******************************************************************************/
parse_item_key(const char * itemkey,AGENT_REQUEST * request)363 int parse_item_key(const char *itemkey, AGENT_REQUEST *request)
364 {
365 int i, ret = FAIL;
366 char *key = NULL, *params = NULL;
367
368 switch (parse_command_dyn(itemkey, &key, ¶ms))
369 {
370 case ZBX_COMMAND_WITH_PARAMS:
371 if (0 == (request->nparam = num_param(params)))
372 goto out; /* key is badly formatted */
373
374 request->params = (char **)zbx_malloc(request->params, request->nparam * sizeof(char *));
375 request->types = (zbx_request_parameter_type_t*)zbx_malloc(request->types,
376 request->nparam * sizeof(zbx_request_parameter_type_t));
377
378 for (i = 0; i < request->nparam; i++)
379 request->params[i] = get_param_dyn(params, i + 1, &request->types[i]);
380 break;
381 case ZBX_COMMAND_ERROR:
382 goto out; /* key is badly formatted */
383 }
384
385 request->key = key;
386 key = NULL;
387
388 ret = SUCCEED;
389 out:
390 zbx_free(params);
391 zbx_free(key);
392
393 return ret;
394 }
395
test_parameter(const char * key)396 void test_parameter(const char *key)
397 {
398 #define ZBX_KEY_COLUMN_WIDTH 45
399
400 AGENT_RESULT result;
401
402 printf("%-*s", ZBX_KEY_COLUMN_WIDTH, key);
403
404 init_result(&result);
405
406 if (SUCCEED == process(key, PROCESS_WITH_ALIAS, &result))
407 {
408 if (0 != ISSET_UI64(&result))
409 printf(" [u|" ZBX_FS_UI64 "]", result.ui64);
410
411 if (0 != ISSET_DBL(&result))
412 printf(" [d|" ZBX_FS_DBL "]", result.dbl);
413
414 if (0 != ISSET_STR(&result))
415 printf(" [s|%s]", result.str);
416
417 if (0 != ISSET_TEXT(&result))
418 printf(" [t|%s]", result.text);
419
420 if (0 != ISSET_MSG(&result))
421 printf(" [m|%s]", result.msg);
422 }
423 else
424 {
425 if (0 != ISSET_MSG(&result))
426 printf(" [m|" ZBX_NOTSUPPORTED "] [%s]", result.msg);
427 else
428 printf(" [m|" ZBX_NOTSUPPORTED "]");
429 }
430
431 free_result(&result);
432
433 printf("\n");
434
435 fflush(stdout);
436
437 #undef ZBX_KEY_COLUMN_WIDTH
438 }
439
test_parameters(void)440 void test_parameters(void)
441 {
442 int i;
443 char *key = NULL;
444 size_t key_alloc = 0;
445
446 for (i = 0; NULL != commands[i].key; i++)
447 {
448 if (0 != strcmp(commands[i].key, "__UserPerfCounter"))
449 {
450 size_t key_offset = 0;
451
452 zbx_strcpy_alloc(&key, &key_alloc, &key_offset, commands[i].key);
453
454 if (0 == (commands[i].flags & CF_USERPARAMETER) && NULL != commands[i].test_param)
455 {
456 zbx_chrcpy_alloc(&key, &key_alloc, &key_offset, '[');
457 zbx_strcpy_alloc(&key, &key_alloc, &key_offset, commands[i].test_param);
458 zbx_chrcpy_alloc(&key, &key_alloc, &key_offset, ']');
459 }
460
461 test_parameter(key);
462 }
463 }
464
465 zbx_free(key);
466
467 test_aliases();
468 }
469
zbx_check_user_parameter(const char * param,char * error,int max_error_len)470 static int zbx_check_user_parameter(const char *param, char *error, int max_error_len)
471 {
472 const char suppressed_chars[] = "\\'\"`*?[]{}~$!&;()<>|#@\n", *c;
473 char *buf = NULL;
474 size_t buf_alloc = 128, buf_offset = 0;
475
476 if (0 != CONFIG_UNSAFE_USER_PARAMETERS)
477 return SUCCEED;
478
479 for (c = suppressed_chars; '\0' != *c; c++)
480 {
481 if (NULL == strchr(param, *c))
482 continue;
483
484 buf = (char *)zbx_malloc(buf, buf_alloc);
485
486 for (c = suppressed_chars; '\0' != *c; c++)
487 {
488 if (c != suppressed_chars)
489 zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, ", ");
490
491 if (0 != isprint(*c))
492 zbx_chrcpy_alloc(&buf, &buf_alloc, &buf_offset, *c);
493 else
494 zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, "0x%02x", (unsigned int)(*c));
495 }
496
497 zbx_snprintf(error, max_error_len, "Special characters \"%s\" are not allowed in the parameters.", buf);
498
499 zbx_free(buf);
500
501 return FAIL;
502 }
503
504 return SUCCEED;
505 }
506
replace_param(const char * cmd,const AGENT_REQUEST * request,char ** out,char * error,int max_error_len)507 static int replace_param(const char *cmd, const AGENT_REQUEST *request, char **out, char *error, int max_error_len)
508 {
509 const char *pl = cmd, *pr, *tmp;
510 size_t out_alloc = 0, out_offset = 0;
511 int num, ret = SUCCEED;
512
513 while (NULL != (pr = strchr(pl, '$')))
514 {
515 zbx_strncpy_alloc(out, &out_alloc, &out_offset, pl, pr - pl);
516
517 /* check if increasing pointer by 1 will not result in buffer overrun */
518 if ('\0' != pr[1])
519 pr++;
520
521 if ('0' == *pr)
522 {
523 zbx_strcpy_alloc(out, &out_alloc, &out_offset, cmd);
524 }
525 else if ('1' <= *pr && *pr <= '9')
526 {
527 num = (int)(*pr - '0');
528
529 if (request->nparam >= num)
530 {
531 tmp = get_rparam(request, num - 1);
532
533 if (SUCCEED != (ret = zbx_check_user_parameter(tmp, error, max_error_len)))
534 break;
535
536 zbx_strcpy_alloc(out, &out_alloc, &out_offset, tmp);
537 }
538 }
539 else
540 {
541 if ('$' != *pr)
542 zbx_chrcpy_alloc(out, &out_alloc, &out_offset, '$');
543 zbx_chrcpy_alloc(out, &out_alloc, &out_offset, *pr);
544 }
545
546 pl = pr + 1;
547 }
548
549 if (SUCCEED == ret)
550 zbx_strcpy_alloc(out, &out_alloc, &out_offset, pl);
551 else
552 zbx_free(*out);
553
554 return ret;
555 }
556
557 /******************************************************************************
558 * *
559 * Function: process *
560 * *
561 * Purpose: execute agent check *
562 * *
563 * Parameters: in_command - item key *
564 * flags - PROCESS_LOCAL_COMMAND, allow execution of system.run *
565 * PROCESS_MODULE_COMMAND, execute item from a module *
566 * PROCESS_WITH_ALIAS, substitute agent Alias *
567 * *
568 * Return value: SUCCEED - successful execution *
569 * NOTSUPPORTED - item key is not supported or other error *
570 * result - contains item value or error message *
571 * *
572 ******************************************************************************/
process(const char * in_command,unsigned flags,AGENT_RESULT * result)573 int process(const char *in_command, unsigned flags, AGENT_RESULT *result)
574 {
575 int ret = NOTSUPPORTED;
576 ZBX_METRIC *command = NULL;
577 AGENT_REQUEST request;
578
579 init_request(&request);
580
581 if (SUCCEED != parse_item_key((0 == (flags & PROCESS_WITH_ALIAS) ? in_command : zbx_alias_get(in_command)),
582 &request))
583 {
584 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid item key format."));
585 goto notsupported;
586 }
587
588 /* system.run is not allowed by default except for getting hostname for daemons */
589 if (1 != CONFIG_ENABLE_REMOTE_COMMANDS && 0 == (flags & PROCESS_LOCAL_COMMAND) &&
590 0 == strcmp(request.key, "system.run"))
591 {
592 SET_MSG_RESULT(result, zbx_strdup(NULL, "Remote commands are not enabled."));
593 goto notsupported;
594 }
595
596 for (command = commands; NULL != command->key; command++)
597 {
598 if (0 == strcmp(command->key, request.key))
599 break;
600 }
601
602 /* item key not found */
603 if (NULL == command->key)
604 {
605 SET_MSG_RESULT(result, zbx_strdup(NULL, "Unsupported item key."));
606 goto notsupported;
607 }
608
609 /* expected item from a module */
610 if (0 != (flags & PROCESS_MODULE_COMMAND) && 0 == (command->flags & CF_MODULE))
611 {
612 SET_MSG_RESULT(result, zbx_strdup(NULL, "Unsupported item key."));
613 goto notsupported;
614 }
615
616 /* command does not accept parameters but was called with parameters */
617 if (0 == (command->flags & CF_HAVEPARAMS) && 0 != request.nparam)
618 {
619 SET_MSG_RESULT(result, zbx_strdup(NULL, "Item does not allow parameters."));
620 goto notsupported;
621 }
622
623 if (0 != (command->flags & CF_USERPARAMETER))
624 {
625 if (0 != (command->flags & CF_HAVEPARAMS))
626 {
627 char *parameters = NULL, error[MAX_STRING_LEN];
628
629 if (FAIL == replace_param(command->test_param, &request, ¶meters, error, sizeof(error)))
630 {
631 SET_MSG_RESULT(result, zbx_strdup(NULL, error));
632 goto notsupported;
633 }
634
635 free_request_params(&request);
636 add_request_param(&request, parameters, REQUEST_PARAMETER_TYPE_STRING);
637 }
638 else
639 {
640 free_request_params(&request);
641 add_request_param(&request, zbx_strdup(NULL, command->test_param),
642 REQUEST_PARAMETER_TYPE_STRING);
643 }
644 }
645
646 if (SYSINFO_RET_OK != command->function(&request, result))
647 {
648 /* "return NOTSUPPORTED;" would be more appropriate here for preserving original error */
649 /* message in "result" but would break things relying on ZBX_NOTSUPPORTED message. */
650 if (0 != (command->flags & CF_MODULE) && 0 == ISSET_MSG(result))
651 SET_MSG_RESULT(result, zbx_strdup(NULL, ZBX_NOTSUPPORTED_MSG));
652
653 goto notsupported;
654 }
655
656 ret = SUCCEED;
657
658 notsupported:
659 free_request(&request);
660
661 return ret;
662 }
663
add_log_result(AGENT_RESULT * result,const char * value)664 static void add_log_result(AGENT_RESULT *result, const char *value)
665 {
666 result->log = (zbx_log_t *)zbx_malloc(result->log, sizeof(zbx_log_t));
667
668 zbx_log_init(result->log);
669
670 result->log->value = zbx_strdup(result->log->value, value);
671 result->type |= AR_LOG;
672 }
673
set_result_type(AGENT_RESULT * result,int value_type,char * c)674 int set_result_type(AGENT_RESULT *result, int value_type, char *c)
675 {
676 zbx_uint64_t value_uint64;
677 int ret = FAIL;
678
679 assert(result);
680
681 switch (value_type)
682 {
683 double dbl_tmp;
684
685 case ITEM_VALUE_TYPE_UINT64:
686 zbx_trim_integer(c);
687 del_zeros(c);
688
689 if (SUCCEED == is_uint64(c, &value_uint64))
690 {
691 SET_UI64_RESULT(result, value_uint64);
692 ret = SUCCEED;
693 }
694 break;
695 case ITEM_VALUE_TYPE_FLOAT:
696 zbx_trim_float(c);
697
698 if (SUCCEED == is_double(c, &dbl_tmp))
699 {
700 SET_DBL_RESULT(result, dbl_tmp);
701 ret = SUCCEED;
702 }
703 break;
704 case ITEM_VALUE_TYPE_STR:
705 zbx_replace_invalid_utf8(c);
706 SET_STR_RESULT(result, zbx_strdup(NULL, c));
707 ret = SUCCEED;
708 break;
709 case ITEM_VALUE_TYPE_TEXT:
710 zbx_replace_invalid_utf8(c);
711 SET_TEXT_RESULT(result, zbx_strdup(NULL, c));
712 ret = SUCCEED;
713 break;
714 case ITEM_VALUE_TYPE_LOG:
715 zbx_replace_invalid_utf8(c);
716 add_log_result(result, c);
717 ret = SUCCEED;
718 break;
719 }
720
721 return ret;
722 }
723
set_result_meta(AGENT_RESULT * result,zbx_uint64_t lastlogsize,int mtime)724 void set_result_meta(AGENT_RESULT *result, zbx_uint64_t lastlogsize, int mtime)
725 {
726 result->lastlogsize = lastlogsize;
727 result->mtime = mtime;
728 result->type |= AR_META;
729 }
730
get_result_ui64_value(AGENT_RESULT * result)731 static zbx_uint64_t *get_result_ui64_value(AGENT_RESULT *result)
732 {
733 zbx_uint64_t value;
734
735 assert(result);
736
737 if (0 != ISSET_UI64(result))
738 {
739 /* nothing to do */
740 }
741 else if (0 != ISSET_DBL(result))
742 {
743 SET_UI64_RESULT(result, result->dbl);
744 }
745 else if (0 != ISSET_STR(result))
746 {
747 zbx_trim_integer(result->str);
748 del_zeros(result->str);
749
750 if (SUCCEED != is_uint64(result->str, &value))
751 return NULL;
752
753 SET_UI64_RESULT(result, value);
754 }
755 else if (0 != ISSET_TEXT(result))
756 {
757 zbx_trim_integer(result->text);
758 del_zeros(result->text);
759
760 if (SUCCEED != is_uint64(result->text, &value))
761 return NULL;
762
763 SET_UI64_RESULT(result, value);
764 }
765 /* skip AR_MESSAGE - it is information field */
766
767 if (0 != ISSET_UI64(result))
768 return &result->ui64;
769
770 return NULL;
771 }
772
get_result_dbl_value(AGENT_RESULT * result)773 static double *get_result_dbl_value(AGENT_RESULT *result)
774 {
775 double value;
776
777 assert(result);
778
779 if (0 != ISSET_DBL(result))
780 {
781 /* nothing to do */
782 }
783 else if (0 != ISSET_UI64(result))
784 {
785 SET_DBL_RESULT(result, result->ui64);
786 }
787 else if (0 != ISSET_STR(result))
788 {
789 zbx_trim_float(result->str);
790
791 if (SUCCEED != is_double(result->str, &value))
792 return NULL;
793
794 SET_DBL_RESULT(result, value);
795 }
796 else if (0 != ISSET_TEXT(result))
797 {
798 zbx_trim_float(result->text);
799
800 if (SUCCEED != is_double(result->text, &value))
801 return NULL;
802
803 SET_DBL_RESULT(result, value);
804 }
805 /* skip AR_MESSAGE - it is information field */
806
807 if (0 != ISSET_DBL(result))
808 return &result->dbl;
809
810 return NULL;
811 }
812
get_result_str_value(AGENT_RESULT * result)813 static char **get_result_str_value(AGENT_RESULT *result)
814 {
815 char *p, tmp;
816
817 assert(result);
818
819 if (0 != ISSET_STR(result))
820 {
821 /* nothing to do */
822 }
823 else if (0 != ISSET_TEXT(result))
824 {
825 /* NOTE: copy only line */
826 for (p = result->text; '\0' != *p && '\r' != *p && '\n' != *p; p++);
827 tmp = *p; /* remember result->text character */
828 *p = '\0'; /* replace to NUL */
829 SET_STR_RESULT(result, zbx_strdup(NULL, result->text)); /* copy line */
830 *p = tmp; /* restore result->text character */
831 }
832 else if (0 != ISSET_UI64(result))
833 {
834 SET_STR_RESULT(result, zbx_dsprintf(NULL, ZBX_FS_UI64, result->ui64));
835 }
836 else if (0 != ISSET_DBL(result))
837 {
838 SET_STR_RESULT(result, zbx_dsprintf(NULL, ZBX_FS_DBL, result->dbl));
839 }
840 /* skip AR_MESSAGE - it is information field */
841
842 if (0 != ISSET_STR(result))
843 return &result->str;
844
845 return NULL;
846 }
847
get_result_text_value(AGENT_RESULT * result)848 static char **get_result_text_value(AGENT_RESULT *result)
849 {
850 assert(result);
851
852 if (0 != ISSET_TEXT(result))
853 {
854 /* nothing to do */
855 }
856 else if (0 != ISSET_STR(result))
857 {
858 SET_TEXT_RESULT(result, zbx_strdup(NULL, result->str));
859 }
860 else if (0 != ISSET_UI64(result))
861 {
862 SET_TEXT_RESULT(result, zbx_dsprintf(NULL, ZBX_FS_UI64, result->ui64));
863 }
864 else if (0 != ISSET_DBL(result))
865 {
866 SET_TEXT_RESULT(result, zbx_dsprintf(NULL, ZBX_FS_DBL, result->dbl));
867 }
868 /* skip AR_MESSAGE - it is information field */
869
870 if (0 != ISSET_TEXT(result))
871 return &result->text;
872
873 return NULL;
874 }
875
get_result_log_value(AGENT_RESULT * result)876 static zbx_log_t *get_result_log_value(AGENT_RESULT *result)
877 {
878 if (0 != ISSET_LOG(result))
879 return result->log;
880
881 if (0 != ISSET_VALUE(result))
882 {
883 result->log = (zbx_log_t *)zbx_malloc(result->log, sizeof(zbx_log_t));
884
885 zbx_log_init(result->log);
886
887 if (0 != ISSET_STR(result))
888 result->log->value = zbx_strdup(result->log->value, result->str);
889 else if (0 != ISSET_TEXT(result))
890 result->log->value = zbx_strdup(result->log->value, result->text);
891 else if (0 != ISSET_UI64(result))
892 result->log->value = zbx_dsprintf(result->log->value, ZBX_FS_UI64, result->ui64);
893 else if (0 != ISSET_DBL(result))
894 result->log->value = zbx_dsprintf(result->log->value, ZBX_FS_DBL, result->dbl);
895
896 result->type |= AR_LOG;
897
898 return result->log;
899 }
900
901 return NULL;
902 }
903
904 /******************************************************************************
905 * *
906 * Function: get_result_value_by_type *
907 * *
908 * Purpose: return value of result in special type *
909 * if value missing, convert existing value to requested type *
910 * *
911 * Return value: *
912 * NULL - if value is missing or can't be converted *
913 * *
914 * Author: Eugene Grigorjev *
915 * *
916 * Comments: better use definitions *
917 * GET_UI64_RESULT *
918 * GET_DBL_RESULT *
919 * GET_STR_RESULT *
920 * GET_TEXT_RESULT *
921 * GET_LOG_RESULT *
922 * GET_MSG_RESULT *
923 * *
924 * AR_MESSAGE - skipped in conversion *
925 * *
926 ******************************************************************************/
get_result_value_by_type(AGENT_RESULT * result,int require_type)927 void *get_result_value_by_type(AGENT_RESULT *result, int require_type)
928 {
929 assert(result);
930
931 switch (require_type)
932 {
933 case AR_UINT64:
934 return (void *)get_result_ui64_value(result);
935 case AR_DOUBLE:
936 return (void *)get_result_dbl_value(result);
937 case AR_STRING:
938 return (void *)get_result_str_value(result);
939 case AR_TEXT:
940 return (void *)get_result_text_value(result);
941 case AR_LOG:
942 return (void *)get_result_log_value(result);
943 case AR_MESSAGE:
944 if (0 != ISSET_MSG(result))
945 return (void *)(&result->msg);
946 break;
947 default:
948 break;
949 }
950
951 return NULL;
952 }
953
954 /******************************************************************************
955 * *
956 * Function: unquote_key_param *
957 * *
958 * Purpose: unquotes special symbols in item key parameter *
959 * *
960 * Parameters: param - [IN/OUT] item key parameter *
961 * *
962 * Comments: *
963 * "param" => param *
964 * "\"param\"" => "param" *
965 * *
966 ******************************************************************************/
unquote_key_param(char * param)967 void unquote_key_param(char *param)
968 {
969 char *dst;
970
971 if ('"' != *param)
972 return;
973
974 for (dst = param++; '\0' != *param; param++)
975 {
976 if ('\\' == *param && '"' == param[1])
977 continue;
978
979 *dst++ = *param;
980 }
981 *--dst = '\0';
982 }
983
984 /******************************************************************************
985 * *
986 * Function: quote_key_param *
987 * *
988 * Purpose: quotes special symbols in item key parameter *
989 * *
990 * Parameters: param - [IN/OUT] item key parameter *
991 * forced - [IN] 1 - enclose parameter in " even if it does not *
992 * contain any special characters *
993 * 0 - do nothing if the parameter does not *
994 * contain any special characters *
995 * *
996 * Return value: SUCCEED - if parameter was successfully quoted or quoting *
997 * was not necessary *
998 * FAIL - if parameter needs to but cannot be quoted due to *
999 * backslash in the end *
1000 * *
1001 ******************************************************************************/
quote_key_param(char ** param,int forced)1002 int quote_key_param(char **param, int forced)
1003 {
1004 size_t sz_src, sz_dst;
1005
1006 if (0 == forced)
1007 {
1008 if ('"' != **param && ' ' != **param && '[' != **param && NULL == strchr(*param, ',') &&
1009 NULL == strchr(*param, ']'))
1010 {
1011 return SUCCEED;
1012 }
1013 }
1014
1015 if (0 != (sz_src = strlen(*param)) && '\\' == (*param)[sz_src - 1])
1016 return FAIL;
1017
1018 sz_dst = zbx_get_escape_string_len(*param, "\"") + 3;
1019
1020 *param = (char *)zbx_realloc(*param, sz_dst);
1021
1022 (*param)[--sz_dst] = '\0';
1023 (*param)[--sz_dst] = '"';
1024
1025 while (0 < sz_src)
1026 {
1027 (*param)[--sz_dst] = (*param)[--sz_src];
1028 if ('"' == (*param)[sz_src])
1029 (*param)[--sz_dst] = '\\';
1030 }
1031 (*param)[--sz_dst] = '"';
1032
1033 return SUCCEED;
1034 }
1035
1036 #ifdef HAVE_KSTAT_H
get_kstat_numeric_value(const kstat_named_t * kn)1037 zbx_uint64_t get_kstat_numeric_value(const kstat_named_t *kn)
1038 {
1039 switch (kn->data_type)
1040 {
1041 case KSTAT_DATA_INT32:
1042 return kn->value.i32;
1043 case KSTAT_DATA_UINT32:
1044 return kn->value.ui32;
1045 case KSTAT_DATA_INT64:
1046 return kn->value.i64;
1047 case KSTAT_DATA_UINT64:
1048 return kn->value.ui64;
1049 default:
1050 THIS_SHOULD_NEVER_HAPPEN;
1051 return 0;
1052 }
1053 }
1054 #endif
1055
1056 #ifndef _WINDOWS
1057 /******************************************************************************
1058 * *
1059 * Function: serialize_agent_result *
1060 * *
1061 * Purpose: serialize agent result to transfer over pipe/socket *
1062 * *
1063 * Parameters: data - [IN/OUT] the data buffer *
1064 * data_alloc - [IN/OUT] the data buffer allocated size *
1065 * data_offset - [IN/OUT] the data buffer data size *
1066 * agent_ret - [IN] the agent result return code *
1067 * result - [IN] the agent result *
1068 * *
1069 * Comments: The agent result is serialized as [rc][type][data] where: *
1070 * [rc] the agent result return code, 4 bytes *
1071 * [type] the agent result data type, 1 byte *
1072 * [data] the agent result data, null terminated string (optional)*
1073 * *
1074 ******************************************************************************/
serialize_agent_result(char ** data,size_t * data_alloc,size_t * data_offset,int agent_ret,AGENT_RESULT * result)1075 static void serialize_agent_result(char **data, size_t *data_alloc, size_t *data_offset, int agent_ret,
1076 AGENT_RESULT *result)
1077 {
1078 char **pvalue, result_type;
1079 size_t value_len;
1080
1081 if (SYSINFO_RET_OK == agent_ret)
1082 {
1083 if (ISSET_TEXT(result))
1084 result_type = 't';
1085 else if (ISSET_STR(result))
1086 result_type = 's';
1087 else if (ISSET_UI64(result))
1088 result_type = 'u';
1089 else if (ISSET_DBL(result))
1090 result_type = 'd';
1091 else if (ISSET_MSG(result))
1092 result_type = 'm';
1093 else
1094 result_type = '-';
1095 }
1096 else
1097 result_type = 'm';
1098
1099 switch (result_type)
1100 {
1101 case 't':
1102 case 's':
1103 case 'u':
1104 case 'd':
1105 pvalue = GET_TEXT_RESULT(result);
1106 break;
1107 case 'm':
1108 pvalue = GET_MSG_RESULT(result);
1109 break;
1110 default:
1111 pvalue = NULL;
1112 }
1113
1114 if (NULL != pvalue)
1115 {
1116 value_len = strlen(*pvalue) + 1;
1117 }
1118 else
1119 {
1120 value_len = 0;
1121 result_type = '-';
1122 }
1123
1124 if (*data_alloc - *data_offset < value_len + 1 + sizeof(int))
1125 {
1126 while (*data_alloc - *data_offset < value_len + 1 + sizeof(int))
1127 *data_alloc *= 1.5;
1128
1129 *data = (char *)zbx_realloc(*data, *data_alloc);
1130 }
1131
1132 memcpy(*data + *data_offset, &agent_ret, sizeof(int));
1133 *data_offset += sizeof(int);
1134
1135 (*data)[(*data_offset)++] = result_type;
1136
1137 if ('-' != result_type)
1138 {
1139 memcpy(*data + *data_offset, *pvalue, value_len);
1140 *data_offset += value_len;
1141 }
1142 }
1143
1144 /******************************************************************************
1145 * *
1146 * Function: deserialize_agent_result *
1147 * *
1148 * Purpose: deserialize agent result *
1149 * *
1150 * Parameters: data - [IN] the data to deserialize *
1151 * result - [OUT] the agent result *
1152 * *
1153 * Return value: the agent result return code (SYSINFO_RET_*) *
1154 * *
1155 ******************************************************************************/
deserialize_agent_result(char * data,AGENT_RESULT * result)1156 static int deserialize_agent_result(char *data, AGENT_RESULT *result)
1157 {
1158 int ret, agent_ret;
1159 char type;
1160
1161 memcpy(&agent_ret, data, sizeof(int));
1162 data += sizeof(int);
1163
1164 type = *data++;
1165
1166 if ('m' == type || 0 == strcmp(data, ZBX_NOTSUPPORTED))
1167 {
1168 SET_MSG_RESULT(result, zbx_strdup(NULL, data));
1169 return agent_ret;
1170 }
1171
1172 switch (type)
1173 {
1174 case 't':
1175 ret = set_result_type(result, ITEM_VALUE_TYPE_TEXT, data);
1176 break;
1177 case 's':
1178 ret = set_result_type(result, ITEM_VALUE_TYPE_STR, data);
1179 break;
1180 case 'u':
1181 ret = set_result_type(result, ITEM_VALUE_TYPE_UINT64, data);
1182 break;
1183 case 'd':
1184 ret = set_result_type(result, ITEM_VALUE_TYPE_FLOAT, data);
1185 break;
1186 default:
1187 ret = SUCCEED;
1188 }
1189
1190 /* return deserialized return code or SYSINFO_RET_FAIL if setting result data failed */
1191 return (FAIL == ret ? SYSINFO_RET_FAIL : agent_ret);
1192 }
1193
1194 /******************************************************************************
1195 * *
1196 * Function: write_all *
1197 * *
1198 * Purpose: call write in a loop, iterating until all the data is written. *
1199 * *
1200 * Parameters: fd - [IN] descriptor *
1201 * buf - [IN] buffer to write *
1202 * n - [IN] bytes count to write *
1203 * *
1204 * Return value: SUCCEED - n bytes successfully written *
1205 * FAIL - less than n bytes are written *
1206 * *
1207 ******************************************************************************/
write_all(int fd,const char * buf,size_t n)1208 static int write_all(int fd, const char *buf, size_t n)
1209 {
1210 ssize_t ret;
1211
1212 while (0 < n)
1213 {
1214 if (-1 != (ret = write(fd, buf, n)))
1215 {
1216 buf += ret;
1217 n -= ret;
1218 }
1219 else if (EINTR != errno)
1220 return FAIL;
1221 }
1222
1223 return SUCCEED;
1224 }
1225
1226 /******************************************************************************
1227 * *
1228 * Function: zbx_execute_threaded_metric *
1229 * *
1230 * Purpose: execute metric in a separate process/thread so it can be *
1231 * killed/terminated when timeout is detected *
1232 * *
1233 * Parameters: metric_func - [IN] the metric function to execute *
1234 * ... the metric function parameters *
1235 * *
1236 * Return value: *
1237 * SYSINFO_RET_OK - the metric was executed successfully *
1238 * SYSINFO_RET_FAIL - otherwise *
1239 * *
1240 ******************************************************************************/
zbx_execute_threaded_metric(zbx_metric_func_t metric_func,AGENT_REQUEST * request,AGENT_RESULT * result)1241 int zbx_execute_threaded_metric(zbx_metric_func_t metric_func, AGENT_REQUEST *request, AGENT_RESULT *result)
1242 {
1243 const char *__function_name = "zbx_execute_threaded_metric";
1244
1245 int ret = SYSINFO_RET_OK;
1246 pid_t pid;
1247 int fds[2], n, status;
1248 char buffer[MAX_STRING_LEN], *data;
1249 size_t data_alloc = MAX_STRING_LEN, data_offset = 0;
1250
1251 zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:'%s'", __function_name, request->key);
1252
1253 if (-1 == pipe(fds))
1254 {
1255 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot create data pipe: %s", strerror_from_system(errno)));
1256 ret = SYSINFO_RET_FAIL;
1257 goto out;
1258 }
1259
1260 if (-1 == (pid = zbx_fork()))
1261 {
1262 close(fds[0]);
1263 close(fds[1]);
1264 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot fork data process: %s", strerror_from_system(errno)));
1265 ret = SYSINFO_RET_FAIL;
1266 goto out;
1267 }
1268
1269 data = (char *)zbx_malloc(NULL, data_alloc);
1270
1271 if (0 == pid)
1272 {
1273 zabbix_log(LOG_LEVEL_DEBUG, "executing in data process for key:'%s'", request->key);
1274
1275 zbx_set_metric_thread_signal_handler();
1276
1277 close(fds[0]);
1278
1279 ret = metric_func(request, result);
1280 serialize_agent_result(&data, &data_alloc, &data_offset, ret, result);
1281
1282 ret = write_all(fds[1], data, data_offset);
1283
1284 zbx_free(data);
1285 free_result(result);
1286
1287 close(fds[1]);
1288
1289 exit(SUCCEED == ret ? EXIT_SUCCESS : EXIT_FAILURE);
1290 }
1291
1292 close(fds[1]);
1293
1294 zbx_alarm_on(CONFIG_TIMEOUT);
1295
1296 while (0 != (n = read(fds[0], buffer, sizeof(buffer))))
1297 {
1298 if (SUCCEED == zbx_alarm_timed_out())
1299 {
1300 SET_MSG_RESULT(result, zbx_strdup(NULL, "Timeout while waiting for data."));
1301 kill(pid, SIGKILL);
1302 ret = SYSINFO_RET_FAIL;
1303 break;
1304 }
1305
1306 if (-1 == n)
1307 {
1308 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Error while reading data: %s", zbx_strerror(errno)));
1309 kill(pid, SIGKILL);
1310 ret = SYSINFO_RET_FAIL;
1311 break;
1312 }
1313
1314 if ((int)(data_alloc - data_offset) < n + 1)
1315 {
1316 while ((int)(data_alloc - data_offset) < n + 1)
1317 data_alloc *= 1.5;
1318
1319 data = (char *)zbx_realloc(data, data_alloc);
1320 }
1321
1322 memcpy(data + data_offset, buffer, n);
1323 data_offset += n;
1324 data[data_offset] = '\0';
1325 }
1326
1327 zbx_alarm_off();
1328
1329 close(fds[0]);
1330
1331 while (-1 == waitpid(pid, &status, 0))
1332 {
1333 if (EINTR != errno)
1334 {
1335 zabbix_log(LOG_LEVEL_ERR, "failed to wait on child processes: %s", zbx_strerror(errno));
1336 ret = SYSINFO_RET_FAIL;
1337 break;
1338 }
1339 }
1340
1341 if (SYSINFO_RET_OK == ret)
1342 {
1343 if (0 == WIFEXITED(status))
1344 {
1345 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Data gathering process terminated unexpectedly with"
1346 " error %d.", status));
1347 kill(pid, SIGKILL);
1348 ret = SYSINFO_RET_FAIL;
1349 }
1350 else if (EXIT_SUCCESS != WEXITSTATUS(status))
1351 {
1352 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Data gathering process terminated with error %d.",
1353 status));
1354 ret = SYSINFO_RET_FAIL;
1355 }
1356 else
1357 ret = deserialize_agent_result(data, result);
1358 }
1359
1360 zbx_free(data);
1361 out:
1362 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s '%s'", __function_name, zbx_sysinfo_ret_string(ret),
1363 ISSET_MSG(result) ? result->msg : "");
1364 return ret;
1365 }
1366 #else
1367
1368 ZBX_THREAD_LOCAL static zbx_uint32_t mutex_flag = ZBX_MUTEX_ALL_ALLOW;
1369
get_thread_global_mutex_flag()1370 zbx_uint32_t get_thread_global_mutex_flag()
1371 {
1372 return mutex_flag;
1373 }
1374
1375 typedef struct
1376 {
1377 zbx_metric_func_t func;
1378 AGENT_REQUEST *request;
1379 AGENT_RESULT *result;
1380 zbx_uint32_t mutex_flag; /* in regular case should always be = ZBX_MUTEX_ALL_ALLOW */
1381 HANDLE timeout_event;
1382 int agent_ret;
1383 }
1384 zbx_metric_thread_args_t;
1385
ZBX_THREAD_ENTRY(agent_metric_thread,data)1386 ZBX_THREAD_ENTRY(agent_metric_thread, data)
1387 {
1388 zbx_metric_thread_args_t *args = (zbx_metric_thread_args_t *)((zbx_thread_args_t *)data)->args;
1389 mutex_flag = args->mutex_flag;
1390
1391 zabbix_log(LOG_LEVEL_DEBUG, "executing in data thread for key:'%s'", args->request->key);
1392
1393 if (SYSINFO_RET_FAIL == (args->agent_ret = args->func(args->request, args->result, args->timeout_event)))
1394 {
1395 if (NULL == GET_MSG_RESULT(args->result))
1396 SET_MSG_RESULT(args->result, zbx_strdup(NULL, ZBX_NOTSUPPORTED));
1397 }
1398
1399 zbx_thread_exit(0);
1400 }
1401
1402 /******************************************************************************
1403 * *
1404 * Function: zbx_execute_threaded_metric *
1405 * *
1406 * Purpose: execute metric in a separate process/thread so it can be *
1407 * killed/terminated when timeout is detected *
1408 * *
1409 * Parameters: metric_func - [IN] the metric function to execute *
1410 * ... the metric function parameters *
1411 * *
1412 * Return value: *
1413 * SYSINFO_RET_OK - the metric was executed successfully *
1414 * SYSINFO_RET_FAIL - otherwise *
1415 * *
1416 ******************************************************************************/
zbx_execute_threaded_metric(zbx_metric_func_t metric_func,AGENT_REQUEST * request,AGENT_RESULT * result)1417 int zbx_execute_threaded_metric(zbx_metric_func_t metric_func, AGENT_REQUEST *request, AGENT_RESULT *result)
1418 {
1419 const char *__function_name = "zbx_execute_threaded_metric";
1420
1421 ZBX_THREAD_HANDLE thread;
1422 zbx_thread_args_t thread_args;
1423 zbx_metric_thread_args_t metric_args = {metric_func, request, result, ZBX_MUTEX_THREAD_DENIED |
1424 ZBX_MUTEX_LOGGING_DENIED};
1425 DWORD rc;
1426 BOOL terminate_thread = FALSE;
1427
1428 zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:'%s'", __function_name, request->key);
1429
1430 if (NULL == (metric_args.timeout_event = CreateEvent(NULL, TRUE, FALSE, NULL)))
1431 {
1432 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot create timeout event for data thread: %s",
1433 strerror_from_system(GetLastError())));
1434 return SYSINFO_RET_FAIL;
1435 }
1436
1437 thread_args.args = (void *)&metric_args;
1438
1439 zbx_thread_start(agent_metric_thread, &thread_args, &thread);
1440
1441 if (ZBX_THREAD_ERROR == thread)
1442 {
1443 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot start data thread: %s",
1444 strerror_from_system(GetLastError())));
1445 CloseHandle(metric_args.timeout_event);
1446 return SYSINFO_RET_FAIL;
1447 }
1448
1449 /* 1000 is multiplier for converting seconds into milliseconds */
1450 if (WAIT_FAILED == (rc = WaitForSingleObject(thread, CONFIG_TIMEOUT * 1000)))
1451 {
1452 /* unexpected error */
1453
1454 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot wait for data: %s",
1455 strerror_from_system(GetLastError())));
1456 terminate_thread = TRUE;
1457 }
1458 else if (WAIT_TIMEOUT == rc)
1459 {
1460 SET_MSG_RESULT(result, zbx_strdup(NULL, "Timeout while waiting for data."));
1461
1462 /* timeout; notify thread to clean up and exit, if stuck then terminate it */
1463
1464 if (FALSE == SetEvent(metric_args.timeout_event))
1465 {
1466 zabbix_log(LOG_LEVEL_ERR, "SetEvent() failed: %s", strerror_from_system(GetLastError()));
1467 terminate_thread = TRUE;
1468 }
1469 else
1470 {
1471 DWORD timeout_rc = WaitForSingleObject(thread, 3000); /* wait up to 3 seconds */
1472
1473 if (WAIT_FAILED == timeout_rc)
1474 {
1475 zabbix_log(LOG_LEVEL_ERR, "Waiting for data failed: %s",
1476 strerror_from_system(GetLastError()));
1477 terminate_thread = TRUE;
1478 }
1479 else if (WAIT_TIMEOUT == timeout_rc)
1480 {
1481 zabbix_log(LOG_LEVEL_ERR, "Stuck data thread");
1482 terminate_thread = TRUE;
1483 }
1484 /* timeout_rc must be WAIT_OBJECT_0 (signaled) */
1485 }
1486 }
1487
1488 if (TRUE == terminate_thread)
1489 {
1490 if (FALSE != TerminateThread(thread, 0))
1491 {
1492 zabbix_log(LOG_LEVEL_ERR, "%s(): TerminateThread() for %s[%s%s] succeeded", __function_name,
1493 request->key, (0 < request->nparam) ? request->params[0] : "",
1494 (1 < request->nparam) ? ",..." : "");
1495 }
1496 else
1497 {
1498 zabbix_log(LOG_LEVEL_ERR, "%s(): TerminateThread() for %s[%s%s] failed: %s", __function_name,
1499 request->key, (0 < request->nparam) ? request->params[0] : "",
1500 (1 < request->nparam) ? ",..." : "",
1501 strerror_from_system(GetLastError()));
1502 }
1503 }
1504
1505 CloseHandle(thread);
1506 CloseHandle(metric_args.timeout_event);
1507
1508 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s '%s'", __function_name,
1509 zbx_sysinfo_ret_string(metric_args.agent_ret), ISSET_MSG(result) ? result->msg : "");
1510
1511 return WAIT_OBJECT_0 == rc ? metric_args.agent_ret : SYSINFO_RET_FAIL;
1512 }
1513 #endif
1514
1515 /******************************************************************************
1516 * *
1517 * Function: zbx_mpoints_free *
1518 * *
1519 * Purpose: frees previously allocated mount-point structure *
1520 * *
1521 * Parameters: mpoint - [IN] pointer to structure from vector *
1522 * *
1523 * Return value: *
1524 * *
1525 ******************************************************************************/
zbx_mpoints_free(zbx_mpoint_t * mpoint)1526 void zbx_mpoints_free(zbx_mpoint_t *mpoint)
1527 {
1528 zbx_free(mpoint);
1529 }
1530