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